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

Unified Diff: ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm

Issue 2589583003: Upstream Chrome on iOS source code [7/11]. (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 side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm
diff --git a/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm b/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..a3e52cb4dc4ac163a39a33167702f669760f78e6
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm
@@ -0,0 +1,677 @@
+// 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/accounts_collection_view_controller.h"
+
+#import "base/ios/weak_nsobject.h"
+#import "base/mac/foundation_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/metrics/user_metrics.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/ios/browser/oauth2_token_service_observer_bridge.h"
+#include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/signin/account_tracker_service_factory.h"
+#import "ios/chrome/browser/signin/authentication_service.h"
+#import "ios/chrome/browser/signin/authentication_service_factory.h"
+#include "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
+#include "ios/chrome/browser/signin/oauth2_token_service_factory.h"
+#include "ios/chrome/browser/signin/signin_manager_factory.h"
+#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
+#include "ios/chrome/browser/sync/sync_observer_bridge.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/alert_coordinator/alert_coordinator.h"
+#import "ios/chrome/browser/ui/authentication/signin_interaction_controller.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/cells/collection_view_text_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/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
+#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
+#import "ios/chrome/browser/ui/commands/open_url_command.h"
+#import "ios/chrome/browser/ui/icons/chrome_icon.h"
+#import "ios/chrome/browser/ui/settings/cells/account_control_item.h"
+#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
+#import "ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/utils/resized_avatar_cache.h"
+#import "ios/chrome/browser/ui/sync/sync_util.h"
+#include "ios/chrome/grit/ios_chromium_strings.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#include "ios/public/provider/chrome/browser/images/branded_image_provider.h"
+#import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
+#import "ios/public/provider/chrome/browser/signin/chrome_identity_browser_opener.h"
+#import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
+#import "net/base/mac/url_conversions.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+NSString* const kSettingsAccountsId = @"kSettingsAccountsId";
+NSString* const kSettingsHeaderId = @"kSettingsHeaderId";
+NSString* const kSettingsAccountsSignoutCellId =
+ @"kSettingsAccountsSignoutCellId";
+NSString* const kSettingsAccountsSyncCellId = @"kSettingsAccountsSyncCellId";
+
+namespace {
+
+typedef NS_ENUM(NSInteger, SectionIdentifier) {
+ SectionIdentifierAccounts = kSectionIdentifierEnumZero,
+ SectionIdentifierSync,
+ SectionIdentifierSignOut,
+};
+
+typedef NS_ENUM(NSInteger, ItemType) {
+ ItemTypeAccount = kItemTypeEnumZero,
+ ItemTypeAddAccount,
+ ItemTypeSync,
+ ItemTypeGoogleActivityControls,
+ ItemTypeSignOut,
+ ItemTypeHeader,
+};
+
+} // namespace
+
+@interface AccountsCollectionViewController ()<
+ ChromeIdentityServiceObserver,
+ ChromeIdentityBrowserOpener,
+ OAuth2TokenServiceObserverBridgeDelegate,
+ SyncObserverModelBridge> {
+ ios::ChromeBrowserState* _browserState; // weak
+ BOOL _closeSettingsOnAddAccount;
+ std::unique_ptr<SyncObserverBridge> _syncObserver;
+ std::unique_ptr<OAuth2TokenServiceObserverBridge> _tokenServiceObserver;
+ base::scoped_nsobject<SigninInteractionController>
+ _signinInteractionController;
+ // Modal alert for sign out.
+ base::scoped_nsobject<AlertCoordinator> _alertCoordinator;
+ // Whether an authentication operation is in progress (e.g switch accounts,
+ // sign out).
+ BOOL _authenticationOperationInProgress;
+ // Whether the view controller is currently being dismissed and new dismiss
+ // requests should be ignored.
+ BOOL _isBeingDismissed;
+ base::WeakNSObject<UIViewController> _settingsDetails;
+ base::scoped_nsobject<ResizedAvatarCache> _avatarCache;
+ std::unique_ptr<ChromeIdentityServiceObserverBridge> _identityServiceObserver;
+
+ // Enable lookup of item corresponding to a given identity GAIA ID string.
+ base::scoped_nsobject<NSDictionary<NSString*, CollectionViewItem*>>
+ _identityMap;
+}
+
+// Stops observing browser state services. This is required during the shutdown
+// phase to avoid observing services for a browser state that is being killed.
+- (void)stopBrowserStateServiceObservers;
+
+@end
+
+@implementation AccountsCollectionViewController
+
+- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
+ closeSettingsOnAddAccount:(BOOL)closeSettingsOnAddAccount {
+ DCHECK(browserState);
+ DCHECK(!browserState->IsOffTheRecord());
+ self = [super initWithStyle:CollectionViewControllerStyleAppBar];
+ if (self) {
+ _browserState = browserState;
+ _closeSettingsOnAddAccount = closeSettingsOnAddAccount;
+ browser_sync::ProfileSyncService* syncService =
+ IOSChromeProfileSyncServiceFactory::GetForBrowserState(_browserState);
+ _syncObserver.reset(new SyncObserverBridge(self, syncService));
+ _tokenServiceObserver.reset(new OAuth2TokenServiceObserverBridge(
+ OAuth2TokenServiceFactory::GetForBrowserState(_browserState), self));
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(willStartSwitchAccount)
+ name:kSwitchAccountWillStartNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(didFinishSwitchAccount)
+ name:kSwitchAccountDidFinishNotification
+ object:nil];
+ self.collectionViewAccessibilityIdentifier = kSettingsAccountsId;
+ _avatarCache.reset([[ResizedAvatarCache alloc] init]);
+ _identityServiceObserver.reset(
+ new ChromeIdentityServiceObserverBridge(self));
+ [self loadModel];
+ }
+
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)stopBrowserStateServiceObservers {
+ _tokenServiceObserver.reset();
+ _syncObserver.reset();
+}
+
+#pragma mark - SettingsControllerProtocol
+
+- (void)settingsWillBeDismissed {
+ [_signinInteractionController cancel];
+ [_alertCoordinator stop];
+ [self stopBrowserStateServiceObservers];
+}
+
+#pragma mark - SettingsRootCollectionViewController
+
+- (void)reloadData {
+ if (![self authService]->IsAuthenticated()) {
+ // This accounts collection view will be popped or dismissed when the user
+ // is signed out. Avoid reloading it in that case as that would lead to an
+ // empty collection view.
+ return;
+ }
+ [super reloadData];
+}
+
+- (void)loadModel {
+ // Update the title with the name with the currently signed-in account.
+ ChromeIdentity* authenticatedIdentity =
+ [self authService]->GetAuthenticatedIdentity();
+ NSString* title = nil;
+ if (authenticatedIdentity) {
+ title = [authenticatedIdentity userFullName];
+ if (!title) {
+ // TODO(crbug.com/656994): Figure how to handle unnamed account.
+ title = @"Unnamed account";
+ }
+ }
+ self.title = title;
+
+ [super loadModel];
+
+ if (![self authService]->IsAuthenticated())
+ return;
+
+ CollectionViewModel* model = self.collectionViewModel;
+
+ NSMutableDictionary<NSString*, CollectionViewItem*>* mutableIdentityMap =
+ [[[NSMutableDictionary alloc] init] autorelease];
+
+ // Account cells.
+ ProfileOAuth2TokenService* oauth2_service =
+ OAuth2TokenServiceFactory::GetForBrowserState(_browserState);
+ AccountTrackerService* accountTracker =
+ ios::AccountTrackerServiceFactory::GetForBrowserState(_browserState);
+ [model addSectionWithIdentifier:SectionIdentifierAccounts];
+ [model setHeader:[self header]
+ forSectionWithIdentifier:SectionIdentifierAccounts];
+ for (const std::string& account_id : oauth2_service->GetAccounts()) {
+ AccountInfo account = accountTracker->GetAccountInfo(account_id);
+ ChromeIdentity* identity = ios::GetChromeBrowserProvider()
+ ->GetChromeIdentityService()
+ ->GetIdentityWithGaiaID(account.gaia);
+ CollectionViewItem* item = [self accountItem:identity];
+ [model addItem:item toSectionWithIdentifier:SectionIdentifierAccounts];
+
+ [mutableIdentityMap setObject:item forKey:identity.gaiaID];
+ }
+ _identityMap.reset([mutableIdentityMap retain]);
+
+ [model addItem:[self addAccountItem]
+ toSectionWithIdentifier:SectionIdentifierAccounts];
+
+ // Sync and Google Activity section.
+ [model addSectionWithIdentifier:SectionIdentifierSync];
+ [model addItem:[self syncItem] toSectionWithIdentifier:SectionIdentifierSync];
+ [model addItem:[self googleActivityControlsItem]
+ toSectionWithIdentifier:SectionIdentifierSync];
+
+ // Sign out section.
+ [model addSectionWithIdentifier:SectionIdentifierSignOut];
+ [model addItem:[self signOutItem]
+ toSectionWithIdentifier:SectionIdentifierSignOut];
+}
+
+#pragma mark - Model objects
+
+- (CollectionViewItem*)header {
+ CollectionViewTextItem* header = [
+ [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader] autorelease];
+ header.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_DESCRIPTION);
+ header.accessibilityIdentifier = kSettingsHeaderId;
+ return header;
+}
+
+- (CollectionViewItem*)accountItem:(ChromeIdentity*)identity {
+ CollectionViewAccountItem* item = [[[CollectionViewAccountItem alloc]
+ initWithType:ItemTypeAccount] autorelease];
+ [self updateAccountItem:item withIdentity:identity];
+ return item;
+}
+
+- (void)updateAccountItem:(CollectionViewAccountItem*)item
+ withIdentity:(ChromeIdentity*)identity {
+ item.image = [_avatarCache resizedAvatarForIdentity:identity];
+ item.text = identity.userEmail;
+ item.chromeIdentity = identity;
+ item.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
+}
+
+- (CollectionViewItem*)addAccountItem {
+ CollectionViewAccountItem* item = [[[CollectionViewAccountItem alloc]
+ initWithType:ItemTypeAddAccount] autorelease];
+ item.text =
+ l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_ADD_ACCOUNT_BUTTON);
+ item.image = [UIImage imageNamed:@"settings_accounts_add_account"];
+ return item;
+}
+
+- (CollectionViewItem*)syncItem {
+ AccountControlItem* item =
+ [[[AccountControlItem alloc] initWithType:ItemTypeSync] autorelease];
+ item.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_TITLE);
+ item.accessibilityIdentifier = kSettingsAccountsSyncCellId;
+ [self updateSyncItem:item];
+ item.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
+ return item;
+}
+
+- (void)updateSyncItem:(AccountControlItem*)syncItem {
+ SyncSetupService* syncSetupService =
+ SyncSetupServiceFactory::GetForBrowserState(_browserState);
+ if (!syncSetupService->HasFinishedInitialSetup()) {
+ syncItem.image = [UIImage imageNamed:@"settings_sync"];
+ syncItem.detailText =
+ l10n_util::GetNSString(IDS_IOS_SYNC_SETUP_IN_PROGRESS);
+ syncItem.shouldDisplayError = NO;
+ return;
+ }
+
+ ChromeIdentity* identity = [self authService]->GetAuthenticatedIdentity();
+ bool hasSyncError = !ios_internal::sync::IsTransientSyncError(
+ syncSetupService->GetSyncServiceState());
+ bool hasMDMError = [self authService]->HasCachedMDMErrorForIdentity(identity);
+ if (hasSyncError || hasMDMError) {
+ syncItem.image = [UIImage imageNamed:@"settings_error"];
+ syncItem.detailText =
+ ios_internal::sync::GetSyncErrorDescriptionForBrowserState(
+ _browserState);
+ syncItem.shouldDisplayError = YES;
+ } else {
+ syncItem.image = [UIImage imageNamed:@"settings_sync"];
+ syncItem.detailText =
+ syncSetupService->IsSyncEnabled()
+ ? l10n_util::GetNSStringF(
+ IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SYNCING,
+ base::SysNSStringToUTF16([identity userEmail]))
+ : l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_IS_OFF);
+ syncItem.shouldDisplayError = NO;
+ }
+}
+
+- (CollectionViewItem*)googleActivityControlsItem {
+ AccountControlItem* item = [[[AccountControlItem alloc]
+ initWithType:ItemTypeGoogleActivityControls] autorelease];
+ item.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_GOOGLE_TITLE);
+ item.detailText =
+ l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_GOOGLE_DESCRIPTION);
+ item.image = ios::GetChromeBrowserProvider()
+ ->GetBrandedImageProvider()
+ ->GetAccountsListActivityControlsImage();
+ item.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
+ return item;
+}
+
+- (CollectionViewItem*)signOutItem {
+ CollectionViewTextItem* item = [[[CollectionViewTextItem alloc]
+ initWithType:ItemTypeSignOut] autorelease];
+ item.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SIGNOUT);
+ item.accessibilityTraits |= UIAccessibilityTraitButton;
+ item.accessibilityIdentifier = kSettingsAccountsSignoutCellId;
+ return item;
+}
+
+#pragma mark - UICollectionViewDelegate
+
+- (void)collectionView:(UICollectionView*)collectionView
+ didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
+ [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
+
+ NSInteger itemType =
+ [self.collectionViewModel itemTypeForIndexPath:indexPath];
+
+ switch (itemType) {
+ case ItemTypeAccount: {
+ CollectionViewAccountItem* item =
+ base::mac::ObjCCastStrict<CollectionViewAccountItem>(
+ [self.collectionViewModel itemAtIndexPath:indexPath]);
+ DCHECK(item.chromeIdentity);
+ [self showAccountDetails:item.chromeIdentity];
+ break;
+ }
+ case ItemTypeAddAccount:
+ [self showAddAccount];
+ break;
+ case ItemTypeSync:
+ [self showSyncSettings];
+ break;
+ case ItemTypeGoogleActivityControls:
+ [self showGoogleActivitySettings];
+ break;
+ case ItemTypeSignOut:
+ [self showDisconnect];
+ break;
+ default:
+ break;
+ }
+}
+
+#pragma mark - UICollectionViewDataSource
+
+- (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView
+ viewForSupplementaryElementOfKind:(NSString*)kind
+ atIndexPath:(NSIndexPath*)indexPath {
+ UICollectionReusableView* view = [super collectionView:collectionView
+ viewForSupplementaryElementOfKind:kind
+ atIndexPath:indexPath];
+ MDCCollectionViewTextCell* textCell =
+ base::mac::ObjCCast<MDCCollectionViewTextCell>(view);
+ if (textCell) {
+ textCell.textLabel.textColor = [[MDCPalette greyPalette] tint500];
+ }
+ return view;
+}
+
+#pragma mark - MDCCollectionViewStylingDelegate
+
+- (CGFloat)collectionView:(UICollectionView*)collectionView
+ cellHeightAtIndexPath:(NSIndexPath*)indexPath {
+ CollectionViewItem* item =
+ [self.collectionViewModel itemAtIndexPath:indexPath];
+ if (item.type == ItemTypeGoogleActivityControls ||
+ item.type == ItemTypeSync) {
+ return [MDCCollectionViewCell
+ cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
+ forItem:item];
+ } else if (item.type == ItemTypeSignOut) {
+ return MDCCellDefaultOneLineHeight;
+ }
+ return MDCCellDefaultTwoLineHeight;
+}
+
+#pragma mark - SyncObserverModelBridge
+
+- (void)onSyncStateChanged {
+ if (![self authService]->IsAuthenticated()) {
+ // Ignore sync state changed notification if signed out.
+ return;
+ }
+
+ NSIndexPath* index =
+ [self.collectionViewModel indexPathForItemType:ItemTypeSync
+ sectionIdentifier:SectionIdentifierSync];
+
+ CollectionViewModel* model = self.collectionViewModel;
+ if ([model numberOfSections] > index.section &&
+ [model numberOfItemsInSection:index.section] > index.row) {
+ AccountControlItem* item = base::mac::ObjCCastStrict<AccountControlItem>(
+ [model itemAtIndexPath:index]);
+ [self updateSyncItem:item];
+ [self.collectionView reloadItemsAtIndexPaths:@[ index ]];
+ }
+}
+
+#pragma mark - OAuth2TokenServiceObserverBridgeDelegate
+
+- (void)onEndBatchChanges {
+ [self reloadData];
+ [self popViewIfSignedOut];
+ if (![self authService]->IsAuthenticated() && _settingsDetails) {
+ [_settingsDetails dismissViewControllerAnimated:YES completion:nil];
+ _settingsDetails.reset();
+ }
+}
+
+#pragma mark - Sync and Activity Controls
+
+- (void)showSyncSettings {
+ if ([_alertCoordinator isVisible])
+ return;
+
+ if ([self authService]->ShowMDMErrorDialogForIdentity(
+ [self authService]->GetAuthenticatedIdentity())) {
+ // If there is an MDM error for the synced identity, show it instead.
+ return;
+ }
+
+ base::scoped_nsobject<UIViewController> controllerToPush(
+ [[SyncSettingsCollectionViewController alloc]
+ initWithBrowserState:_browserState
+ allowSwitchSyncAccount:YES]);
+ [self.navigationController pushViewController:controllerToPush animated:YES];
+}
+
+- (void)showGoogleActivitySettings {
+ if ([_alertCoordinator isVisible])
+ return;
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_AccountSettings_GoogleActivityControlsClicked"));
+ base::scoped_nsobject<UINavigationController> settingsDetails(
+ ios::GetChromeBrowserProvider()
+ ->GetChromeIdentityService()
+ ->NewWebAndAppSettingDetails(
+ [self authService]->GetAuthenticatedIdentity(), self));
+ UIImage* closeIcon = [ChromeIcon closeIcon];
+ SEL action = @selector(closeGoogleActivitySettings:);
+ [settingsDetails.get().topViewController navigationItem].leftBarButtonItem =
+ [ChromeIcon templateBarButtonItemWithImage:closeIcon
+ target:self
+ action:action];
+ [self presentViewController:settingsDetails animated:YES completion:nil];
+
+ // Keep a weak reference on the settings details, to be able to dismiss it
+ // when the primary account is removed.
+ _settingsDetails.reset(settingsDetails);
+}
+
+- (void)closeGoogleActivitySettings:(id)sender {
+ DCHECK(_settingsDetails);
+ [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+#pragma mark - Authentication operations
+
+- (void)showAddAccount {
+ if ([_alertCoordinator isVisible])
+ return;
+ if (_signinInteractionController) {
+ // Ignore this user action if there is already an add account operation
+ // in-progress.
+ return;
+ }
+ _signinInteractionController.reset([[SigninInteractionController alloc]
+ initWithBrowserState:_browserState
+ presentingViewController:self.navigationController
+ isPresentedOnSettings:YES
+ signInAccessPoint:signin_metrics::AccessPoint::
+ ACCESS_POINT_SETTINGS]);
+
+ // |_authenticationOperationInProgress| is reset when the signin interaction
+ // controller is dismissed.
+ _authenticationOperationInProgress = YES;
+ base::WeakNSObject<AccountsCollectionViewController> weakSelf(self);
+ [_signinInteractionController addAccountWithCompletion:^(BOOL success) {
+ [weakSelf handleDidAddAccount:success];
+ }
+ viewController:self];
+}
+
+- (void)handleDidAddAccount:(BOOL)success {
+ _signinInteractionController.reset();
+ [self handleAuthenticationOperationDidFinish];
+ if (success && _closeSettingsOnAddAccount) {
+ base::scoped_nsobject<GenericChromeCommand> closeSettingsCommand(
+ [[GenericChromeCommand alloc] initWithTag:IDC_CLOSE_SETTINGS]);
+ [self chromeExecuteCommand:closeSettingsCommand];
+ }
+}
+
+- (void)showAccountDetails:(ChromeIdentity*)identity {
+ if ([_alertCoordinator isVisible])
+ return;
+ base::scoped_nsobject<UIViewController> accountDetails(
+ ios::GetChromeBrowserProvider()
+ ->GetChromeIdentityService()
+ ->NewAccountDetails(identity, self));
+ if (!accountDetails) {
+ // Failed to create a new account details. Ignored.
+ return;
+ }
+ [self presentViewController:accountDetails animated:YES completion:nil];
+
+ // Keep a weak reference on the account details, to be able to dismiss it
+ // when the primary account is removed.
+ _settingsDetails.reset(accountDetails);
+}
+
+- (void)showDisconnect {
+ if (_authenticationOperationInProgress || [_alertCoordinator isVisible] ||
+ self != [self.navigationController topViewController]) {
+ // An action is already in progress, ignore user's request.
+ return;
+ }
+
+ NSString* title;
+ NSString* message;
+ NSString* continueButtonTitle;
+ if ([self authService]->IsAuthenticatedIdentityManaged()) {
+ std::string hosted_domain =
+ ios::SigninManagerFactory::GetForBrowserState(_browserState)
+ ->GetAuthenticatedAccountInfo()
+ .hosted_domain;
+ title = l10n_util::GetNSString(IDS_IOS_MANAGED_DISCONNECT_DIALOG_TITLE);
+ message = l10n_util::GetNSStringF(IDS_IOS_MANAGED_DISCONNECT_DIALOG_INFO,
+ base::UTF8ToUTF16(hosted_domain));
+ continueButtonTitle =
+ l10n_util::GetNSString(IDS_IOS_MANAGED_DISCONNECT_DIALOG_ACCEPT);
+ } else {
+ title = l10n_util::GetNSString(IDS_IOS_DISCONNECT_DIALOG_TITLE);
+ message = l10n_util::GetNSString(IDS_IOS_DISCONNECT_DIALOG_INFO_MOBILE);
+ continueButtonTitle = l10n_util::GetNSString(
+ IDS_IOS_DISCONNECT_DIALOG_CONTINUE_BUTTON_MOBILE);
+ }
+ _alertCoordinator.reset([[AlertCoordinator alloc]
+ initWithBaseViewController:self
+ title:title
+ message:message]);
+
+ [_alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
+ action:nil
+ style:UIAlertActionStyleCancel];
+ base::WeakNSObject<AccountsCollectionViewController> weakSelf(self);
+ [_alertCoordinator addItemWithTitle:continueButtonTitle
+ action:^{
+ [weakSelf handleDisconnect];
+ }
+ style:UIAlertActionStyleDefault];
+ [_alertCoordinator start];
+}
+
+- (void)handleDisconnect {
+ AuthenticationService* authService = [self authService];
+ if (authService->IsAuthenticated()) {
+ _authenticationOperationInProgress = YES;
+ [self preventUserInteraction];
+ authService->SignOut(signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS, ^{
+ [self allowUserInteraction];
+ _authenticationOperationInProgress = NO;
+ [base::mac::ObjCCastStrict<SettingsNavigationController>(
+ self.navigationController)
+ popViewControllerOrCloseSettingsAnimated:YES];
+ });
+ }
+}
+
+// Sets |_authenticationOperationInProgress| to NO and pops this accounts
+// collection view controller if the user is signed out.
+- (void)handleAuthenticationOperationDidFinish {
+ DCHECK(_authenticationOperationInProgress);
+ _authenticationOperationInProgress = NO;
+ [self popViewIfSignedOut];
+}
+
+- (void)popViewIfSignedOut {
+ if ([self authService]->IsAuthenticated()) {
+ return;
+ }
+ if (_authenticationOperationInProgress) {
+ // The signed out state might be temporary (e.g. account switch, ...).
+ // Don't pop this view based on intermediary values.
+ return;
+ }
+ [self dismissSelfAnimated:NO];
+}
+
+- (void)dismissSelfAnimated:(BOOL)animated {
+ if (_isBeingDismissed) {
+ return;
+ }
+ _isBeingDismissed = YES;
+ [_signinInteractionController cancelAndDismiss];
+ [_alertCoordinator stop];
+ [self.navigationController popToViewController:self animated:NO];
+ [base::mac::ObjCCastStrict<SettingsNavigationController>(
+ self.navigationController)
+ popViewControllerOrCloseSettingsAnimated:animated];
+}
+
+#pragma mark - Access to authentication service
+
+- (AuthenticationService*)authService {
+ return AuthenticationServiceFactory::GetForBrowserState(_browserState);
+}
+
+#pragma mark - Switch accounts notifications
+
+- (void)willStartSwitchAccount {
+ _authenticationOperationInProgress = YES;
+}
+
+- (void)didFinishSwitchAccount {
+ [self handleAuthenticationOperationDidFinish];
+}
+
+#pragma mark - ChromeIdentityBrowserOpener
+
+- (void)openURL:(NSURL*)url
+ view:(UIView*)view
+ viewController:(UIViewController*)viewController {
+ base::scoped_nsobject<OpenUrlCommand> command(
+ [[OpenUrlCommand alloc] initWithURLFromChrome:net::GURLWithNSURL(url)]);
+ [command setTag:IDC_CLOSE_SETTINGS_AND_OPEN_URL];
+ [self chromeExecuteCommand:command];
+}
+
+#pragma mark - ChromeIdentityServiceObserver
+
+- (void)onProfileUpdate:(ChromeIdentity*)identity {
+ CollectionViewAccountItem* item =
+ base::mac::ObjCCastStrict<CollectionViewAccountItem>(
+ [_identityMap objectForKey:identity.gaiaID]);
+ [self updateAccountItem:item withIdentity:identity];
+ NSIndexPath* indexPath =
+ [self.collectionViewModel indexPathForItem:item
+ inSectionWithIdentifier:SectionIdentifierAccounts];
+ [self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]];
+}
+
+- (void)onChromeIdentityServiceWillBeDestroyed {
+ _identityServiceObserver.reset();
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698