| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.h" |
| |
| #include <memory> |
| |
| #include "base/auto_reset.h" |
| #include "base/mac/foundation_util.h" |
| #include "components/autofill/core/common/autofill_prefs.h" |
| #include "components/google/core/common/google_util.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "components/sync/base/model_type.h" |
| #include "components/sync/driver/sync_service.h" |
| #include "components/sync/driver/sync_user_settings.h" |
| #include "ios/chrome/browser/application_context.h" |
| #include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
| #include "ios/chrome/browser/chrome_url_constants.h" |
| #include "ios/chrome/browser/experimental_flags.h" |
| #import "ios/chrome/browser/signin/authentication_service.h" |
| #include "ios/chrome/browser/signin/authentication_service_factory.h" |
| #import "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h" |
| #include "ios/chrome/browser/signin/identity_manager_factory.h" |
| #include "ios/chrome/browser/sync/profile_sync_service_factory.h" |
| #include "ios/chrome/browser/sync/sync_setup_service.h" |
| #include "ios/chrome/browser/sync/sync_setup_service_factory.h" |
| #import "ios/chrome/browser/ui/authentication/authentication_flow.h" |
| #import "ios/chrome/browser/ui/authentication/resized_avatar_cache.h" |
| #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h" |
| #import "ios/chrome/browser/ui/collection_view/cells/collection_view_account_item.h" |
| #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" |
| #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" |
| #import "ios/chrome/browser/ui/commands/application_commands.h" |
| #import "ios/chrome/browser/ui/commands/open_new_tab_command.h" |
| #import "ios/chrome/browser/ui/commands/show_signin_command.h" |
| #import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_detail_item.h" |
| #import "ios/chrome/browser/ui/settings/cells/legacy/legacy_sync_switch_item.h" |
| #import "ios/chrome/browser/ui/settings/cells/settings_text_item.h" |
| #import "ios/chrome/browser/ui/settings/cells/text_and_error_item.h" |
| #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" |
| #import "ios/chrome/browser/ui/settings/sync_encryption_passphrase_table_view_controller.h" |
| #import "ios/chrome/browser/ui/settings/sync_encryption_table_view_controller.h" |
| #import "ios/chrome/browser/ui/settings/sync_utils/sync_util.h" |
| #import "ios/chrome/browser/ui/util/uikit_ui_util.h" |
| #include "ios/chrome/grit/ios_strings.h" |
| #import "ios/public/provider/chrome/browser/chrome_browser_provider.h" |
| #import "ios/public/provider/chrome/browser/signin/chrome_identity.h" |
| #import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" |
| #import "services/identity/public/objc/identity_manager_observer_bridge.h" |
| #include "ui/base/l10n/l10n_util_mac.h" |
| #include "url/gurl.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| // The a11y identifier of the view controller's view. |
| NSString* const kSettingsSyncId = @"kSettingsSyncId"; |
| // Notification when a switch account operation will start. |
| NSString* const kSwitchAccountWillStartNotification = |
| @"kSwitchAccountWillStartNotification"; |
| // Notification when a switch account operation did finish. |
| NSString* const kSwitchAccountDidFinishNotification = |
| @"kSwitchAccountDidFinishNotification"; |
| // Used to tag and retrieve ItemTypeSyncableDataType cell tags. |
| const NSInteger kTagShift = 1000; |
| |
| namespace { |
| |
| typedef NS_ENUM(NSInteger, SectionIdentifier) { |
| SectionIdentifierSyncError = kSectionIdentifierEnumZero, |
| SectionIdentifierEnableSync, |
| SectionIdentifierSyncAccounts, |
| SectionIdentifierSyncServices, |
| SectionIdentifierEncryptionAndFooter, |
| }; |
| |
| typedef NS_ENUM(NSInteger, ItemType) { |
| ItemTypeSyncError = kItemTypeEnumZero, |
| ItemTypeSyncSwitch, |
| ItemTypeAccount, |
| ItemTypeSyncEverything, |
| ItemTypeSyncableDataType, |
| ItemTypeAutofillWalletImport, |
| ItemTypeEncryption, |
| ItemTypeManageSyncedData, |
| ItemTypeHeader, |
| }; |
| |
| } // namespace |
| |
| @interface SyncSettingsCollectionViewController () < |
| ChromeIdentityServiceObserver, |
| IdentityManagerObserverBridgeDelegate, |
| SettingsControllerProtocol, |
| SyncObserverModelBridge> { |
| ios::ChromeBrowserState* _browserState; // Weak. |
| SyncSetupService* _syncSetupService; // Weak. |
| std::unique_ptr<SyncObserverBridge> _syncObserver; |
| std::unique_ptr<identity::IdentityManagerObserverBridge> |
| _identityManagerObserver; |
| AuthenticationFlow* _authenticationFlow; |
| // Whether switching sync account is allowed on the screen. |
| BOOL _allowSwitchSyncAccount; |
| // Whether an authentication operation is in progress (e.g switch accounts). |
| BOOL _authenticationOperationInProgress; |
| // Whether Sync State changes should be currently ignored. |
| BOOL _ignoreSyncStateChanges; |
| |
| // Cache for Identity items avatar images. |
| ResizedAvatarCache* _avatarCache; |
| std::unique_ptr<ChromeIdentityServiceObserverBridge> _identityServiceObserver; |
| // Enable lookup of item corresponding to a given identity GAIA ID string. |
| NSDictionary<NSString*, CollectionViewItem*>* _identityMap; |
| } |
| |
| // Stops observing browser state services. |
| - (void)stopBrowserStateServiceObservers; |
| // Pops the view if user is signed out and not authentication operation is in |
| // progress. Returns YES if the view was popped. |
| - (BOOL)popViewIfSignedOut; |
| |
| // Returns a switch item for sync, set to on if |isOn| is YES. |
| - (CollectionViewItem*)syncSwitchItem:(BOOL)isOn; |
| // Returns an item for sync errors other than sync encryption. |
| - (CollectionViewItem*)syncErrorItem; |
| // Returns a switch item for sync everything, set to on if |isOn| is YES. |
| - (CollectionViewItem*)syncEverythingSwitchItem:(BOOL)isOn; |
| // Returns a switch item for the syncable data type |dataType|, set to on if |
| // |IsDataTypePreferred| for that type returns true. |
| - (CollectionViewItem*)switchItemForDataType: |
| (SyncSetupService::SyncableDatatype)dataType; |
| // Returns a switch item for the Autofill wallet import setting. |
| - (CollectionViewItem*)switchItemForAutofillWalletImport; |
| // Returns an item for Encryption. |
| - (CollectionViewItem*)encryptionCellItem; |
| // Returns an item to open a link to manage the synced data. |
| - (CollectionViewItem*)manageSyncedDataItem; |
| |
| // Action method for sync switch. |
| - (void)changeSyncStatusToOn:(UISwitch*)sender; |
| // Action method for the sync error cell. |
| - (void)fixSyncErrorIfPossible; |
| // Action method for the account cells. |
| - (void)startSwitchAccountForIdentity:(ChromeIdentity*)identity |
| postSignInAction:(PostSignInAction)postSigninAction; |
| // Callback for switch account action method. |
| - (void)didSwitchAccountWithSuccess:(BOOL)success; |
| // Action method for the Sync Everything switch. |
| - (void)changeSyncEverythingStatusToOn:(UISwitch*)sender; |
| // Action method for the data type switches. |
| - (void)changeDataTypeSyncStatusToOn:(UISwitch*)sender; |
| // Action method for the Autofill wallet import switch. |
| - (void)autofillWalletImportChanged:(UISwitch*)sender; |
| // Action method for the encryption cell. |
| - (void)showEncryption; |
| |
| // Updates the visual status of the screen (i.e. whether cells are enabled, |
| // whether errors are displayed, ...). |
| - (void)updateCollectionView; |
| // Ensures the Sync error cell is shown when there is an error. |
| - (void)updateSyncError; |
| // Updates the Autofill wallet import cell (i.e. whether it is enabled and on). |
| - (void)updateAutofillWalletImportCell; |
| // Ensures the encryption cell displays an error if needed. |
| - (void)updateEncryptionCell; |
| // Updates the account item so it can reflect the latest state of the identity. |
| - (void)updateAccountItem:(CollectionViewAccountItem*)item |
| withIdentity:(ChromeIdentity*)identity; |
| |
| // Returns whether the Sync Settings screen has an Accounts section, allowing |
| // users to choose to which account they want to sync to. |
| - (BOOL)hasAccountsSection; |
| // Returns whether a sync error cell should be displayed. |
| - (BOOL)shouldDisplaySyncError; |
| // Returns whether the Sync settings should be disabled because of a Sync error. |
| - (BOOL)shouldDisableSettingsOnSyncError; |
| // Returns whether an error should be displayed on the encryption cell. |
| - (BOOL)shouldDisplayEncryptionError; |
| // Returns whether the existing sync error is fixable by a user action. |
| - (BOOL)isSyncErrorFixableByUserAction; |
| // Returns the ID to use to access the l10n string for the given data type. |
| - (int)titleIdForSyncableDataType:(SyncSetupService::SyncableDatatype)datatype; |
| // Returns whether the encryption item should be enabled. |
| - (BOOL)shouldEncryptionItemBeEnabled; |
| // Returns whether the sync everything item should be enabled. |
| - (BOOL)shouldSyncEverythingItemBeEnabled; |
| // Returns whether the data type items should be enabled. |
| - (BOOL)shouldSyncableItemsBeEnabled; |
| // Returns the tag for a data type switch based on its index path. |
| - (NSInteger)tagForIndexPath:(NSIndexPath*)indexPath; |
| // Returns the indexPath for a data type switch based on its tag. |
| - (NSIndexPath*)indexPathForTag:(NSInteger)shiftedTag; |
| |
| // Whether the Autofill wallet import item should be enabled. |
| @property(nonatomic, readonly, getter=isAutofillWalletImportItemEnabled) |
| BOOL autofillWalletImportItemEnabled; |
| |
| // Whether the Autofill wallet import item should be on. |
| @property(nonatomic, assign, getter=isAutofillWalletImportOn) |
| BOOL autofillWalletImportOn; |
| |
| @end |
| |
| @implementation SyncSettingsCollectionViewController |
| |
| #pragma mark Initialization |
| |
| - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState |
| allowSwitchSyncAccount:(BOOL)allowSwitchSyncAccount { |
| DCHECK(browserState); |
| UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init]; |
| self = [super initWithLayout:layout |
| style:CollectionViewControllerStyleDefault]; |
| if (self) { |
| _allowSwitchSyncAccount = allowSwitchSyncAccount; |
| _browserState = browserState; |
| _syncSetupService = |
| SyncSetupServiceFactory::GetForBrowserState(_browserState); |
| self.title = l10n_util::GetNSString(IDS_IOS_SYNC_SETTING_TITLE); |
| syncer::SyncService* syncService = |
| ProfileSyncServiceFactory::GetForBrowserState(_browserState); |
| _syncObserver.reset(new SyncObserverBridge(self, syncService)); |
| _identityManagerObserver.reset(new identity::IdentityManagerObserverBridge( |
| IdentityManagerFactory::GetForBrowserState(_browserState), self)); |
| self.collectionViewAccessibilityIdentifier = kSettingsSyncId; |
| _avatarCache = [[ResizedAvatarCache alloc] init]; |
| _identityServiceObserver.reset( |
| new ChromeIdentityServiceObserverBridge(self)); |
| // TODO(crbug.com/764578): -loadModel should not be called from |
| // initializer. A possible fix is to move this call to -viewDidLoad. |
| [self loadModel]; |
| } |
| return self; |
| } |
| |
| - (void)stopBrowserStateServiceObservers { |
| _syncObserver.reset(); |
| _identityManagerObserver.reset(); |
| _identityServiceObserver.reset(); |
| } |
| |
| - (BOOL)popViewIfSignedOut { |
| if (AuthenticationServiceFactory::GetForBrowserState(_browserState) |
| ->IsAuthenticated()) { |
| return NO; |
| } |
| if (_authenticationOperationInProgress) { |
| // The signed out state might be temporary (e.g. account switch, ...). |
| // Don't pop this view based on intermediary values. |
| return NO; |
| } |
| [self.navigationController popToViewController:self animated:NO]; |
| [base::mac::ObjCCastStrict<SettingsNavigationController>( |
| self.navigationController) popViewControllerOrCloseSettingsAnimated:NO]; |
| return YES; |
| } |
| |
| #pragma mark View lifecycle |
| |
| - (void)viewWillAppear:(BOOL)animated { |
| [super viewWillAppear:animated]; |
| [self updateEncryptionCell]; |
| } |
| |
| #pragma mark SettingsRootCollectionViewController |
| |
| - (void)loadModel { |
| [super loadModel]; |
| CollectionViewModel* model = self.collectionViewModel; |
| |
| // SyncError section. |
| if ([self shouldDisplaySyncError]) { |
| [model addSectionWithIdentifier:SectionIdentifierSyncError]; |
| [model addItem:[self syncErrorItem] |
| toSectionWithIdentifier:SectionIdentifierSyncError]; |
| } |
| |
| // Sync Section. |
| BOOL syncEnabled = _syncSetupService->IsSyncEnabled(); |
| [model addSectionWithIdentifier:SectionIdentifierEnableSync]; |
| [model addItem:[self syncSwitchItem:syncEnabled] |
| toSectionWithIdentifier:SectionIdentifierEnableSync]; |
| |
| // Sync to Section. |
| if ([self hasAccountsSection]) { |
| NSMutableDictionary<NSString*, CollectionViewItem*>* mutableIdentityMap = |
| [[NSMutableDictionary alloc] init]; |
| // Accounts section. Cells enabled if sync is on. |
| [model addSectionWithIdentifier:SectionIdentifierSyncAccounts]; |
| SettingsTextItem* syncToHeader = |
| [[SettingsTextItem alloc] initWithType:ItemTypeHeader]; |
| syncToHeader.text = l10n_util::GetNSString(IDS_IOS_SYNC_TO_TITLE); |
| syncToHeader.textColor = [[MDCPalette greyPalette] tint500]; |
| [model setHeader:syncToHeader |
| forSectionWithIdentifier:SectionIdentifierSyncAccounts]; |
| auto* identity_manager = |
| IdentityManagerFactory::GetForBrowserState(_browserState); |
| |
| for (const AccountInfo& account : |
| identity_manager->GetAccountsWithRefreshTokens()) { |
| ChromeIdentity* identity = ios::GetChromeBrowserProvider() |
| ->GetChromeIdentityService() |
| ->GetIdentityWithGaiaID(account.gaia); |
| CollectionViewItem* accountItem = [self accountItem:identity]; |
| [model addItem:accountItem |
| toSectionWithIdentifier:SectionIdentifierSyncAccounts]; |
| [mutableIdentityMap setObject:accountItem forKey:identity.gaiaID]; |
| } |
| _identityMap = mutableIdentityMap; |
| } |
| |
| // Data Types to sync. Enabled if sync is on. |
| [model addSectionWithIdentifier:SectionIdentifierSyncServices]; |
| SettingsTextItem* syncServicesHeader = |
| [[SettingsTextItem alloc] initWithType:ItemTypeHeader]; |
| syncServicesHeader.text = |
| l10n_util::GetNSString(IDS_IOS_SYNC_DATA_TYPES_TITLE); |
| syncServicesHeader.textColor = [[MDCPalette greyPalette] tint500]; |
| [model setHeader:syncServicesHeader |
| forSectionWithIdentifier:SectionIdentifierSyncServices]; |
| BOOL syncEverythingEnabled = _syncSetupService->IsSyncingAllDataTypes(); |
| [model addItem:[self syncEverythingSwitchItem:syncEverythingEnabled] |
| toSectionWithIdentifier:SectionIdentifierSyncServices]; |
| // Specific Data Types to sync. Enabled if Sync Everything is off. |
| for (int i = 0; i < SyncSetupService::kNumberOfSyncableDatatypes; ++i) { |
| SyncSetupService::SyncableDatatype dataType = |
| static_cast<SyncSetupService::SyncableDatatype>(i); |
| [model addItem:[self switchItemForDataType:dataType] |
| toSectionWithIdentifier:SectionIdentifierSyncServices]; |
| } |
| // Autofill wallet import switch. |
| [model addItem:[self switchItemForAutofillWalletImport] |
| toSectionWithIdentifier:SectionIdentifierSyncServices]; |
| |
| // Encryption section. Enabled if sync is on. |
| [model addSectionWithIdentifier:SectionIdentifierEncryptionAndFooter]; |
| [model addItem:[self encryptionCellItem] |
| toSectionWithIdentifier:SectionIdentifierEncryptionAndFooter]; |
| [model addItem:[self manageSyncedDataItem] |
| toSectionWithIdentifier:SectionIdentifierEncryptionAndFooter]; |
| } |
| |
| #pragma mark - Model items |
| |
| - (CollectionViewItem*)syncSwitchItem:(BOOL)isOn { |
| LegacySyncSwitchItem* syncSwitchItem = [self |
| switchItemWithType:ItemTypeSyncSwitch |
| title:l10n_util::GetNSString(IDS_IOS_SYNC_SETTING_TITLE) |
| subTitle:l10n_util::GetNSString( |
| IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SUBTITLE)]; |
| syncSwitchItem.on = isOn; |
| return syncSwitchItem; |
| } |
| |
| - (CollectionViewItem*)syncErrorItem { |
| DCHECK([self shouldDisplaySyncError]); |
| CollectionViewAccountItem* syncErrorItem = |
| [[CollectionViewAccountItem alloc] initWithType:ItemTypeSyncError]; |
| syncErrorItem.cellStyle = CollectionViewCellStyle::kUIKit; |
| syncErrorItem.text = l10n_util::GetNSString(IDS_IOS_SYNC_ERROR_TITLE); |
| syncErrorItem.image = [UIImage imageNamed:@"settings_error"]; |
| syncErrorItem.detailText = GetSyncErrorMessageForBrowserState(_browserState); |
| return syncErrorItem; |
| } |
| |
| - (CollectionViewItem*)accountItem:(ChromeIdentity*)identity { |
| CollectionViewAccountItem* identityAccountItem = |
| [[CollectionViewAccountItem alloc] initWithType:ItemTypeAccount]; |
| identityAccountItem.cellStyle = CollectionViewCellStyle::kUIKit; |
| [self updateAccountItem:identityAccountItem withIdentity:identity]; |
| |
| identityAccountItem.enabled = _syncSetupService->IsSyncEnabled(); |
| ChromeIdentity* authenticatedIdentity = |
| AuthenticationServiceFactory::GetForBrowserState(_browserState) |
| ->GetAuthenticatedIdentity(); |
| if (identity == authenticatedIdentity) { |
| identityAccountItem.accessoryType = MDCCollectionViewCellAccessoryCheckmark; |
| } |
| return identityAccountItem; |
| } |
| |
| - (CollectionViewItem*)syncEverythingSwitchItem:(BOOL)isOn { |
| LegacySyncSwitchItem* syncSwitchItem = [self |
| switchItemWithType:ItemTypeSyncEverything |
| title:l10n_util::GetNSString(IDS_IOS_SYNC_EVERYTHING_TITLE) |
| subTitle:nil]; |
| syncSwitchItem.on = isOn; |
| syncSwitchItem.enabled = [self shouldSyncEverythingItemBeEnabled]; |
| return syncSwitchItem; |
| } |
| |
| - (CollectionViewItem*)switchItemForDataType: |
| (SyncSetupService::SyncableDatatype)dataType { |
| syncer::ModelType modelType = _syncSetupService->GetModelType(dataType); |
| BOOL isOn = _syncSetupService->IsDataTypePreferred(modelType); |
| |
| LegacySyncSwitchItem* syncDataTypeItem = |
| [self switchItemWithType:ItemTypeSyncableDataType |
| title:l10n_util::GetNSString( |
| [self titleIdForSyncableDataType:dataType]) |
| subTitle:nil]; |
| syncDataTypeItem.dataType = dataType; |
| syncDataTypeItem.on = isOn; |
| syncDataTypeItem.enabled = [self shouldSyncableItemsBeEnabled]; |
| return syncDataTypeItem; |
| } |
| |
| - (CollectionViewItem*)switchItemForAutofillWalletImport { |
| NSString* title = l10n_util::GetNSString( |
| IDS_AUTOFILL_ENABLE_PAYMENTS_INTEGRATION_CHECKBOX_LABEL); |
| LegacySyncSwitchItem* autofillWalletImportItem = |
| [self switchItemWithType:ItemTypeAutofillWalletImport |
| title:title |
| subTitle:nil]; |
| autofillWalletImportItem.on = [self isAutofillWalletImportOn]; |
| autofillWalletImportItem.enabled = [self isAutofillWalletImportItemEnabled]; |
| return autofillWalletImportItem; |
| } |
| |
| - (CollectionViewItem*)encryptionCellItem { |
| TextAndErrorItem* encryptionCellItem = |
| [[TextAndErrorItem alloc] initWithType:ItemTypeEncryption]; |
| encryptionCellItem.text = |
| l10n_util::GetNSString(IDS_IOS_SYNC_ENCRYPTION_TITLE); |
| encryptionCellItem.accessoryType = |
| MDCCollectionViewCellAccessoryDisclosureIndicator; |
| encryptionCellItem.shouldDisplayError = [self shouldDisplayEncryptionError]; |
| encryptionCellItem.enabled = [self shouldEncryptionItemBeEnabled]; |
| return encryptionCellItem; |
| } |
| |
| - (CollectionViewItem*)manageSyncedDataItem { |
| SettingsTextItem* manageSyncedDataItem = |
| [[SettingsTextItem alloc] initWithType:ItemTypeManageSyncedData]; |
| manageSyncedDataItem.text = |
| l10n_util::GetNSString(IDS_IOS_SYNC_RESET_GOOGLE_DASHBOARD_NO_LINK); |
| manageSyncedDataItem.accessibilityTraits |= UIAccessibilityTraitButton; |
| return manageSyncedDataItem; |
| } |
| |
| #pragma mark Item Constructors |
| |
| - (LegacySyncSwitchItem*)switchItemWithType:(NSInteger)type |
| title:(NSString*)title |
| subTitle:(NSString*)detailText { |
| LegacySyncSwitchItem* switchItem = |
| [[LegacySyncSwitchItem alloc] initWithType:type]; |
| switchItem.text = title; |
| switchItem.detailText = detailText; |
| return switchItem; |
| } |
| |
| #pragma mark - UICollectionViewDataSource |
| |
| - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView |
| cellForItemAtIndexPath:(NSIndexPath*)indexPath { |
| UICollectionViewCell* cell = |
| [super collectionView:collectionView cellForItemAtIndexPath:indexPath]; |
| NSInteger itemType = |
| [self.collectionViewModel itemTypeForIndexPath:indexPath]; |
| |
| switch (itemType) { |
| case ItemTypeSyncError: { |
| CollectionViewAccountCell* accountCell = |
| base::mac::ObjCCastStrict<CollectionViewAccountCell>(cell); |
| accountCell.textLabel.textColor = [[MDCPalette redPalette] tint700]; |
| accountCell.detailTextLabel.numberOfLines = 1; |
| break; |
| } |
| case ItemTypeSyncSwitch: { |
| LegacySyncSwitchCell* switchCell = |
| base::mac::ObjCCastStrict<LegacySyncSwitchCell>(cell); |
| [switchCell.switchView addTarget:self |
| action:@selector(changeSyncStatusToOn:) |
| forControlEvents:UIControlEventValueChanged]; |
| break; |
| } |
| case ItemTypeSyncEverything: { |
| LegacySyncSwitchCell* switchCell = |
| base::mac::ObjCCastStrict<LegacySyncSwitchCell>(cell); |
| [switchCell.switchView |
| addTarget:self |
| action:@selector(changeSyncEverythingStatusToOn:) |
| forControlEvents:UIControlEventValueChanged]; |
| break; |
| } |
| case ItemTypeSyncableDataType: { |
| LegacySyncSwitchCell* switchCell = |
| base::mac::ObjCCastStrict<LegacySyncSwitchCell>(cell); |
| [switchCell.switchView addTarget:self |
| action:@selector(changeDataTypeSyncStatusToOn:) |
| forControlEvents:UIControlEventValueChanged]; |
| switchCell.switchView.tag = [self tagForIndexPath:indexPath]; |
| break; |
| } |
| case ItemTypeAutofillWalletImport: { |
| LegacySyncSwitchCell* switchCell = |
| base::mac::ObjCCastStrict<LegacySyncSwitchCell>(cell); |
| [switchCell.switchView addTarget:self |
| action:@selector(autofillWalletImportChanged:) |
| forControlEvents:UIControlEventValueChanged]; |
| break; |
| } |
| default: |
| break; |
| } |
| return cell; |
| } |
| |
| #pragma mark UICollectionViewDelegate |
| |
| - (void)collectionView:(UICollectionView*)collectionView |
| didSelectItemAtIndexPath:(NSIndexPath*)indexPath { |
| [super collectionView:collectionView didSelectItemAtIndexPath:indexPath]; |
| |
| NSInteger itemType = |
| [self.collectionViewModel itemTypeForIndexPath:indexPath]; |
| switch (itemType) { |
| case ItemTypeSyncError: |
| [self fixSyncErrorIfPossible]; |
| break; |
| case ItemTypeAccount: { |
| CollectionViewAccountItem* accountItem = |
| base::mac::ObjCCastStrict<CollectionViewAccountItem>( |
| [self.collectionViewModel itemAtIndexPath:indexPath]); |
| if (!accountItem.accessoryType) { |
| [self startSwitchAccountForIdentity:accountItem.chromeIdentity |
| postSignInAction:POST_SIGNIN_ACTION_NONE]; |
| } |
| break; |
| } |
| case ItemTypeEncryption: |
| [self showEncryption]; |
| break; |
| case ItemTypeManageSyncedData: { |
| GURL learnMoreUrl = google_util::AppendGoogleLocaleParam( |
| GURL(kSyncGoogleDashboardURL), |
| GetApplicationContext()->GetApplicationLocale()); |
| OpenNewTabCommand* command = |
| [OpenNewTabCommand commandWithURLFromChrome:learnMoreUrl]; |
| [self.dispatcher closeSettingsUIAndOpenURL:command]; |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| #pragma mark MDCCollectionViewStylingDelegate |
| |
| - (CGFloat)collectionView:(UICollectionView*)collectionView |
| cellHeightAtIndexPath:(NSIndexPath*)indexPath { |
| CollectionViewItem* item = |
| [self.collectionViewModel itemAtIndexPath:indexPath]; |
| switch (item.type) { |
| case ItemTypeAccount: |
| return MDCCellDefaultTwoLineHeight; |
| case ItemTypeSyncSwitch: |
| case ItemTypeAutofillWalletImport: |
| return [MDCCollectionViewCell |
| cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) |
| forItem:item]; |
| case ItemTypeSyncError: |
| return MDCCellDefaultOneLineWithAvatarHeight; |
| default: |
| return MDCCellDefaultOneLineHeight; |
| } |
| } |
| |
| - (BOOL)collectionView:(UICollectionView*)collectionView |
| hidesInkViewAtIndexPath:(NSIndexPath*)indexPath { |
| NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; |
| switch (type) { |
| case ItemTypeSyncSwitch: |
| case ItemTypeSyncEverything: |
| case ItemTypeSyncableDataType: |
| return YES; |
| default: |
| return NO; |
| } |
| } |
| |
| #pragma mark - Actions |
| |
| - (void)changeSyncStatusToOn:(UISwitch*)sender { |
| if (self.navigationController.topViewController != self) { |
| // Workaround for timing issue when taping on a switch and the error or |
| // encryption cells. See crbug.com/647678. |
| return; |
| } |
| |
| BOOL isOn = sender.isOn; |
| BOOL wasOn = _syncSetupService->IsSyncEnabled(); |
| if (wasOn == isOn) |
| return; |
| |
| base::AutoReset<BOOL> autoReset(&_ignoreSyncStateChanges, YES); |
| _syncSetupService->SetSyncEnabled(isOn); |
| |
| BOOL isNowOn = _syncSetupService->IsSyncEnabled(); |
| if (isNowOn == wasOn) { |
| DLOG(WARNING) << "Call to SetSyncEnabled(" << (isOn ? "YES" : "NO") |
| << ") failed."; |
| // This shouldn't happen, but in case there was an underlying sync problem, |
| // make sure the UI reflects sync's reality. |
| NSIndexPath* indexPath = [self.collectionViewModel |
| indexPathForItemType:ItemTypeSyncSwitch |
| sectionIdentifier:SectionIdentifierEnableSync]; |
| |
| LegacySyncSwitchItem* item = |
| base::mac::ObjCCastStrict<LegacySyncSwitchItem>( |
| [self.collectionViewModel itemAtIndexPath:indexPath]); |
| item.on = isNowOn; |
| } |
| [self updateCollectionView]; |
| } |
| |
| - (void)fixSyncErrorIfPossible { |
| if (![self isSyncErrorFixableByUserAction] || ![self shouldDisplaySyncError]) |
| return; |
| |
| // Unrecoverable errors are special-cased to only do the signing out and back |
| // in from the Sync settings screen (where user interaction can safely be |
| // prevented). |
| if (_syncSetupService->GetSyncServiceState() == |
| SyncSetupService::kSyncServiceUnrecoverableError) { |
| ChromeIdentity* authenticatedIdentity = |
| AuthenticationServiceFactory::GetForBrowserState(_browserState) |
| ->GetAuthenticatedIdentity(); |
| [self startSwitchAccountForIdentity:authenticatedIdentity |
| postSignInAction:POST_SIGNIN_ACTION_START_SYNC]; |
| return; |
| } |
| |
| SyncSetupService::SyncServiceState syncState = |
| GetSyncStateForBrowserState(_browserState); |
| if (ShouldShowSyncSignin(syncState)) { |
| [self.dispatcher |
| showSignin:[[ShowSigninCommand alloc] |
| initWithOperation: |
| AUTHENTICATION_OPERATION_REAUTHENTICATE |
| accessPoint:signin_metrics::AccessPoint:: |
| ACCESS_POINT_UNKNOWN] |
| baseViewController:self]; |
| } else if (ShouldShowSyncSettings(syncState)) { |
| [self.dispatcher showSyncSettingsFromViewController:self]; |
| } else if (ShouldShowSyncPassphraseSettings(syncState)) { |
| [self.dispatcher showSyncPassphraseSettingsFromViewController:self]; |
| } |
| } |
| |
| - (void)startSwitchAccountForIdentity:(ChromeIdentity*)identity |
| postSignInAction:(PostSignInAction)postSignInAction { |
| if (!_syncSetupService->IsSyncEnabled()) |
| return; |
| |
| _authenticationOperationInProgress = YES; |
| [[NSNotificationCenter defaultCenter] |
| postNotificationName:kSwitchAccountWillStartNotification |
| object:self]; |
| [self preventUserInteraction]; |
| DCHECK(!_authenticationFlow); |
| _authenticationFlow = [[AuthenticationFlow alloc] |
| initWithBrowserState:_browserState |
| identity:identity |
| shouldClearData:SHOULD_CLEAR_DATA_USER_CHOICE |
| postSignInAction:postSignInAction |
| presentingViewController:self]; |
| _authenticationFlow.dispatcher = self.dispatcher; |
| |
| __weak SyncSettingsCollectionViewController* weakSelf = self; |
| [_authenticationFlow startSignInWithCompletion:^(BOOL success) { |
| [weakSelf didSwitchAccountWithSuccess:success]; |
| }]; |
| } |
| |
| - (void)didSwitchAccountWithSuccess:(BOOL)success { |
| _authenticationFlow = nil; |
| [self allowUserInteraction]; |
| [[NSNotificationCenter defaultCenter] |
| postNotificationName:kSwitchAccountDidFinishNotification |
| object:self]; |
| _authenticationOperationInProgress = NO; |
| if (![self popViewIfSignedOut]) { |
| // Only reload the view if it wasn't popped. |
| [self reloadData]; |
| } |
| } |
| |
| - (void)changeSyncEverythingStatusToOn:(UISwitch*)sender { |
| if (!_syncSetupService->IsSyncEnabled() || |
| [self shouldDisableSettingsOnSyncError]) |
| return; |
| BOOL isOn = sender.isOn; |
| BOOL wasOn = _syncSetupService->IsSyncingAllDataTypes(); |
| if (wasOn == isOn) |
| return; |
| |
| base::AutoReset<BOOL> autoReset(&_ignoreSyncStateChanges, YES); |
| _syncSetupService->SetSyncingAllDataTypes(isOn); |
| |
| // Base the UI on the actual sync value, not the toggle. |
| BOOL isNowOn = _syncSetupService->IsSyncingAllDataTypes(); |
| if (isNowOn == wasOn) { |
| DLOG(WARNING) << "Call to SetSyncingAllDataTypes(" << (isOn ? "YES" : "NO") |
| << ") failed"; |
| // No change - there was a sync-level problem that didn't allow the change. |
| // This really shouldn't happen, but just in case, make sure the UI reflects |
| // sync's reality. |
| NSIndexPath* indexPath = [self.collectionViewModel |
| indexPathForItemType:ItemTypeSyncEverything |
| sectionIdentifier:SectionIdentifierSyncServices]; |
| LegacySyncSwitchItem* item = |
| base::mac::ObjCCastStrict<LegacySyncSwitchItem>( |
| [self.collectionViewModel itemAtIndexPath:indexPath]); |
| item.on = isNowOn; |
| } |
| [self updateCollectionView]; |
| } |
| |
| - (void)changeDataTypeSyncStatusToOn:(UISwitch*)sender { |
| if (!_syncSetupService->IsSyncEnabled() || |
| _syncSetupService->IsSyncingAllDataTypes() || |
| [self shouldDisableSettingsOnSyncError]) |
| return; |
| |
| BOOL isOn = sender.isOn; |
| |
| LegacySyncSwitchItem* syncSwitchItem = |
| base::mac::ObjCCastStrict<LegacySyncSwitchItem>([self.collectionViewModel |
| itemAtIndexPath:[self indexPathForTag:sender.tag]]); |
| SyncSetupService::SyncableDatatype dataType = |
| (SyncSetupService::SyncableDatatype)syncSwitchItem.dataType; |
| syncer::ModelType modelType = _syncSetupService->GetModelType(dataType); |
| |
| base::AutoReset<BOOL> autoReset(&_ignoreSyncStateChanges, YES); |
| _syncSetupService->SetDataTypeEnabled(modelType, isOn); |
| |
| // Set value of Autofill wallet import accordingly if Autofill Sync changed. |
| if (dataType == SyncSetupService::kSyncAutofill) { |
| [self setAutofillWalletImportOn:isOn]; |
| [self updateCollectionView]; |
| } |
| } |
| |
| - (void)autofillWalletImportChanged:(UISwitch*)sender { |
| if (![self isAutofillWalletImportItemEnabled]) |
| return; |
| |
| [self setAutofillWalletImportOn:sender.isOn]; |
| } |
| |
| - (void)showEncryption { |
| syncer::SyncService* syncService = |
| ProfileSyncServiceFactory::GetForBrowserState(_browserState); |
| if (!syncService->IsEngineInitialized() || |
| !_syncSetupService->IsSyncEnabled() || |
| [self shouldDisableSettingsOnSyncError]) |
| return; |
| |
| UIViewController<SettingsRootViewControlling>* controllerToPush; |
| // If there was a sync error, prompt the user to enter the passphrase. |
| // Otherwise, show the full encryption options. |
| if (syncService->GetUserSettings()->IsPassphraseRequired()) { |
| controllerToPush = [[SyncEncryptionPassphraseTableViewController alloc] |
| initWithBrowserState:_browserState]; |
| } else { |
| controllerToPush = [[SyncEncryptionTableViewController alloc] |
| initWithBrowserState:_browserState]; |
| } |
| controllerToPush.dispatcher = self.dispatcher; |
| [self.navigationController pushViewController:controllerToPush animated:YES]; |
| } |
| |
| #pragma mark Updates |
| |
| - (void)updateCollectionView { |
| __weak SyncSettingsCollectionViewController* weakSelf = self; |
| [self.collectionView performBatchUpdates:^{ |
| [weakSelf updateCollectionViewInternal]; |
| } |
| completion:nil]; |
| } |
| |
| - (void)updateCollectionViewInternal { |
| NSIndexPath* indexPath = [self.collectionViewModel |
| indexPathForItemType:ItemTypeSyncSwitch |
| sectionIdentifier:SectionIdentifierEnableSync]; |
| |
| LegacySyncSwitchItem* syncItem = |
| base::mac::ObjCCastStrict<LegacySyncSwitchItem>( |
| [self.collectionViewModel itemAtIndexPath:indexPath]); |
| syncItem.on = _syncSetupService->IsSyncEnabled(); |
| [self reconfigureCellsForItems:@[ syncItem ]]; |
| |
| // Update Sync Accounts section. |
| if ([self hasAccountsSection]) { |
| NSInteger section = [self.collectionViewModel |
| sectionForSectionIdentifier:SectionIdentifierSyncAccounts]; |
| NSInteger itemsCount = |
| [self.collectionViewModel numberOfItemsInSection:section]; |
| NSMutableArray* accountsToReconfigure = [[NSMutableArray alloc] init]; |
| for (NSInteger item = 0; item < itemsCount; ++item) { |
| NSIndexPath* indexPath = [self.collectionViewModel |
| indexPathForItemType:ItemTypeAccount |
| sectionIdentifier:SectionIdentifierSyncAccounts |
| atIndex:item]; |
| CollectionViewAccountItem* accountItem = |
| base::mac::ObjCCastStrict<CollectionViewAccountItem>( |
| [self.collectionViewModel itemAtIndexPath:indexPath]); |
| accountItem.enabled = _syncSetupService->IsSyncEnabled(); |
| [accountsToReconfigure addObject:accountItem]; |
| } |
| [self reconfigureCellsForItems:accountsToReconfigure]; |
| } |
| |
| // Update Sync Services section. |
| indexPath = [self.collectionViewModel |
| indexPathForItemType:ItemTypeSyncEverything |
| sectionIdentifier:SectionIdentifierSyncServices]; |
| LegacySyncSwitchItem* syncEverythingItem = |
| base::mac::ObjCCastStrict<LegacySyncSwitchItem>( |
| [self.collectionViewModel itemAtIndexPath:indexPath]); |
| syncEverythingItem.on = _syncSetupService->IsSyncingAllDataTypes(); |
| syncEverythingItem.enabled = [self shouldSyncEverythingItemBeEnabled]; |
| [self reconfigureCellsForItems:@[ syncEverythingItem ]]; |
| |
| // Syncable data types cells |
| NSMutableArray* switchsToReconfigure = [[NSMutableArray alloc] init]; |
| for (NSInteger index = 0; |
| index < SyncSetupService::kNumberOfSyncableDatatypes; ++index) { |
| SyncSetupService::SyncableDatatype dataType = |
| static_cast<SyncSetupService::SyncableDatatype>(index); |
| NSIndexPath* indexPath = [self.collectionViewModel |
| indexPathForItemType:ItemTypeSyncableDataType |
| sectionIdentifier:SectionIdentifierSyncServices |
| atIndex:index]; |
| LegacySyncSwitchItem* syncSwitchItem = |
| base::mac::ObjCCastStrict<LegacySyncSwitchItem>( |
| [self.collectionViewModel itemAtIndexPath:indexPath]); |
| DCHECK_EQ(index, syncSwitchItem.dataType); |
| syncer::ModelType modelType = _syncSetupService->GetModelType(dataType); |
| syncSwitchItem.on = _syncSetupService->IsDataTypePreferred(modelType); |
| syncSwitchItem.enabled = [self shouldSyncableItemsBeEnabled]; |
| [switchsToReconfigure addObject:syncSwitchItem]; |
| } |
| [self reconfigureCellsForItems:switchsToReconfigure]; |
| |
| // Update Autofill wallet import cell. |
| [self updateAutofillWalletImportCell]; |
| |
| // Update Encryption cell. |
| [self updateEncryptionCell]; |
| |
| // Add/Remove the Sync Error. This is the only update that can change index |
| // paths. It is done last because self.collectionViewModel isn't aware of |
| // the performBatchUpdates:completion: order of update/remove/delete. |
| [self updateSyncError]; |
| } |
| |
| - (void)updateSyncError { |
| BOOL shouldDisplayError = [self shouldDisplaySyncError]; |
| BOOL isDisplayingError = |
| [self.collectionViewModel hasItemForItemType:ItemTypeSyncError |
| sectionIdentifier:SectionIdentifierSyncError]; |
| if (shouldDisplayError && !isDisplayingError) { |
| [self.collectionViewModel |
| insertSectionWithIdentifier:SectionIdentifierSyncError |
| atIndex:0]; |
| [self.collectionViewModel addItem:[self syncErrorItem] |
| toSectionWithIdentifier:SectionIdentifierSyncError]; |
| NSInteger section = [self.collectionViewModel |
| sectionForSectionIdentifier:SectionIdentifierSyncError]; |
| [self.collectionView insertSections:[NSIndexSet indexSetWithIndex:section]]; |
| } else if (!shouldDisplayError && isDisplayingError) { |
| NSInteger section = [self.collectionViewModel |
| sectionForSectionIdentifier:SectionIdentifierSyncError]; |
| [self.collectionViewModel |
| removeSectionWithIdentifier:SectionIdentifierSyncError]; |
| [self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:section]]; |
| } |
| } |
| |
| - (void)updateAutofillWalletImportCell { |
| // Force turn on Autofill wallet import if syncing everthing. |
| BOOL isSyncingEverything = _syncSetupService->IsSyncingAllDataTypes(); |
| if (isSyncingEverything) { |
| [self setAutofillWalletImportOn:isSyncingEverything]; |
| } |
| |
| NSIndexPath* indexPath = [self.collectionViewModel |
| indexPathForItemType:ItemTypeAutofillWalletImport |
| sectionIdentifier:SectionIdentifierSyncServices]; |
| LegacySyncSwitchItem* syncSwitchItem = |
| base::mac::ObjCCastStrict<LegacySyncSwitchItem>( |
| [self.collectionViewModel itemAtIndexPath:indexPath]); |
| syncSwitchItem.on = [self isAutofillWalletImportOn]; |
| syncSwitchItem.enabled = [self isAutofillWalletImportItemEnabled]; |
| [self reconfigureCellsForItems:@[ syncSwitchItem ]]; |
| } |
| |
| - (void)updateEncryptionCell { |
| BOOL shouldDisplayEncryptionError = [self shouldDisplayEncryptionError]; |
| NSIndexPath* indexPath = [self.collectionViewModel |
| indexPathForItemType:ItemTypeEncryption |
| sectionIdentifier:SectionIdentifierEncryptionAndFooter]; |
| TextAndErrorItem* item = base::mac::ObjCCastStrict<TextAndErrorItem>( |
| [self.collectionViewModel itemAtIndexPath:indexPath]); |
| item.shouldDisplayError = shouldDisplayEncryptionError; |
| item.enabled = [self shouldEncryptionItemBeEnabled]; |
| [self reconfigureCellsForItems:@[ item ]]; |
| } |
| |
| - (void)updateAccountItem:(CollectionViewAccountItem*)item |
| withIdentity:(ChromeIdentity*)identity { |
| item.image = [_avatarCache resizedAvatarForIdentity:identity]; |
| item.text = identity.userEmail; |
| item.chromeIdentity = identity; |
| } |
| |
| #pragma mark Helpers |
| |
| - (BOOL)hasAccountsSection { |
| return _allowSwitchSyncAccount && |
| IdentityManagerFactory::GetForBrowserState(_browserState) |
| ->GetAccountsWithRefreshTokens() |
| .size() > 1; |
| } |
| |
| - (BOOL)shouldDisplaySyncError { |
| SyncSetupService::SyncServiceState state = |
| _syncSetupService->GetSyncServiceState(); |
| return state != SyncSetupService::kNoSyncServiceError; |
| } |
| |
| - (BOOL)shouldDisableSettingsOnSyncError { |
| SyncSetupService::SyncServiceState state = |
| _syncSetupService->GetSyncServiceState(); |
| return state != SyncSetupService::kNoSyncServiceError && |
| state != SyncSetupService::kSyncServiceNeedsPassphrase; |
| } |
| |
| - (BOOL)shouldDisplayEncryptionError { |
| return _syncSetupService->GetSyncServiceState() == |
| SyncSetupService::kSyncServiceNeedsPassphrase; |
| } |
| |
| - (BOOL)isSyncErrorFixableByUserAction { |
| SyncSetupService::SyncServiceState state = |
| _syncSetupService->GetSyncServiceState(); |
| return state == SyncSetupService::kSyncServiceNeedsPassphrase || |
| state == SyncSetupService::kSyncServiceSignInNeedsUpdate || |
| state == SyncSetupService::kSyncServiceUnrecoverableError; |
| } |
| |
| - (int)titleIdForSyncableDataType:(SyncSetupService::SyncableDatatype)datatype { |
| switch (datatype) { |
| case SyncSetupService::kSyncBookmarks: |
| return IDS_SYNC_DATATYPE_BOOKMARKS; |
| case SyncSetupService::kSyncOmniboxHistory: |
| return IDS_SYNC_DATATYPE_TYPED_URLS; |
| case SyncSetupService::kSyncPasswords: |
| return IDS_SYNC_DATATYPE_PASSWORDS; |
| case SyncSetupService::kSyncOpenTabs: |
| return IDS_SYNC_DATATYPE_TABS; |
| case SyncSetupService::kSyncAutofill: |
| return IDS_SYNC_DATATYPE_AUTOFILL; |
| case SyncSetupService::kSyncPreferences: |
| return IDS_SYNC_DATATYPE_PREFERENCES; |
| case SyncSetupService::kSyncReadingList: |
| return IDS_SYNC_DATATYPE_READING_LIST; |
| case SyncSetupService::kNumberOfSyncableDatatypes: |
| NOTREACHED(); |
| } |
| return 0; |
| } |
| |
| - (BOOL)shouldEncryptionItemBeEnabled { |
| syncer::SyncService* syncService = |
| ProfileSyncServiceFactory::GetForBrowserState(_browserState); |
| return (syncService->IsEngineInitialized() && |
| _syncSetupService->IsSyncEnabled() && |
| ![self shouldDisableSettingsOnSyncError]); |
| } |
| |
| - (BOOL)shouldSyncEverythingItemBeEnabled { |
| return (_syncSetupService->IsSyncEnabled() && |
| ![self shouldDisableSettingsOnSyncError]); |
| } |
| |
| - (BOOL)shouldSyncableItemsBeEnabled { |
| return (!_syncSetupService->IsSyncingAllDataTypes() && |
| _syncSetupService->IsSyncEnabled() && |
| ![self shouldDisableSettingsOnSyncError]); |
| } |
| |
| - (BOOL)isAutofillWalletImportItemEnabled { |
| syncer::ModelType autofillModelType = |
| _syncSetupService->GetModelType(SyncSetupService::kSyncAutofill); |
| BOOL isAutofillOn = _syncSetupService->IsDataTypePreferred(autofillModelType); |
| return isAutofillOn && [self shouldSyncableItemsBeEnabled]; |
| } |
| |
| - (BOOL)isAutofillWalletImportOn { |
| return autofill::prefs::IsPaymentsIntegrationEnabled( |
| _browserState->GetPrefs()); |
| } |
| |
| - (void)setAutofillWalletImportOn:(BOOL)on { |
| autofill::prefs::SetPaymentsIntegrationEnabled(_browserState->GetPrefs(), on); |
| } |
| |
| - (NSInteger)tagForIndexPath:(NSIndexPath*)indexPath { |
| DCHECK(indexPath.section == |
| [self.collectionViewModel |
| sectionForSectionIdentifier:SectionIdentifierSyncServices]); |
| NSInteger index = |
| [self.collectionViewModel indexInItemTypeForIndexPath:indexPath]; |
| return index + kTagShift; |
| } |
| |
| - (NSIndexPath*)indexPathForTag:(NSInteger)shiftedTag { |
| NSInteger unshiftedTag = shiftedTag - kTagShift; |
| return [self.collectionViewModel |
| indexPathForItemType:ItemTypeSyncableDataType |
| sectionIdentifier:SectionIdentifierSyncServices |
| atIndex:unshiftedTag]; |
| } |
| |
| #pragma mark SyncObserverModelBridge |
| |
| - (void)onSyncStateChanged { |
| if (_ignoreSyncStateChanges || _authenticationOperationInProgress) { |
| return; |
| } |
| [self updateCollectionView]; |
| } |
| |
| #pragma mark identity::IdentityManagerObserverBridgeDelegate |
| |
| - (void)onEndBatchOfRefreshTokenStateChanges { |
| if (_authenticationOperationInProgress) { |
| return; |
| } |
| if (![self popViewIfSignedOut]) { |
| // Only reload the view if it wasn't popped. |
| [self reloadData]; |
| } |
| } |
| |
| #pragma mark SettingsControllerProtocol callbacks |
| |
| - (void)settingsWillBeDismissed { |
| [self stopBrowserStateServiceObservers]; |
| [_authenticationFlow cancelAndDismiss]; |
| } |
| |
| #pragma mark - ChromeIdentityServiceObserver |
| |
| - (void)profileUpdate:(ChromeIdentity*)identity { |
| CollectionViewAccountItem* item = |
| base::mac::ObjCCastStrict<CollectionViewAccountItem>( |
| [_identityMap objectForKey:identity.gaiaID]); |
| if (!item) { |
| // Ignoring unknown identity. |
| return; |
| } |
| [self updateAccountItem:item withIdentity:identity]; |
| [self reconfigureCellsForItems:@[ item ]]; |
| } |
| |
| - (void)chromeIdentityServiceWillBeDestroyed { |
| _identityServiceObserver.reset(); |
| } |
| |
| @end |