Chromium Code Reviews| Index: ios/chrome/widget_extension/widget_view_controller.mm |
| diff --git a/ios/chrome/widget_extension/widget_view_controller.mm b/ios/chrome/widget_extension/widget_view_controller.mm |
| index aa93999c29e3794b9b67622d5bb61d4e77d2f5ef..8c344d2d5c27cfe0b7aba3f7e85ab6af45fe98d8 100644 |
| --- a/ios/chrome/widget_extension/widget_view_controller.mm |
| +++ b/ios/chrome/widget_extension/widget_view_controller.mm |
| @@ -6,25 +6,60 @@ |
| #import <NotificationCenter/NotificationCenter.h> |
| +#include "base/ios/ios_util.h" |
| #include "base/mac/foundation_util.h" |
| #include "base/strings/sys_string_conversions.h" |
| +#include "components/open_from_clipboard/clipboard_recent_content_impl_ios.h" |
| #include "ios/chrome/common/app_group/app_group_constants.h" |
| -#include "ios/chrome/common/x_callback_url.h" |
| #import "ios/chrome/widget_extension/widget_view.h" |
| -#import "net/base/mac/url_conversions.h" |
| -#include "url/gurl.h" |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| +namespace { |
| +// Using GURL in the extension is not wanted as it includes ICU which makes the |
| +// extension binary much larger; therefore, ios/chrome/common/x_callback_url.h |
| +// cannot be used. As this class makes a very basic use of xcallback no full |
|
lpromero
2017/04/11 13:24:04
s/xcallback/x-callback-url, and add a comma.
lody
2017/04/11 14:38:19
Done.
|
| +// implementation in is required. |
|
lpromero
2017/04/11 13:24:03
Should you remove "in"?
lody
2017/04/11 14:38:18
Done.
|
| +NSString* const kXCallbackURLHost = @"x-callback-url"; |
| +} // namespace |
| + |
| @interface WidgetViewController ()<WidgetViewActionTarget> |
| @property(nonatomic, weak) WidgetView* widgetView; |
| +@property(nonatomic, strong) NSURL* copiedURL; |
| +@property(nonatomic, strong) |
| + ClipboardRecentContentImplIOS* clipboardRecentContent; |
| + |
| +// Updates the widget with latest data from the clipboard. Returns whether any |
| +// visual updates occured. |
| +- (BOOL)updateWidget; |
| +// Opens the main application with the given |command|. |
| +- (void)openAppWithCommand:(NSString*)command; |
| +// Opens the main application with the given |command| and |parameter|. |
| +- (void)openAppWithCommand:(NSString*)command Parameter:(NSString*)parameter; |
|
lpromero
2017/04/11 13:24:03
s/Parameter/parameter
lody
2017/04/11 14:38:18
Done.
|
| +// Returns the dictionary of commands to pass via user defaults to open the main |
| +// application for a given |command| and |parameter|. |
| ++ (NSDictionary*)commandDict:(NSString*)command Parameter:(NSString*)parameter; |
|
lpromero
2017/04/11 13:24:03
Rename commandDictForCommand:parameter:, or dictFo
lody
2017/04/11 14:38:18
Done.
|
| + |
| @end |
| @implementation WidgetViewController |
| @synthesize widgetView = _widgetView; |
| +@synthesize copiedURL = _copiedURL; |
| +@synthesize clipboardRecentContent = _clipboardRecentContent; |
| + |
| +- (instancetype)init { |
| + self = [super init]; |
| + if (self) { |
| + _clipboardRecentContent = [[ClipboardRecentContentImplIOS alloc] |
| + initWithAuthorizedSchemes:[NSSet setWithObjects:@"http", @"https", nil] |
| + userDefaults:app_group::GetGroupUserDefaults() |
| + delegate:nil]; |
| + } |
| + return self; |
| +} |
| #pragma mark - UIViewController |
| @@ -36,49 +71,146 @@ |
| WidgetView* widgetView = [[WidgetView alloc] initWithActionTarget:self]; |
| self.widgetView = widgetView; |
| [self.view addSubview:self.widgetView]; |
| + [self updateWidget]; |
| + |
| + if (base::ios::IsRunningOnIOS10OrLater()) { |
| + self.extensionContext.widgetLargestAvailableDisplayMode = |
| + NCWidgetDisplayModeExpanded; |
| + } |
| + |
| + self.widgetView.translatesAutoresizingMaskIntoConstraints = NO; |
| + |
| + NSLayoutConstraint* heightAnchor = [self.widgetView.heightAnchor |
| + constraintEqualToAnchor:self.view.heightAnchor]; |
| + heightAnchor.priority = 900; |
| - [self.widgetView setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| [NSLayoutConstraint activateConstraints:@[ |
| [self.widgetView.leadingAnchor |
| - constraintEqualToAnchor:[self.view leadingAnchor]], |
| + constraintEqualToAnchor:self.view.leadingAnchor], |
| + [self.widgetView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor], |
| [self.widgetView.trailingAnchor |
| - constraintEqualToAnchor:[self.view trailingAnchor]], |
| - [self.widgetView.heightAnchor |
| - constraintEqualToAnchor:[self.view heightAnchor]], |
| - [self.widgetView.widthAnchor |
| - constraintEqualToAnchor:[self.view widthAnchor]] |
| + constraintEqualToAnchor:self.view.trailingAnchor], |
| + heightAnchor, |
| + [self.widgetView.topAnchor constraintEqualToAnchor:self.view.topAnchor], |
| ]]; |
| } |
| -- (void)openApp:(id)sender { |
| +- (void)viewDidAppear:(BOOL)animated { |
|
lpromero
2017/04/11 13:24:03
You should call [super viewDidAppear:animated]. I
lpromero
2017/04/11 13:24:03
Why in viewDidLoad and viewDidAppear and not just
lody
2017/04/11 14:38:18
Done.
lody
2017/04/11 14:38:18
ViewDidLoad is not called as often as viewWillAppe
|
| + [self updateWidget]; |
| +} |
| + |
| +- (void)widgetPerformUpdateWithCompletionHandler: |
| + (void (^)(NCUpdateResult))completionHandler { |
| + completionHandler([self updateWidget] ? NCUpdateResultNewData |
| + : NCUpdateResultNoData); |
| +} |
| + |
| +- (BOOL)updateWidget { |
| + NSURL* url = [_clipboardRecentContent recentURLFromClipboard]; |
| + |
| + if (![url isEqual:self.copiedURL]) { |
| + self.copiedURL = url; |
| + [self.widgetView |
| + updateCopiedURL:self.copiedURL ? self.copiedURL.absoluteString : nil]; |
|
lpromero
2017/04/11 13:24:03
You can simplify in [self.widgetView updateCopiedU
lody
2017/04/11 14:38:18
Done.
|
| + |
| + return YES; |
| + } |
| + return NO; |
| +} |
| + |
| +#pragma mark NCWidgetProviding |
|
lpromero
2017/04/11 13:24:03
Nit: #pragma mark - NCWidgetProviding
lody
2017/04/11 14:38:18
Done.
|
| + |
| +- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode |
| + withMaximumSize:(CGSize)maxSize { |
| + CGSize fittingSize = [self.widgetView |
| + systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; |
| + if (fittingSize.height > maxSize.height) { |
| + self.preferredContentSize = maxSize; |
| + } else { |
| + self.preferredContentSize = fittingSize; |
| + } |
| +} |
| + |
| +#pragma mark WidgetViewActionTarget |
|
lpromero
2017/04/11 13:24:03
Ditto
lody
2017/04/11 14:38:19
Done.
|
| + |
| +- (void)openSearch:(id)sender { |
| + [self openAppWithCommand:base::SysUTF8ToNSString( |
| + app_group::kChromeAppGroupFocusOmniboxCommand)]; |
| +} |
| + |
| +- (void)openIncognito:(id)sender { |
| + [self |
| + openAppWithCommand:base::SysUTF8ToNSString( |
| + app_group::kChromeAppGroupIncognitoSearchCommand)]; |
| +} |
| + |
| +- (void)openVoice:(id)sender { |
| + [self openAppWithCommand:base::SysUTF8ToNSString( |
| + app_group::kChromeAppGroupVoiceSearchCommand)]; |
| +} |
| + |
| +- (void)openQRCode:(id)sender { |
| + [self openAppWithCommand:base::SysUTF8ToNSString( |
| + app_group::kChromeAppGroupQRScannerCommand)]; |
| +} |
| + |
| +- (void)openCopiedLink:(id)sender { |
| + DCHECK(self.copiedURL); |
| + [self openAppWithCommand:base::SysUTF8ToNSString( |
| + app_group::kChromeAppGroupOpenURLCommand) |
| + Parameter:self.copiedURL.absoluteString]; |
| +} |
| + |
| +#pragma mark internal |
|
lpromero
2017/04/11 13:24:04
Ditto
lody
2017/04/11 14:38:19
Done.
|
| + |
| +- (void)openAppWithCommand:(NSString*)command { |
| + return [self openAppWithCommand:command Parameter:nil]; |
| +} |
| + |
| +- (void)openAppWithCommand:(NSString*)command Parameter:(NSString*)parameter { |
| NSUserDefaults* sharedDefaults = |
| [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()]; |
| NSString* defaultsKey = |
| base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference); |
| - [sharedDefaults setObject:[WidgetViewController commandDict] |
| - forKey:defaultsKey]; |
| + [sharedDefaults |
| + setObject:[WidgetViewController commandDict:command Parameter:parameter] |
| + forKey:defaultsKey]; |
| [sharedDefaults synchronize]; |
| NSString* scheme = base::mac::ObjCCast<NSString>([[NSBundle mainBundle] |
| objectForInfoDictionaryKey:@"KSChannelChromeScheme"]); |
| if (!scheme) |
| return; |
| - const GURL openURL = |
| - CreateXCallbackURL(base::SysNSStringToUTF8(scheme), |
| - app_group::kChromeAppGroupXCallbackCommand); |
| - [self.extensionContext openURL:net::NSURLWithGURL(openURL) |
| - completionHandler:nil]; |
| + |
| + NSURLComponents* urlComponents = [NSURLComponents new]; |
| + urlComponents.scheme = scheme; |
| + urlComponents.host = kXCallbackURLHost; |
| + urlComponents.path = [NSString |
| + stringWithFormat:@"/%@", base::SysUTF8ToNSString( |
|
lpromero
2017/04/11 13:24:03
Do you really need the "/" given that you are sett
lody
2017/04/11 14:38:18
unfortunately, nope (unless I missed an option)
|
| + app_group::kChromeAppGroupXCallbackCommand)]; |
| + |
| + NSURL* openURL = [urlComponents URL]; |
| + [self.extensionContext openURL:openURL completionHandler:nil]; |
| } |
| -+ (NSDictionary*)commandDict { |
| - NSString* command = |
| - base::SysUTF8ToNSString(app_group::kChromeAppGroupFocusOmniboxCommand); |
| ++ (NSDictionary*)commandDict:(NSString*)command Parameter:(NSString*)parameter { |
|
lpromero
2017/04/11 13:24:04
s/Parameter/parameter
lody
2017/04/11 14:38:18
Done.
|
| NSString* timePrefKey = |
| base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandTimePreference); |
| NSString* appPrefKey = |
| base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandAppPreference); |
| NSString* commandPrefKey = base::SysUTF8ToNSString( |
| app_group::kChromeAppGroupCommandCommandPreference); |
| + |
| + if (parameter) { |
| + NSString* paramPrefKey = base::SysUTF8ToNSString( |
| + app_group::kChromeAppGroupCommandParameterPreference); |
| + return @{ |
| + timePrefKey : [NSDate date], |
| + appPrefKey : @"TodayExtension", |
| + commandPrefKey : command, |
| + paramPrefKey : parameter, |
| + }; |
| + } |
| return @{ |
| timePrefKey : [NSDate date], |
| appPrefKey : @"TodayExtension", |