Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(553)

Side by Side Diff: ios/chrome/share_extension/share_view_controller.mm

Issue 2608913002: Handle invalid URLs in share extension. (Closed)
Patch Set: feedback Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import <MobileCoreServices/MobileCoreServices.h> 5 #import <MobileCoreServices/MobileCoreServices.h>
6 6
7 #import "ios/chrome/share_extension/share_view_controller.h" 7 #import "ios/chrome/share_extension/share_view_controller.h"
8 8
9 #import "base/ios/block_types.h" 9 #import "base/ios/block_types.h"
10 #import "base/mac/foundation_util.h" 10 #import "base/mac/foundation_util.h"
(...skipping 16 matching lines...) Expand all
27 const CGFloat kShareExtensionMaxWidth = 390; 27 const CGFloat kShareExtensionMaxWidth = 390;
28 // Clip the last separator out of the table view. 28 // Clip the last separator out of the table view.
29 const CGFloat kScreenShotWidth = 100; 29 const CGFloat kScreenShotWidth = 100;
30 const CGFloat kScreenShotHeight = 100; 30 const CGFloat kScreenShotHeight = 100;
31 const CGFloat kAnimationDuration = 0.3; 31 const CGFloat kAnimationDuration = 0.3;
32 const CGFloat kMediumAlpha = 0.5; 32 const CGFloat kMediumAlpha = 0.5;
33 33
34 } // namespace 34 } // namespace
35 35
36 @interface ShareViewController ()<ShareExtensionViewActionTarget> { 36 @interface ShareViewController ()<ShareExtensionViewActionTarget> {
37 // This constraint the center of the widget to be vertically in the center 37 // This constrains the center of the widget to be vertically in the center
gambard 2017/01/02 10:55:08 Why adding a "s" to constraint?
Olivier 2017/01/02 12:23:31 Because constraint is a noun and constrain is a ve
38 // of the the screen. It has to be modified for the dismissal animation. 38 // of the the screen. It has to be modified for the appearance and dismissal
39 NSLayoutConstraint* _centerYConstraint; 39 // animation.
40 NSLayoutConstraint* _widgetVerticalPlacementConstraint;
40 41
41 NSURL* _shareURL; 42 NSURL* _shareURL;
42 NSString* _shareTitle; 43 NSString* _shareTitle;
44 UIImage* _image;
43 NSExtensionItem* _shareItem; 45 NSExtensionItem* _shareItem;
44 } 46 }
45 47
46 @property(nonatomic, weak) UIView* maskView; 48 @property(nonatomic, weak) UIView* maskView;
47 @property(nonatomic, weak) ShareExtensionView* shareView; 49 @property(nonatomic, weak) ShareExtensionView* shareView;
48 @property(nonatomic, assign) app_group::ShareExtensionItemType itemType; 50 @property(nonatomic, assign) app_group::ShareExtensionItemType itemType;
49 51
50 // Creates a files in |app_group::ShareExtensionItemsFolder()| containing a 52 // Creates a files in |app_group::ShareExtensionItemsFolder()| containing a
51 // serialized NSDictionary. 53 // serialized NSDictionary.
52 // If |cancel| is true, |actionType| is ignored. 54 // If |cancel| is true, |actionType| is ignored.
53 - (void)queueActionItemURL:(NSURL*)URL 55 - (void)queueActionItemURL:(NSURL*)URL
54 title:(NSString*)title 56 title:(NSString*)title
55 action:(app_group::ShareExtensionItemType)actionType 57 action:(app_group::ShareExtensionItemType)actionType
56 cancel:(BOOL)cancel 58 cancel:(BOOL)cancel
57 completion:(ProceduralBlock)completion; 59 completion:(ProceduralBlock)completion;
58 60
59 // Loads all the shared elements from the extension context and update the UI. 61 // Loads all the shared elements from the extension context and update the UI.
60 - (void)loadElementsFromContext; 62 - (void)loadElementsFromContext;
61 63
62 // Sets constaints to the widget so that margin are at least 64 // Sets constaints to the widget so that margin are at least
63 // kShareExtensionMargin points and widget width is closest up to 65 // kShareExtensionMargin points and widget width is closest up to
64 // kShareExtensionMaxWidth points. 66 // kShareExtensionMaxWidth points.
65 - (void)constrainWidgetWidth; 67 - (void)constrainWidgetWidth;
66 68
69 // Displays the normal share view.
70 - (void)displayShareView;
71
72 // Displays an alert to report an error to the user.
73 - (void)displayErrorView;
74
67 @end 75 @end
68 76
69 @implementation ShareViewController 77 @implementation ShareViewController
70 78
71 @synthesize maskView = _maskView; 79 @synthesize maskView = _maskView;
72 @synthesize shareView = _shareView; 80 @synthesize shareView = _shareView;
73 @synthesize itemType = _itemType; 81 @synthesize itemType = _itemType;
74 82
75 #pragma mark - UIViewController 83 #pragma mark - UIViewController
76 84
(...skipping 11 matching lines...) Expand all
88 // This view is the main view of the share extension. 96 // This view is the main view of the share extension.
89 ShareExtensionView* shareView = 97 ShareExtensionView* shareView =
90 [[ShareExtensionView alloc] initWithActionTarget:self]; 98 [[ShareExtensionView alloc] initWithActionTarget:self];
91 [self setShareView:shareView]; 99 [self setShareView:shareView];
92 [self.view addSubview:self.shareView]; 100 [self.view addSubview:self.shareView];
93 101
94 [self constrainWidgetWidth]; 102 [self constrainWidgetWidth];
95 103
96 // Position the widget below the screen. It will be slided up with an 104 // Position the widget below the screen. It will be slided up with an
97 // animation. 105 // animation.
98 _centerYConstraint = [[shareView centerYAnchor] 106 _widgetVerticalPlacementConstraint =
99 constraintEqualToAnchor:[self.view centerYAnchor]]; 107 [[shareView topAnchor] constraintEqualToAnchor:[self.view bottomAnchor]];
100 [_centerYConstraint setConstant:(self.view.frame.size.height + 108 [_widgetVerticalPlacementConstraint setActive:YES];
101 self.shareView.frame.size.height) /
102 2];
103 [_centerYConstraint setActive:YES];
104 [[[shareView centerXAnchor] constraintEqualToAnchor:[self.view centerXAnchor]] 109 [[[shareView centerXAnchor] constraintEqualToAnchor:[self.view centerXAnchor]]
105 setActive:YES]; 110 setActive:YES];
106 111
107 [self.maskView setTranslatesAutoresizingMaskIntoConstraints:NO]; 112 [self.maskView setTranslatesAutoresizingMaskIntoConstraints:NO];
108 [self.shareView setTranslatesAutoresizingMaskIntoConstraints:NO]; 113 [self.shareView setTranslatesAutoresizingMaskIntoConstraints:NO];
109 114
110 [self loadElementsFromContext]; 115 [self loadElementsFromContext];
111 } 116 }
112 117
113 - (void)viewWillAppear:(BOOL)animated {
114 [super viewWillAppear:animated];
115
116 // Center the widget.
117 [_centerYConstraint setConstant:0];
118 [self.maskView setAlpha:0];
119 [UIView animateWithDuration:kAnimationDuration
120 animations:^{
121 [self.maskView setAlpha:1];
122 [self.view layoutIfNeeded];
123 }];
124 }
125
126 #pragma mark - Private methods 118 #pragma mark - Private methods
127 119
120 - (void)displayShareView {
121 [self.shareView setTitle:_shareTitle];
122 [self.shareView setURL:_shareURL];
123 if (_image) {
124 [self.shareView setScreenshot:_image];
125 }
126 dispatch_async(dispatch_get_main_queue(), ^{
127 // Center the widget.
128 [_widgetVerticalPlacementConstraint setActive:NO];
gambard 2017/01/02 10:55:08 Nit: you could use dot syntax for readability, her
Olivier 2017/01/02 12:23:31 setActive has a lot of consequences, so I prefer t
129 _widgetVerticalPlacementConstraint = [[_shareView centerYAnchor]
gambard 2017/01/02 10:55:08 Same for the centerYAnchor
Olivier 2017/01/02 12:23:31 Done.
130 constraintEqualToAnchor:[self.view centerYAnchor]];
131 [_widgetVerticalPlacementConstraint setActive:YES];
132 [self.maskView setAlpha:0];
133 [UIView animateWithDuration:kAnimationDuration
134 animations:^{
135 [self.maskView setAlpha:1];
136 [self.view layoutIfNeeded];
137 }];
138 });
139 }
140
141 - (void)displayErrorView {
142 NSString* errorMessage =
143 NSLocalizedString(@"IDS_IOS_ERROR_MESSAGE_SHARE_EXTENSION",
144 @"The error message to display to the user.");
145 NSString* okButton =
146 NSLocalizedString(@"IDS_IOS_OK_BUTTON_SHARE_EXTENSION",
147 @"The label of the OK button in share extension.");
148 NSString* applicationName = [[[NSBundle mainBundle] infoDictionary]
149 valueForKey:@"CFBundleDisplayName"];
150 errorMessage =
151 [errorMessage stringByReplacingOccurrencesOfString:@"APPLICATION_NAME"
152 withString:applicationName];
153 UIAlertController* alert =
154 [UIAlertController alertControllerWithTitle:errorMessage
155 message:[_shareURL absoluteString]
156 preferredStyle:UIAlertControllerStyleAlert];
157 UIAlertAction* defaultAction =
158 [UIAlertAction actionWithTitle:okButton
159 style:UIAlertActionStyleDefault
160 handler:^(UIAlertAction* action) {
161 [self dismissAndReturnItem:nil];
162 }];
163 [alert addAction:defaultAction];
164 [self presentViewController:alert animated:YES completion:nil];
165 }
166
128 - (void)constrainWidgetWidth { 167 - (void)constrainWidgetWidth {
129 // Setting the constraints. 168 // Setting the constraints.
130 NSDictionary* views = @{ @"share" : self.shareView }; 169 NSDictionary* views = @{ @"share" : self.shareView };
131 170
132 NSDictionary* metrics = @{ 171 NSDictionary* metrics = @{
133 @"margin" : @(kShareExtensionMargin), 172 @"margin" : @(kShareExtensionMargin),
134 @"maxWidth" : @(kShareExtensionMaxWidth), 173 @"maxWidth" : @(kShareExtensionMaxWidth),
135 }; 174 };
136 175
137 NSArray* constraints = @[ 176 NSArray* constraints = @[
(...skipping 26 matching lines...) Expand all
164 if ([itemProvider hasItemConformingToTypeIdentifier:typeURL]) { 203 if ([itemProvider hasItemConformingToTypeIdentifier:typeURL]) {
165 ItemBlock URLCompletion = ^(id idURL, NSError* error) { 204 ItemBlock URLCompletion = ^(id idURL, NSError* error) {
166 NSURL* URL = static_cast<NSURL*>(idURL); 205 NSURL* URL = static_cast<NSURL*>(idURL);
167 dispatch_async(dispatch_get_main_queue(), ^{ 206 dispatch_async(dispatch_get_main_queue(), ^{
168 _shareItem = [item copy]; 207 _shareItem = [item copy];
169 _shareURL = [URL copy]; 208 _shareURL = [URL copy];
170 _shareTitle = [[[item attributedContentText] string] copy]; 209 _shareTitle = [[[item attributedContentText] string] copy];
171 if ([_shareTitle length] == 0) { 210 if ([_shareTitle length] == 0) {
172 _shareTitle = [URL host]; 211 _shareTitle = [URL host];
173 } 212 }
174 [self.shareView setURL:URL]; 213 if ([[_shareURL scheme] isEqualToString:@"http"] ||
175 [self.shareView setTitle:_shareTitle]; 214 [[_shareURL scheme] isEqualToString:@"https"]) {
215 [self displayShareView];
216 } else {
217 [self displayErrorView];
218 }
176 }); 219 });
177 220
178 }; 221 };
179 [itemProvider loadItemForTypeIdentifier:typeURL 222 [itemProvider loadItemForTypeIdentifier:typeURL
180 options:nil 223 options:nil
181 completionHandler:URLCompletion]; 224 completionHandler:URLCompletion];
182 NSDictionary* imageOptions = @{ 225 NSDictionary* imageOptions = @{
183 NSItemProviderPreferredImageSizeKey : [NSValue 226 NSItemProviderPreferredImageSizeKey : [NSValue
184 valueWithCGSize:CGSizeMake(kScreenShotWidth, kScreenShotHeight)] 227 valueWithCGSize:CGSizeMake(kScreenShotWidth, kScreenShotHeight)]
185 }; 228 };
186 ItemBlock ImageCompletion = ^(id item, NSError* error) { 229 ItemBlock imageCompletion = ^(id item, NSError* error) {
187 230 _image = static_cast<UIImage*>(item);
188 UIImage* image = static_cast<UIImage*>(item); 231 if (_image && self.shareView) {
189 if (image) {
190 dispatch_async(dispatch_get_main_queue(), ^{ 232 dispatch_async(dispatch_get_main_queue(), ^{
191 [self.shareView setScreenshot:image]; 233 [self.shareView setScreenshot:_image];
192 }); 234 });
193 } 235 }
194
195 }; 236 };
196 [itemProvider loadPreviewImageWithOptions:imageOptions 237 [itemProvider loadPreviewImageWithOptions:imageOptions
197 completionHandler:ImageCompletion]; 238 completionHandler:imageCompletion];
198 } 239 }
199 } 240 }
200 } 241 }
201 } 242 }
202 243
203 - (void)dismissAndReturnItem:(NSExtensionItem*)item { 244 - (void)dismissAndReturnItem:(NSExtensionItem*)item {
204 // Set the Y center constraints so the whole extension slides out of the 245 // Set the Y placement constraints so the whole extension slides out of the
205 // screen. Constant is relative to the center of the screen. 246 // screen.
206 // The direction (up or down) is relative to the output (cancel or submit). 247 // The direction (up or down) is relative to the output (cancel or submit).
207 NSInteger direction = item ? -1 : 1; 248 [_widgetVerticalPlacementConstraint setActive:NO];
208 [_centerYConstraint setConstant:direction * 249 if (item) {
209 (self.view.frame.size.height + 250 _widgetVerticalPlacementConstraint = [[_shareView bottomAnchor]
210 self.shareView.frame.size.height) / 251 constraintEqualToAnchor:[self.view topAnchor]];
211 2]; 252 } else {
253 _widgetVerticalPlacementConstraint = [[_shareView topAnchor]
254 constraintEqualToAnchor:[self.view bottomAnchor]];
255 }
256 [_widgetVerticalPlacementConstraint setActive:YES];
212 [UIView animateWithDuration:kAnimationDuration 257 [UIView animateWithDuration:kAnimationDuration
213 animations:^{ 258 animations:^{
214 [self.maskView setAlpha:0]; 259 [self.maskView setAlpha:0];
215 [self.view layoutIfNeeded]; 260 [self.view layoutIfNeeded];
216 } 261 }
217 completion:^(BOOL finished) { 262 completion:^(BOOL finished) {
218 NSArray* returnItem = item ? @[ item ] : @[]; 263 NSArray* returnItem = item ? @[ item ] : @[];
219 [self.extensionContext completeRequestReturningItems:returnItem 264 [self.extensionContext completeRequestReturningItems:returnItem
220 completionHandler:nil]; 265 completionHandler:nil];
221 }]; 266 }];
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 [self dismissAndReturnItem:_shareItem]; 343 [self dismissAndReturnItem:_shareItem];
299 }]; 344 }];
300 } 345 }
301 346
302 - (void)shareExtensionView:(id)sender 347 - (void)shareExtensionView:(id)sender
303 typeChanged:(app_group::ShareExtensionItemType)type { 348 typeChanged:(app_group::ShareExtensionItemType)type {
304 [self setItemType:type]; 349 [self setItemType:type];
305 } 350 }
306 351
307 @end 352 @end
OLDNEW
« no previous file with comments | « ios/chrome/share_extension/share_extension_view.mm ('k') | ios/chrome/share_extension/strings/ios_share_extension_strings.grd » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698