OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h
" | 5 #import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h
" |
6 #import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller_p
rivate.h" | 6 #import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller_p
rivate.h" |
7 | 7 |
8 #import <StoreKit/StoreKit.h> | 8 #import <StoreKit/StoreKit.h> |
9 | 9 |
10 #import "base/ios/weak_nsobject.h" | |
11 #include "base/logging.h" | 10 #include "base/logging.h" |
12 #import "base/mac/foundation_util.h" | 11 #import "base/mac/foundation_util.h" |
13 #import "base/mac/scoped_nsobject.h" | |
14 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
15 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
16 #include "base/metrics/user_metrics.h" | 14 #include "base/metrics/user_metrics.h" |
17 #include "base/metrics/user_metrics_action.h" | 15 #include "base/metrics/user_metrics_action.h" |
18 #include "base/strings/sys_string_conversions.h" | 16 #include "base/strings/sys_string_conversions.h" |
19 #include "base/threading/sequenced_worker_pool.h" | 17 #include "base/threading/sequenced_worker_pool.h" |
20 #include "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h" | 18 #include "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h" |
21 #import "ios/chrome/browser/installation_notifier.h" | 19 #import "ios/chrome/browser/installation_notifier.h" |
22 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrom
e.h" | 20 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrom
e.h" |
23 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item
.h" | 21 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item
.h" |
24 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" | 22 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" |
25 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" | 23 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" |
26 #import "ios/chrome/browser/ui/settings/cells/native_app_item.h" | 24 #import "ios/chrome/browser/ui/settings/cells/native_app_item.h" |
27 #import "ios/chrome/browser/ui/settings/settings_utils.h" | 25 #import "ios/chrome/browser/ui/settings/settings_utils.h" |
28 #import "ios/chrome/common/string_util.h" | 26 #import "ios/chrome/common/string_util.h" |
29 #include "ios/chrome/grit/ios_strings.h" | 27 #include "ios/chrome/grit/ios_strings.h" |
30 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h" | 28 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h" |
31 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_metad
ata.h" | 29 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_metad
ata.h" |
32 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_white
list_manager.h" | 30 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_white
list_manager.h" |
33 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate
rialButtons.h" | 31 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate
rialButtons.h" |
34 #include "ios/web/public/web_thread.h" | 32 #include "ios/web/public/web_thread.h" |
35 #include "ui/base/l10n/l10n_util.h" | 33 #include "ui/base/l10n/l10n_util.h" |
36 #include "url/gurl.h" | 34 #include "url/gurl.h" |
37 | 35 |
| 36 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 37 #error "This file requires ARC support." |
| 38 #endif |
| 39 |
38 const NSInteger kTagShift = 1000; | 40 const NSInteger kTagShift = 1000; |
39 | 41 |
40 namespace { | 42 namespace { |
41 | 43 |
42 typedef NS_ENUM(NSInteger, SectionIdentifier) { | 44 typedef NS_ENUM(NSInteger, SectionIdentifier) { |
43 SectionIdentifierLearnMore = kSectionIdentifierEnumZero, | 45 SectionIdentifierLearnMore = kSectionIdentifierEnumZero, |
44 SectionIdentifierApps, | 46 SectionIdentifierApps, |
45 }; | 47 }; |
46 | 48 |
47 typedef NS_ENUM(NSInteger, ItemType) { | 49 typedef NS_ENUM(NSInteger, ItemType) { |
48 ItemTypeApp = kItemTypeEnumZero, | 50 ItemTypeApp = kItemTypeEnumZero, |
49 ItemTypeLearnMore, | 51 ItemTypeLearnMore, |
50 }; | 52 }; |
51 | 53 |
52 } // namespace | 54 } // namespace |
53 | 55 |
54 @interface NativeAppsCollectionViewController ()< | 56 @interface NativeAppsCollectionViewController ()< |
55 SKStoreProductViewControllerDelegate> { | 57 SKStoreProductViewControllerDelegate> { |
56 std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> _imageFetcher; | 58 std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> _imageFetcher; |
57 base::scoped_nsobject<NSArray> _nativeAppsInSettings; | 59 NSArray* _nativeAppsInSettings; |
58 BOOL _userDidSomething; | 60 BOOL _userDidSomething; |
59 } | 61 } |
60 | 62 |
61 // List of the native apps visible in Settings. | 63 // List of the native apps visible in Settings. |
62 @property(nonatomic, copy) NSArray* appsInSettings; | 64 @property(nonatomic, copy) NSArray* appsInSettings; |
63 | 65 |
64 // Delegate for App-Store-related operations. | 66 // Delegate for App-Store-related operations. |
65 @property(nonatomic, assign) id<StoreKitLauncher> storeKitLauncher; | 67 @property(nonatomic, weak) id<StoreKitLauncher> storeKitLauncher; |
66 | 68 |
67 // Sets up the list of visible apps based on |nativeAppWhitelistManager|, which | 69 // Sets up the list of visible apps based on |nativeAppWhitelistManager|, which |
68 // serves as datasource for this controller. Apps from | 70 // serves as datasource for this controller. Apps from |
69 // |nativeAppWhitelistManager| are stored in |_nativeAppsInSettings| and | 71 // |nativeAppWhitelistManager| are stored in |_nativeAppsInSettings| and |
70 // |-reloadData| is sent to the receiver. | 72 // |-reloadData| is sent to the receiver. |
71 - (void)configureWithNativeAppWhiteListManager: | 73 - (void)configureWithNativeAppWhiteListManager: |
72 (id<NativeAppWhitelistManager>)nativeAppWhitelistManager; | 74 (id<NativeAppWhitelistManager>)nativeAppWhitelistManager; |
73 | 75 |
74 // Returns a new Native App collection view item for the metadata at |index| in | 76 // Returns a new Native App collection view item for the metadata at |index| in |
75 // |_nativeAppsInSettings|. | 77 // |_nativeAppsInSettings|. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 | 112 |
111 [self loadModel]; | 113 [self loadModel]; |
112 } | 114 } |
113 return self; | 115 return self; |
114 } | 116 } |
115 | 117 |
116 - (void)dealloc { | 118 - (void)dealloc { |
117 [[InstallationNotifier sharedInstance] unregisterForNotifications:self]; | 119 [[InstallationNotifier sharedInstance] unregisterForNotifications:self]; |
118 if (!_userDidSomething) | 120 if (!_userDidSomething) |
119 [self recordUserAction:settings::kNativeAppsActionDidNothing]; | 121 [self recordUserAction:settings::kNativeAppsActionDidNothing]; |
120 [super dealloc]; | |
121 } | 122 } |
122 | 123 |
123 #pragma mark - View lifecycle | 124 #pragma mark - View lifecycle |
124 | 125 |
125 - (void)viewDidLoad { | 126 - (void)viewDidLoad { |
126 self.title = l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_SM_SETTINGS); | 127 self.title = l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_SM_SETTINGS); |
127 [self configureWithNativeAppWhiteListManager: | 128 [self configureWithNativeAppWhiteListManager: |
128 ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()]; | 129 ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()]; |
129 | 130 |
130 [super viewDidLoad]; | 131 [super viewDidLoad]; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 forControlEvents:UIControlEventValueChanged]; | 207 forControlEvents:UIControlEventValueChanged]; |
207 appCell.installButton.tag = [self tagForIndexPath:indexPath]; | 208 appCell.installButton.tag = [self tagForIndexPath:indexPath]; |
208 [appCell.installButton addTarget:self | 209 [appCell.installButton addTarget:self |
209 action:@selector(installApp:) | 210 action:@selector(installApp:) |
210 forControlEvents:UIControlEventTouchUpInside]; | 211 forControlEvents:UIControlEventTouchUpInside]; |
211 CollectionViewItem* item = | 212 CollectionViewItem* item = |
212 [self.collectionViewModel itemAtIndexPath:indexPath]; | 213 [self.collectionViewModel itemAtIndexPath:indexPath]; |
213 NativeAppItem* appItem = base::mac::ObjCCastStrict<NativeAppItem>(item); | 214 NativeAppItem* appItem = base::mac::ObjCCastStrict<NativeAppItem>(item); |
214 if (!appItem.icon) { | 215 if (!appItem.icon) { |
215 // Fetch the real icon. | 216 // Fetch the real icon. |
216 base::WeakNSObject<NativeAppsCollectionViewController> weakSelf(self); | 217 __weak NativeAppsCollectionViewController* weakSelf = self; |
217 id<NativeAppMetadata> metadata = [self nativeAppAtIndex:indexPath.item]; | 218 id<NativeAppMetadata> metadata = [self nativeAppAtIndex:indexPath.item]; |
218 [metadata fetchSmallIconWithImageFetcher:_imageFetcher.get() | 219 [metadata fetchSmallIconWithImageFetcher:_imageFetcher.get() |
219 completionBlock:^(UIImage* image) { | 220 completionBlock:^(UIImage* image) { |
220 base::scoped_nsobject< | 221 |
221 NativeAppsCollectionViewController> | 222 NativeAppsCollectionViewController* strongSelf = |
222 strongSelf([weakSelf retain]); | 223 weakSelf; |
223 if (!image || !strongSelf) | 224 if (!image || !strongSelf) |
224 return; | 225 return; |
225 appItem.icon = image; | 226 appItem.icon = image; |
226 [strongSelf.get().collectionView | 227 [strongSelf.collectionView |
227 reloadItemsAtIndexPaths:@[ indexPath ]]; | 228 reloadItemsAtIndexPaths:@[ indexPath ]]; |
228 }]; | 229 }]; |
229 } | 230 } |
230 } | 231 } |
231 | 232 |
232 - (CollectionViewItem*)learnMoreItem { | 233 - (CollectionViewItem*)learnMoreItem { |
233 NSString* learnMoreText = | 234 NSString* learnMoreText = |
234 l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_SM_SECTION_HEADER); | 235 l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_SM_SECTION_HEADER); |
235 CollectionViewFooterItem* learnMoreItem = [[[CollectionViewFooterItem alloc] | 236 CollectionViewFooterItem* learnMoreItem = |
236 initWithType:ItemTypeLearnMore] autorelease]; | 237 [[CollectionViewFooterItem alloc] initWithType:ItemTypeLearnMore]; |
237 learnMoreItem.text = learnMoreText; | 238 learnMoreItem.text = learnMoreText; |
238 return learnMoreItem; | 239 return learnMoreItem; |
239 } | 240 } |
240 | 241 |
241 #pragma mark - SKStoreProductViewControllerDelegate methods | 242 #pragma mark - SKStoreProductViewControllerDelegate methods |
242 | 243 |
243 - (void)productViewControllerDidFinish: | 244 - (void)productViewControllerDidFinish: |
244 (SKStoreProductViewController*)viewController { | 245 (SKStoreProductViewController*)viewController { |
245 [self dismissViewControllerAnimated:YES completion:nil]; | 246 [self dismissViewControllerAnimated:YES completion:nil]; |
246 } | 247 } |
247 | 248 |
248 #pragma mark - StoreKitLauncher methods | 249 #pragma mark - StoreKitLauncher methods |
249 | 250 |
250 - (void)openAppStore:(NSString*)appId { | 251 - (void)openAppStore:(NSString*)appId { |
251 // Reported crashes show that -openAppStore: had been called with | 252 // Reported crashes show that -openAppStore: had been called with |
252 // a nil |appId|, but opening AppStore is meaningful only if the |appId| is | 253 // a nil |appId|, but opening AppStore is meaningful only if the |appId| is |
253 // not nil, so be defensive and early return if |appId| is nil. | 254 // not nil, so be defensive and early return if |appId| is nil. |
254 if (![appId length]) | 255 if (![appId length]) |
255 return; | 256 return; |
256 NSDictionary* product = | 257 NSDictionary* product = |
257 @{SKStoreProductParameterITunesItemIdentifier : appId}; | 258 @{SKStoreProductParameterITunesItemIdentifier : appId}; |
258 base::scoped_nsobject<SKStoreProductViewController> storeViewController( | 259 SKStoreProductViewController* storeViewController = |
259 [[SKStoreProductViewController alloc] init]); | 260 [[SKStoreProductViewController alloc] init]; |
260 [storeViewController setDelegate:self]; | 261 [storeViewController setDelegate:self]; |
261 [storeViewController loadProductWithParameters:product completionBlock:nil]; | 262 [storeViewController loadProductWithParameters:product completionBlock:nil]; |
262 [self presentViewController:storeViewController animated:YES completion:nil]; | 263 [self presentViewController:storeViewController animated:YES completion:nil]; |
263 } | 264 } |
264 | 265 |
265 #pragma mark - MDCCollectionViewStylingDelegate | 266 #pragma mark - MDCCollectionViewStylingDelegate |
266 | 267 |
267 // MDCCollectionViewStylingDelegate protocol is implemented so that cells don't | 268 // MDCCollectionViewStylingDelegate protocol is implemented so that cells don't |
268 // display ink on touch. | 269 // display ink on touch. |
269 - (BOOL)collectionView:(nonnull UICollectionView*)collectionView | 270 - (BOOL)collectionView:(nonnull UICollectionView*)collectionView |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 - (CollectionViewItem*)nativeAppItemAtIndex:(NSUInteger)index { | 366 - (CollectionViewItem*)nativeAppItemAtIndex:(NSUInteger)index { |
366 id<NativeAppMetadata> metadata = [self nativeAppAtIndex:index]; | 367 id<NativeAppMetadata> metadata = [self nativeAppAtIndex:index]; |
367 // Determine the state of the cell. | 368 // Determine the state of the cell. |
368 NativeAppItemState state; | 369 NativeAppItemState state; |
369 if ([metadata isInstalled]) { | 370 if ([metadata isInstalled]) { |
370 state = [metadata shouldAutoOpenLinks] ? NativeAppItemSwitchOn | 371 state = [metadata shouldAutoOpenLinks] ? NativeAppItemSwitchOn |
371 : NativeAppItemSwitchOff; | 372 : NativeAppItemSwitchOff; |
372 } else { | 373 } else { |
373 state = NativeAppItemInstall; | 374 state = NativeAppItemInstall; |
374 } | 375 } |
375 NativeAppItem* appItem = | 376 NativeAppItem* appItem = [[NativeAppItem alloc] initWithType:ItemTypeApp]; |
376 [[[NativeAppItem alloc] initWithType:ItemTypeApp] autorelease]; | |
377 appItem.name = [metadata appName]; | 377 appItem.name = [metadata appName]; |
378 appItem.state = state; | 378 appItem.state = state; |
379 return appItem; | 379 return appItem; |
380 } | 380 } |
381 | 381 |
382 - (NSArray*)appsInSettings { | 382 - (NSArray*)appsInSettings { |
383 return _nativeAppsInSettings.get(); | 383 return _nativeAppsInSettings; |
384 } | 384 } |
385 | 385 |
386 - (void)setAppsInSettings:(NSArray*)apps { | 386 - (void)setAppsInSettings:(NSArray*)apps { |
387 _nativeAppsInSettings.reset([apps copy]); | 387 _nativeAppsInSettings = [apps copy]; |
388 } | 388 } |
389 | 389 |
390 - (NSInteger)tagForIndexPath:(NSIndexPath*)indexPath { | 390 - (NSInteger)tagForIndexPath:(NSIndexPath*)indexPath { |
391 DCHECK(indexPath.section == | 391 DCHECK(indexPath.section == |
392 [self.collectionViewModel | 392 [self.collectionViewModel |
393 sectionForSectionIdentifier:SectionIdentifierApps]); | 393 sectionForSectionIdentifier:SectionIdentifierApps]); |
394 return indexPath.item + kTagShift; | 394 return indexPath.item + kTagShift; |
395 } | 395 } |
396 | 396 |
397 - (NSIndexPath*)indexPathForTag:(NSInteger)shiftedTag { | 397 - (NSIndexPath*)indexPathForTag:(NSInteger)shiftedTag { |
398 NSInteger unshiftedTag = shiftedTag - kTagShift; | 398 NSInteger unshiftedTag = shiftedTag - kTagShift; |
399 return [NSIndexPath | 399 return [NSIndexPath |
400 indexPathForItem:unshiftedTag | 400 indexPathForItem:unshiftedTag |
401 inSection:[self.collectionViewModel | 401 inSection:[self.collectionViewModel |
402 sectionForSectionIdentifier:SectionIdentifierApps]]; | 402 sectionForSectionIdentifier:SectionIdentifierApps]]; |
403 } | 403 } |
404 | 404 |
405 @end | 405 @end |
OLD | NEW |