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

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

Issue 2586713002: Upstream code and resources for Chrome on iOS extensions. (Closed)
Patch Set: Created 4 years 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #import <MobileCoreServices/MobileCoreServices.h>
6
7 #import "ios/chrome/share_extension/share_view_controller.h"
8
9 #import "base/ios/block_types.h"
10 #import "base/mac/foundation_util.h"
11 #import "ios/chrome/common/app_group/app_group_constants.h"
12 #import "ios/chrome/share_extension/share_extension_view.h"
13 #import "ios/chrome/share_extension/ui_util.h"
14
15 #if !defined(__has_feature) || !__has_feature(objc_arc)
16 #error "This file requires ARC support."
17 #endif
18
19 // Type for completion handler to fetch the components of the share items.
20 // |idResponse| type depends on the element beeing fetched.
21 using ItemBlock = void (^)(id idResponse, NSError* error);
22
23 namespace {
24
25 // Minimum size around the widget
26 const CGFloat kShareExtensionMargin = 15;
27 const CGFloat kShareExtensionMaxWidth = 390;
28 // Clip the last separator out of the table view.
29 const CGFloat kScreenShotWidth = 100;
30 const CGFloat kScreenShotHeight = 100;
31 const CGFloat kAnimationDuration = 0.3;
32 const CGFloat kMediumAlpha = 0.5;
33
34 } // namespace
35
36 @interface ShareViewController ()<ShareExtensionViewActionTarget> {
37 // This constraint the center of the widget to be vertically in the center
38 // of the the screen. It has to be modified for the dismissal animation.
39 NSLayoutConstraint* _centerYConstraint;
40
41 NSURL* _shareURL;
42 NSString* _shareTitle;
43 NSExtensionItem* _shareItem;
44 }
45
46 @property(nonatomic, weak) UIView* maskView;
47 @property(nonatomic, weak) ShareExtensionView* shareView;
48 @property(nonatomic, assign) app_group::ShareExtensionItemType itemType;
49
50 // Creates a files in |app_group::ShareExtensionItemsFolder()| containing a
51 // serialized NSDictionary.
52 // If |cancel| is true, |actionType| is ignored.
53 - (void)queueActionItemURL:(NSURL*)URL
54 title:(NSString*)title
55 action:(app_group::ShareExtensionItemType)actionType
56 cancel:(BOOL)cancel
57 completion:(ProceduralBlock)completion;
58
59 // Loads all the shared elements from the extension context and update the UI.
60 - (void)loadElementsFromContext;
61
62 // Performs a fade in animation for the whole widget.
63 - (void)fadeIn;
64
65 // Sets constaints to the widget so that margin are at least
66 // kShareExtensionMargin points and widget width is closest up to
67 // kShareExtensionMaxWidth points.
68 - (void)constrainWidgetWidth;
69
70 @end
71
72 @implementation ShareViewController
73
74 @synthesize maskView = _maskView;
75 @synthesize shareView = _shareView;
76 @synthesize itemType = _itemType;
77
78 - (void)viewDidLoad {
79 [super viewDidLoad];
80
81 // This view shadows the screen under the share extension.
82 UIView* maskView = [[UIView alloc] initWithFrame:CGRectZero];
83 [self setMaskView:maskView];
84 [self.maskView
85 setBackgroundColor:[UIColor colorWithWhite:0 alpha:kMediumAlpha]];
86 [self.view addSubview:self.maskView];
87 ui_util::ConstrainAllSidesOfViewToView(self.view, self.maskView);
88
89 // This view is the main view of the share extension.
90 ShareExtensionView* shareView =
91 [[ShareExtensionView alloc] initWithActionTarget:self];
92 [self setShareView:shareView];
93 [self.view addSubview:self.shareView];
94
95 [self constrainWidgetWidth];
96
97 // Center the widget in the screen.
98 _centerYConstraint = [[shareView centerYAnchor]
99 constraintEqualToAnchor:[self.view centerYAnchor]];
100 [_centerYConstraint setActive:YES];
101 [[[shareView centerXAnchor] constraintEqualToAnchor:[self.view centerXAnchor]]
102 setActive:YES];
103
104 [self.maskView setTranslatesAutoresizingMaskIntoConstraints:NO];
105 [self.shareView setTranslatesAutoresizingMaskIntoConstraints:NO];
106
107 [self loadElementsFromContext];
108 [self fadeIn];
109 }
110
111 - (void)constrainWidgetWidth {
112 // Setting the constraints.
113 NSDictionary* views = @{ @"share" : self.shareView };
114
115 NSDictionary* metrics = @{
116 @"margin" : @(kShareExtensionMargin),
117 @"maxWidth" : @(kShareExtensionMaxWidth),
118 };
119
120 NSArray* constraints = @[
121 // Sets the margin around the share extension.
122 @"H:|-(>=margin)-[share(<=maxWidth)]-(>=margin)-|",
123 // If the screen is too small, reduce width of widget.
124 @"H:[share(==maxWidth@900)]",
125 ];
126
127 for (NSString* constraint : constraints) {
128 [NSLayoutConstraint
129 activateConstraints:[NSLayoutConstraint
130 constraintsWithVisualFormat:constraint
131 options:0
132 metrics:metrics
133 views:views]];
134 }
135
136 // |self.shareView| must be as large as possible and in the center of the
137 // screen.
138 [self.shareView
139 setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh
140 forAxis:UILayoutConstraintAxisHorizontal];
141 }
142
143 - (void)fadeIn {
144 // Fade in animation.
145 [self.maskView setAlpha:0];
146 [self.shareView setAlpha:0];
147 [UIView animateWithDuration:kAnimationDuration
148 animations:^{
149 [self.maskView setAlpha:kMediumAlpha];
150 [self.shareView setAlpha:1];
151 }];
152 }
153
154 - (void)loadElementsFromContext {
155 NSString* typeURL = static_cast<NSString*>(kUTTypeURL);
156 for (NSExtensionItem* item in self.extensionContext.inputItems) {
157 for (NSItemProvider* itemProvider in item.attachments) {
158 if ([itemProvider hasItemConformingToTypeIdentifier:typeURL]) {
159 ItemBlock URLCompletion = ^(id idURL, NSError* error) {
160 NSURL* URL = static_cast<NSURL*>(idURL);
161 dispatch_async(dispatch_get_main_queue(), ^{
162 _shareItem = [item copy];
163 _shareURL = [URL copy];
164 _shareTitle = [[[item attributedContentText] string] copy];
165 if ([_shareTitle length] == 0) {
166 _shareTitle = [URL host];
167 }
168 [self.shareView setURL:URL];
169 [self.shareView setTitle:_shareTitle];
170 });
171
172 };
173 [itemProvider loadItemForTypeIdentifier:typeURL
174 options:nil
175 completionHandler:URLCompletion];
176 NSDictionary* imageOptions = @{
177 NSItemProviderPreferredImageSizeKey : [NSValue
178 valueWithCGSize:CGSizeMake(kScreenShotWidth, kScreenShotHeight)]
179 };
180 ItemBlock ImageCompletion = ^(id item, NSError* error) {
181
182 UIImage* image = static_cast<UIImage*>(item);
183 if (image) {
184 dispatch_async(dispatch_get_main_queue(), ^{
185 [self.shareView setScreenshot:image];
186 });
187 }
188
189 };
190 [itemProvider loadPreviewImageWithOptions:imageOptions
191 completionHandler:ImageCompletion];
192 }
193 }
194 }
195 }
196
197 - (void)dismissAndReturnItem:(NSExtensionItem*)item {
198 // Set the Y center constraints so the whole extension slides up out of the
199 // screen. Constant is relative to the center of the screen.
200 [_centerYConstraint setConstant:-(self.view.frame.size.height +
201 self.shareView.frame.size.height) /
202 2];
203 [UIView animateWithDuration:kAnimationDuration
204 animations:^{
205 [self.maskView setAlpha:0];
206 [self.view layoutIfNeeded];
207 }
208 completion:^(BOOL finished) {
209 NSArray* returnItem = item ? @[ item ] : @[];
210 [self.extensionContext completeRequestReturningItems:returnItem
211 completionHandler:nil];
212 }];
213 }
214
215 - (void)queueActionItemURL:(NSURL*)URL
216 title:(NSString*)title
217 action:(app_group::ShareExtensionItemType)actionType
218 cancel:(BOOL)cancel
219 completion:(ProceduralBlock)completion {
220 NSURL* readingListURL = app_group::ShareExtensionItemsFolder();
221 if (![[NSFileManager defaultManager]
222 fileExistsAtPath:[readingListURL path]]) {
223 [[NSFileManager defaultManager] createDirectoryAtPath:[readingListURL path]
224 withIntermediateDirectories:YES
225 attributes:nil
226 error:nil];
227 }
228 NSDate* date = [NSDate date];
229 NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
230 // This format sorts files by alphabetical order.
231 [dateFormatter setDateFormat:@"yyyy-MM-dd-HH-mm-ss.SSSSSS"];
232 NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
233 [dateFormatter setTimeZone:timeZone];
234 NSString* dateString = [dateFormatter stringFromDate:date];
235 NSURL* fileURL =
236 [readingListURL URLByAppendingPathComponent:dateString isDirectory:NO];
237
238 NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
239 if (URL)
240 [dict setObject:URL forKey:app_group::kShareItemURL];
241 if (title)
242 [dict setObject:title forKey:app_group::kShareItemTitle];
243 [dict setObject:date forKey:app_group::kShareItemDate];
244
245 if (!cancel) {
246 NSNumber* entryType = [NSNumber numberWithInteger:actionType];
247 [dict setObject:entryType forKey:app_group::kShareItemType];
248 }
249
250 [dict setValue:[NSNumber numberWithBool:cancel]
251 forKey:app_group::kShareItemCancel];
252 NSData* data = [NSKeyedArchiver archivedDataWithRootObject:dict];
253 [[NSFileManager defaultManager] createFileAtPath:[fileURL path]
254 contents:data
255 attributes:nil];
256 if (completion) {
257 completion();
258 }
259 }
260
261 #pragma mark - ShareExtensionViewActionTarget
262
263 - (void)shareExtensionViewDidSelectCancel:(id)sender {
264 [self queueActionItemURL:nil
265 title:nil
266 action:app_group::READING_LIST_ITEM // Ignored
267 cancel:YES
268 completion:^{
269 [self dismissAndReturnItem:nil];
270 }];
271 }
272
273 - (void)shareExtensionViewDidSelectAddToReadingList:(id)sender {
274 [self queueActionItemURL:_shareURL
275 title:_shareTitle
276 action:app_group::READING_LIST_ITEM
277 cancel:NO
278 completion:^{
279 [self dismissAndReturnItem:_shareItem];
280 }];
281 }
282
283 - (void)shareExtensionViewDidSelectAddToBookmarks:(id)sender {
284 [self queueActionItemURL:_shareURL
285 title:_shareTitle
286 action:app_group::BOOKMARK_ITEM
287 cancel:NO
288 completion:^{
289 [self dismissAndReturnItem:_shareItem];
290 }];
291 }
292
293 - (void)shareExtensionView:(id)sender
294 typeChanged:(app_group::ShareExtensionItemType)type {
295 [self setItemType:type];
296 }
297
298 @end
OLDNEW
« no previous file with comments | « ios/chrome/share_extension/share_view_controller.h ('k') | ios/chrome/share_extension/ui_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698