| 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 |