| Index: ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
|
| diff --git a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2628a0bdea123a3f3df4b743bc17300813464967
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
|
| @@ -0,0 +1,1096 @@
|
| +// 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/settings_collection_view_controller.h"
|
| +
|
| +#include <memory>
|
| +
|
| +#import "base/ios/weak_nsobject.h"
|
| +#import "base/mac/foundation_util.h"
|
| +#import "base/mac/scoped_nsobject.h"
|
| +#include "base/metrics/user_metrics.h"
|
| +#include "base/scoped_observer.h"
|
| +#include "base/strings/sys_string_conversions.h"
|
| +#include "components/autofill/core/common/autofill_pref_names.h"
|
| +#include "components/browser_sync/profile_sync_service.h"
|
| +#include "components/keyed_service/core/service_access_type.h"
|
| +#include "components/password_manager/core/browser/password_bubble_experiment.h"
|
| +#include "components/password_manager/core/browser/password_store.h"
|
| +#include "components/password_manager/core/common/password_manager_pref_names.h"
|
| +#include "components/prefs/pref_change_registrar.h"
|
| +#include "components/prefs/pref_service.h"
|
| +#include "components/search_engines/util.h"
|
| +#include "components/signin/core/browser/signin_manager.h"
|
| +#include "components/signin/core/common/signin_pref_names.h"
|
| +#include "components/strings/grit/components_strings.h"
|
| +#include "ios/chrome/browser/application_context.h"
|
| +#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
|
| +#include "ios/chrome/browser/browser_state/chrome_browser_state_removal_controller.h"
|
| +#include "ios/chrome/browser/experimental_flags.h"
|
| +#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
|
| +#include "ios/chrome/browser/pref_names.h"
|
| +#import "ios/chrome/browser/prefs/pref_observer_bridge.h"
|
| +#include "ios/chrome/browser/search_engines/template_url_service_factory.h"
|
| +#import "ios/chrome/browser/signin/authentication_service.h"
|
| +#include "ios/chrome/browser/signin/authentication_service_factory.h"
|
| +#include "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.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/authentication/signin_interaction_controller.h"
|
| +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_account_item.h"
|
| +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h"
|
| +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_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/settings/about_chrome_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/accounts_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/autofill_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/bandwidth_management_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/cells/account_signin_item.h"
|
| +#import "ios/chrome/browser/ui/settings/content_settings_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/privacy_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/search_engine_settings_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/settings_utils.h"
|
| +#import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h"
|
| +#import "ios/chrome/browser/ui/settings/voicesearch_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/sync/sync_util.h"
|
| +#import "ios/chrome/browser/ui/uikit_ui_util.h"
|
| +#include "ios/chrome/browser/voice/speech_input_locale_config.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"
|
| +#import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
|
| +#include "ios/public/provider/chrome/browser/signin/signin_resources_provider.h"
|
| +#include "ios/public/provider/chrome/browser/voice/voice_search_prefs.h"
|
| +#include "ui/base/l10n/l10n_util_mac.h"
|
| +
|
| +NSString* const kSettingsCollectionViewId = @"kSettingsCollectionViewId";
|
| +NSString* const kSettingsSignInCellId = @"kSettingsSignInCellId";
|
| +NSString* const kSettingsAccountCellId = @"kSettingsAccountCellId";
|
| +NSString* const kSettingsSearchEngineCellId = @"Search Engine";
|
| +NSString* const kSettingsVoiceSearchCellId = @"Voice Search Settings";
|
| +
|
| +@interface SettingsCollectionViewController (NotificationBridgeDelegate)
|
| +// Notifies this controller that the sign in state has changed.
|
| +- (void)onSignInStateChanged;
|
| +@end
|
| +
|
| +namespace {
|
| +
|
| +const CGFloat kAccountProfilePhotoDimension = 40.0f;
|
| +
|
| +typedef NS_ENUM(NSInteger, SectionIdentifier) {
|
| + SectionIdentifierSignIn = kSectionIdentifierEnumZero,
|
| + SectionIdentifierBasics,
|
| + SectionIdentifierAdvanced,
|
| + SectionIdentifierInfo,
|
| + SectionIdentifierDebug,
|
| +};
|
| +
|
| +typedef NS_ENUM(NSInteger, ItemType) {
|
| + ItemTypeSignInButton = kItemTypeEnumZero,
|
| + ItemTypeAccount,
|
| + ItemTypeHeader,
|
| + ItemTypeSearchEngine,
|
| + ItemTypeSavedPasswords,
|
| + ItemTypeAutofill,
|
| + ItemTypeNativeApps,
|
| + ItemTypeVoiceSearch,
|
| + ItemTypePrivacy,
|
| + ItemTypeContentSettings,
|
| + ItemTypeBandwidth,
|
| + ItemTypeAboutChrome,
|
| + ItemTypeMemoryDebugging,
|
| + ItemTypeViewSource,
|
| + ItemTypeLogJavascript,
|
| + ItemTypeShowAutofillTypePredictions,
|
| + ItemTypeCellCatalog,
|
| +};
|
| +
|
| +#if CHROMIUM_BUILD && !defined(NDEBUG)
|
| +NSString* kDevViewSourceKey = @"DevViewSource";
|
| +NSString* kLogJavascriptKey = @"LogJavascript";
|
| +NSString* kShowAutofillTypePredictionsKey = @"ShowAutofillTypePredictions";
|
| +#endif // CHROMIUM_BUILD && !defined(NDEBUG)
|
| +
|
| +#pragma mark - SigninObserverBridge Class
|
| +
|
| +class SigninObserverBridge : public SigninManagerBase::Observer {
|
| + public:
|
| + SigninObserverBridge(ios::ChromeBrowserState* browserState,
|
| + SettingsCollectionViewController* owner);
|
| + ~SigninObserverBridge() override{};
|
| +
|
| + // SigninManagerBase::Observer implementation:
|
| + void GoogleSigninSucceeded(const std::string& account_id,
|
| + const std::string& username,
|
| + const std::string& password) override;
|
| + void GoogleSignedOut(const std::string& account_id,
|
| + const std::string& username) override;
|
| +
|
| + private:
|
| + base::WeakNSObject<SettingsCollectionViewController> owner_;
|
| + ScopedObserver<SigninManager, SigninObserverBridge> observer_;
|
| +};
|
| +
|
| +SigninObserverBridge::SigninObserverBridge(
|
| + ios::ChromeBrowserState* browserState,
|
| + SettingsCollectionViewController* owner)
|
| + : owner_(owner), observer_(this) {
|
| + DCHECK(owner_);
|
| + SigninManager* sigin_manager =
|
| + ios::SigninManagerFactory::GetForBrowserState(browserState);
|
| + if (!sigin_manager)
|
| + return;
|
| + observer_.Add(sigin_manager);
|
| +}
|
| +
|
| +void SigninObserverBridge::GoogleSigninSucceeded(const std::string& account_id,
|
| + const std::string& username,
|
| + const std::string& password) {
|
| + [owner_ onSignInStateChanged];
|
| +}
|
| +
|
| +void SigninObserverBridge::GoogleSignedOut(const std::string& account_id,
|
| + const std::string& username) {
|
| + [owner_ onSignInStateChanged];
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +#pragma mark - SettingsCollectionViewController
|
| +
|
| +@interface SettingsCollectionViewController ()<SettingsControllerProtocol,
|
| + SyncObserverModelBridge,
|
| + ChromeIdentityServiceObserver,
|
| + BooleanObserver,
|
| + PrefObserverDelegate> {
|
| + // The main browser state that hold the settings. Never off the record.
|
| + ios::ChromeBrowserState* _mainBrowserState; // weak
|
| +
|
| + // The current browser state. It is either |_mainBrowserState|
|
| + // or |_mainBrowserState->GetOffTheRecordChromeBrowserState()|.
|
| + ios::ChromeBrowserState* _currentBrowserState; // weak
|
| + std::unique_ptr<SigninObserverBridge> _notificationBridge;
|
| + std::unique_ptr<SyncObserverBridge> _syncObserverBridge;
|
| + base::scoped_nsobject<SigninInteractionController>
|
| + _signinInteractionController;
|
| + // Whether the impression of the Signin button has already been recorded.
|
| + BOOL _hasRecordedSigninImpression;
|
| + // PrefBackedBoolean for ShowMemoryDebugTools switch.
|
| + base::scoped_nsobject<PrefBackedBoolean> _showMemoryDebugToolsEnabled;
|
| + // The item related to the switch for the show suggestions setting.
|
| + base::scoped_nsobject<CollectionViewSwitchItem> _showMemoryDebugToolsItem;
|
| +
|
| + // Cached resized profile image.
|
| + base::scoped_nsobject<UIImage> _resizedImage;
|
| + base::WeakNSObject<UIImage> _oldImage;
|
| +
|
| + // Identity object and observer used for Account Item refresh.
|
| + base::scoped_nsobject<ChromeIdentity> _identity;
|
| + std::unique_ptr<ChromeIdentityServiceObserverBridge> _identityServiceObserver;
|
| +
|
| + // PrefMember for voice locale code.
|
| + StringPrefMember _voiceLocaleCode;
|
| + // Pref observer to track changes to prefs.
|
| + std::unique_ptr<PrefObserverBridge> _prefObserverBridge;
|
| + // TODO(crbug.com/662435): Refactor PrefObserverBridge so it owns the
|
| + // PrefChangeRegistrar.
|
| + // Registrar for pref changes notifications.
|
| + PrefChangeRegistrar _prefChangeRegistrar;
|
| +
|
| + // Updatable Items.
|
| + base::scoped_nsobject<CollectionViewDetailItem> _voiceSearchDetailItem;
|
| + base::scoped_nsobject<CollectionViewDetailItem> _defaultSearchEngineItem;
|
| + base::scoped_nsobject<CollectionViewDetailItem> _savePasswordsDetailItem;
|
| + base::scoped_nsobject<CollectionViewDetailItem> _autoFillDetailItem;
|
| +}
|
| +
|
| +// Stops observing browser state services. This is required during the shutdown
|
| +// phase to avoid observing services for a profile that is being killed.
|
| +- (void)stopBrowserStateServiceObservers;
|
| +
|
| +@end
|
| +
|
| +@implementation SettingsCollectionViewController
|
| +
|
| +#pragma mark Initialization
|
| +
|
| +- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)mainBrowserState
|
| + currentBrowserState:
|
| + (ios::ChromeBrowserState*)currentBrowserState {
|
| + DCHECK(mainBrowserState);
|
| + DCHECK(currentBrowserState);
|
| + DCHECK_EQ(mainBrowserState,
|
| + currentBrowserState->GetOriginalChromeBrowserState());
|
| + self = [super initWithStyle:CollectionViewControllerStyleAppBar];
|
| + if (self) {
|
| + _mainBrowserState = mainBrowserState;
|
| + _currentBrowserState = currentBrowserState;
|
| + self.title = l10n_util::GetNSStringWithFixup(IDS_IOS_SETTINGS_TITLE);
|
| + self.collectionViewAccessibilityIdentifier = kSettingsCollectionViewId;
|
| + _notificationBridge.reset(
|
| + new SigninObserverBridge(_mainBrowserState, self));
|
| + syncer::SyncService* syncService =
|
| + IOSChromeProfileSyncServiceFactory::GetForBrowserState(
|
| + _mainBrowserState);
|
| + _syncObserverBridge.reset(new SyncObserverBridge(self, syncService));
|
| +
|
| + _showMemoryDebugToolsEnabled.reset([[PrefBackedBoolean alloc]
|
| + initWithPrefService:GetApplicationContext()->GetLocalState()
|
| + prefName:prefs::kShowMemoryDebuggingTools]);
|
| + [_showMemoryDebugToolsEnabled setObserver:self];
|
| +
|
| + AuthenticationService* authService =
|
| + AuthenticationServiceFactory::GetForBrowserState(_mainBrowserState);
|
| + _identity.reset([authService->GetAuthenticatedIdentity() retain]);
|
| + _identityServiceObserver.reset(
|
| + new ChromeIdentityServiceObserverBridge(self));
|
| +
|
| + PrefService* prefService = _mainBrowserState->GetPrefs();
|
| +
|
| + _voiceLocaleCode.Init(prefs::kVoiceSearchLocale, prefService);
|
| +
|
| + _prefChangeRegistrar.Init(prefService);
|
| + _prefObserverBridge.reset(new PrefObserverBridge(self));
|
| + // Register to observe any changes on Perf backed values displayed by the
|
| + // screen.
|
| + _prefObserverBridge->ObserveChangesForPreference(prefs::kVoiceSearchLocale,
|
| + &_prefChangeRegistrar);
|
| + _prefObserverBridge->ObserveChangesForPreference(
|
| + password_manager::prefs::kPasswordManagerSavingEnabled,
|
| + &_prefChangeRegistrar);
|
| + _prefObserverBridge->ObserveChangesForPreference(
|
| + autofill::prefs::kAutofillEnabled, &_prefChangeRegistrar);
|
| +
|
| + [self loadModel];
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (void)dealloc {
|
| + [self stopBrowserStateServiceObservers];
|
| + [super dealloc];
|
| +}
|
| +
|
| +- (void)stopBrowserStateServiceObservers {
|
| + _syncObserverBridge.reset();
|
| + _notificationBridge.reset();
|
| + _identityServiceObserver.reset();
|
| + [_showMemoryDebugToolsEnabled setObserver:nil];
|
| +}
|
| +
|
| +- (SigninInteractionController*)signinInteractionController {
|
| + return _signinInteractionController;
|
| +}
|
| +
|
| +#pragma mark View lifecycle
|
| +
|
| +// TODO(crbug.com/661915): Refactor TemplateURLObserver and re-implement this so
|
| +// it observes the default search engine name instead of reloading on
|
| +// ViewWillAppear.
|
| +- (void)viewWillAppear:(BOOL)animated {
|
| + [super viewWillAppear:animated];
|
| + [self updateSearchCell];
|
| +}
|
| +
|
| +#pragma mark SettingsRootCollectionViewController
|
| +
|
| +- (void)loadModel {
|
| + [super loadModel];
|
| +
|
| + CollectionViewModel* model = self.collectionViewModel;
|
| +
|
| + // Sign in/Account section
|
| + [model addSectionWithIdentifier:SectionIdentifierSignIn];
|
| + AuthenticationService* authService =
|
| + AuthenticationServiceFactory::GetForBrowserState(_mainBrowserState);
|
| + if (!authService->IsAuthenticated()) {
|
| + if (!_hasRecordedSigninImpression) {
|
| + // Once the Settings are open, this button impression will at most be
|
| + // recorded once until they are closed.
|
| + base::RecordAction(
|
| + base::UserMetricsAction("Signin_Impression_FromSettings"));
|
| + _hasRecordedSigninImpression = YES;
|
| + }
|
| + [model addItem:[self signInTextItem]
|
| + toSectionWithIdentifier:SectionIdentifierSignIn];
|
| + } else {
|
| + [model addItem:[self accountCellItem]
|
| + toSectionWithIdentifier:SectionIdentifierSignIn];
|
| + }
|
| +
|
| + // Basics section
|
| + [model addSectionWithIdentifier:SectionIdentifierBasics];
|
| + CollectionViewTextItem* basicsHeader = [
|
| + [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader] autorelease];
|
| + basicsHeader.text = l10n_util::GetNSString(IDS_IOS_OPTIONS_GENERAL_TAB_LABEL);
|
| + [model setHeader:basicsHeader
|
| + forSectionWithIdentifier:SectionIdentifierBasics];
|
| + [model addItem:[self searchEngineDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierBasics];
|
| + [model addItem:[self savePasswordsDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierBasics];
|
| + [model addItem:[self autoFillDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierBasics];
|
| + [model addItem:[self nativeAppsDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierBasics];
|
| +
|
| + // Advanced Section
|
| + [model addSectionWithIdentifier:SectionIdentifierAdvanced];
|
| + CollectionViewTextItem* advancedHeader = [
|
| + [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader] autorelease];
|
| + advancedHeader.text =
|
| + l10n_util::GetNSString(IDS_IOS_OPTIONS_ADVANCED_TAB_LABEL);
|
| + [model setHeader:advancedHeader
|
| + forSectionWithIdentifier:SectionIdentifierAdvanced];
|
| + [model addItem:[self voiceSearchDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierAdvanced];
|
| + [model addItem:[self privacyDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierAdvanced];
|
| + [model addItem:[self contentSettingsDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierAdvanced];
|
| + [model addItem:[self bandwidthManagementDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierAdvanced];
|
| +
|
| + // Info Section
|
| + [model addSectionWithIdentifier:SectionIdentifierInfo];
|
| + [model addItem:[self aboutChromeDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierInfo];
|
| +
|
| + // Debug Section
|
| + if ([self hasDebugSection]) {
|
| + [model addSectionWithIdentifier:SectionIdentifierDebug];
|
| + CollectionViewTextItem* debugHeader = [[[CollectionViewTextItem alloc]
|
| + initWithType:ItemTypeHeader] autorelease];
|
| + debugHeader.text = @"Debug";
|
| + [model setHeader:debugHeader
|
| + forSectionWithIdentifier:SectionIdentifierDebug];
|
| + }
|
| +
|
| + if (experimental_flags::IsMemoryDebuggingEnabled()) {
|
| + _showMemoryDebugToolsItem.reset([[self showMemoryDebugSwitchItem] retain]);
|
| + [model addItem:_showMemoryDebugToolsItem
|
| + toSectionWithIdentifier:SectionIdentifierDebug];
|
| + }
|
| +
|
| +#if CHROMIUM_BUILD && !defined(NDEBUG)
|
| + [model addItem:[self viewSourceSwitchItem]
|
| + toSectionWithIdentifier:SectionIdentifierDebug];
|
| + [model addItem:[self logJavascriptConsoleSwitchItem]
|
| + toSectionWithIdentifier:SectionIdentifierDebug];
|
| + [model addItem:[self showAutofillTypePredictionsSwitchItem]
|
| + toSectionWithIdentifier:SectionIdentifierDebug];
|
| + [model addItem:[self materialCatalogDetailItem]
|
| + toSectionWithIdentifier:SectionIdentifierDebug];
|
| +#endif // CHROMIUM_BUILD && !defined(NDEBUG)
|
| +}
|
| +
|
| +#pragma mark - Model Items
|
| +
|
| +- (CollectionViewItem*)signInTextItem {
|
| + AccountSignInItem* signInTextItem = [[[AccountSignInItem alloc]
|
| + initWithType:ItemTypeSignInButton] autorelease];
|
| + signInTextItem.accessibilityIdentifier = kSettingsSignInCellId;
|
| + UIImage* image = CircularImageFromImage(ios::GetChromeBrowserProvider()
|
| + ->GetSigninResourcesProvider()
|
| + ->GetDefaultAvatar(),
|
| + kAccountProfilePhotoDimension);
|
| + signInTextItem.image = image;
|
| +
|
| + return signInTextItem;
|
| +}
|
| +
|
| +- (CollectionViewItem*)accountCellItem {
|
| + CollectionViewAccountItem* identityAccountItem =
|
| + [[[CollectionViewAccountItem alloc] initWithType:ItemTypeAccount]
|
| + autorelease];
|
| + identityAccountItem.accessoryType =
|
| + MDCCollectionViewCellAccessoryDisclosureIndicator;
|
| + identityAccountItem.accessibilityIdentifier = kSettingsAccountCellId;
|
| + [self updateIdentityAccountItem:identityAccountItem];
|
| + return identityAccountItem;
|
| +}
|
| +
|
| +- (CollectionViewItem*)searchEngineDetailItem {
|
| + NSString* defaultSearchEngineName =
|
| + base::SysUTF16ToNSString(GetDefaultSearchEngineName(
|
| + ios::TemplateURLServiceFactory::GetForBrowserState(
|
| + _mainBrowserState)));
|
| +
|
| + _defaultSearchEngineItem.reset(
|
| + [[self detailItemWithType:ItemTypeSearchEngine
|
| + text:l10n_util::GetNSString(
|
| + IDS_IOS_SEARCH_ENGINE_SETTING_TITLE)
|
| + detailText:defaultSearchEngineName] retain]);
|
| + _defaultSearchEngineItem.get().accessibilityIdentifier =
|
| + kSettingsSearchEngineCellId;
|
| + return _defaultSearchEngineItem;
|
| +}
|
| +
|
| +- (CollectionViewItem*)savePasswordsDetailItem {
|
| + BOOL savePasswordsEnabled = _mainBrowserState->GetPrefs()->GetBoolean(
|
| + password_manager::prefs::kPasswordManagerSavingEnabled);
|
| + NSString* passwordsDetail = savePasswordsEnabled
|
| + ? l10n_util::GetNSString(IDS_IOS_SETTING_ON)
|
| + : l10n_util::GetNSString(IDS_IOS_SETTING_OFF);
|
| + int titleId = IDS_IOS_SAVE_PASSWORDS;
|
| + syncer::SyncService* syncService =
|
| + IOSChromeProfileSyncServiceFactory::GetForBrowserState(_mainBrowserState);
|
| + if (password_bubble_experiment::IsSmartLockBrandingEnabled(syncService)) {
|
| + titleId = IDS_IOS_SAVE_PASSWORDS_SMART_LOCK;
|
| + }
|
| +
|
| + _savePasswordsDetailItem.reset(
|
| + [[self detailItemWithType:ItemTypeSavedPasswords
|
| + text:l10n_util::GetNSString(titleId)
|
| + detailText:passwordsDetail] retain]);
|
| +
|
| + return _savePasswordsDetailItem;
|
| +}
|
| +
|
| +- (CollectionViewItem*)autoFillDetailItem {
|
| + BOOL autofillEnabled = _mainBrowserState->GetPrefs()->GetBoolean(
|
| + autofill::prefs::kAutofillEnabled);
|
| + NSString* autofillDetail = autofillEnabled
|
| + ? l10n_util::GetNSString(IDS_IOS_SETTING_ON)
|
| + : l10n_util::GetNSString(IDS_IOS_SETTING_OFF);
|
| + _autoFillDetailItem.reset(
|
| + [[self detailItemWithType:ItemTypeAutofill
|
| + text:l10n_util::GetNSString(IDS_IOS_AUTOFILL)
|
| + detailText:autofillDetail] retain]);
|
| +
|
| + return _autoFillDetailItem;
|
| +}
|
| +
|
| +- (CollectionViewItem*)nativeAppsDetailItem {
|
| + return [self
|
| + detailItemWithType:ItemTypeNativeApps
|
| + text:l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_SM_SETTINGS)
|
| + detailText:nil];
|
| +}
|
| +
|
| +- (CollectionViewItem*)voiceSearchDetailItem {
|
| + voice::SpeechInputLocaleConfig* localeConfig =
|
| + voice::SpeechInputLocaleConfig::GetInstance();
|
| + voice::SpeechInputLocale locale =
|
| + _voiceLocaleCode.GetValue().length()
|
| + ? localeConfig->GetLocaleForCode(_voiceLocaleCode.GetValue())
|
| + : localeConfig->GetDefaultLocale();
|
| + NSString* languageName = base::SysUTF16ToNSString(locale.display_name);
|
| + _voiceSearchDetailItem.reset(
|
| + [[self detailItemWithType:ItemTypeVoiceSearch
|
| + text:l10n_util::GetNSString(
|
| + IDS_IOS_VOICE_SEARCH_SETTING_TITLE)
|
| + detailText:languageName] retain]);
|
| + _voiceSearchDetailItem.get().accessibilityIdentifier =
|
| + kSettingsVoiceSearchCellId;
|
| + return _voiceSearchDetailItem;
|
| +}
|
| +
|
| +- (CollectionViewItem*)privacyDetailItem {
|
| + return
|
| + [self detailItemWithType:ItemTypePrivacy
|
| + text:l10n_util::GetNSString(
|
| + IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY)
|
| + detailText:nil];
|
| +}
|
| +
|
| +- (CollectionViewItem*)contentSettingsDetailItem {
|
| + return [self
|
| + detailItemWithType:ItemTypeContentSettings
|
| + text:l10n_util::GetNSString(IDS_IOS_CONTENT_SETTINGS_TITLE)
|
| + detailText:nil];
|
| +}
|
| +
|
| +- (CollectionViewItem*)bandwidthManagementDetailItem {
|
| + return [self detailItemWithType:ItemTypeBandwidth
|
| + text:l10n_util::GetNSString(
|
| + IDS_IOS_BANDWIDTH_MANAGEMENT_SETTINGS)
|
| + detailText:nil];
|
| +}
|
| +
|
| +- (CollectionViewItem*)aboutChromeDetailItem {
|
| + return [self detailItemWithType:ItemTypeAboutChrome
|
| + text:l10n_util::GetNSString(IDS_IOS_PRODUCT_NAME)
|
| + detailText:nil];
|
| +}
|
| +
|
| +- (CollectionViewSwitchItem*)showMemoryDebugSwitchItem {
|
| + CollectionViewSwitchItem* showMemoryDebugSwitchItem =
|
| + [self switchItemWithType:ItemTypeMemoryDebugging
|
| + title:@"Show memory debug tools"
|
| + withDefaultsKey:nil];
|
| + showMemoryDebugSwitchItem.on = [_showMemoryDebugToolsEnabled value];
|
| +
|
| + return showMemoryDebugSwitchItem;
|
| +}
|
| +#if CHROMIUM_BUILD && !defined(NDEBUG)
|
| +
|
| +- (CollectionViewSwitchItem*)viewSourceSwitchItem {
|
| + return [self switchItemWithType:ItemTypeViewSource
|
| + title:@"View source menu"
|
| + withDefaultsKey:kDevViewSourceKey];
|
| +}
|
| +
|
| +- (CollectionViewSwitchItem*)logJavascriptConsoleSwitchItem {
|
| + return [self switchItemWithType:ItemTypeLogJavascript
|
| + title:@"Log JS"
|
| + withDefaultsKey:kLogJavascriptKey];
|
| +}
|
| +
|
| +- (CollectionViewSwitchItem*)showAutofillTypePredictionsSwitchItem {
|
| + return [self switchItemWithType:ItemTypeShowAutofillTypePredictions
|
| + title:@"Show Autofill type predictions"
|
| + withDefaultsKey:kShowAutofillTypePredictionsKey];
|
| +}
|
| +
|
| +- (CollectionViewDetailItem*)materialCatalogDetailItem {
|
| + return [self detailItemWithType:ItemTypeCellCatalog
|
| + text:@"Cell Catalog"
|
| + detailText:nil];
|
| +}
|
| +#endif // CHROMIUM_BUILD && !defined(NDEBUG)
|
| +
|
| +#pragma mark Item Updaters
|
| +
|
| +- (void)updateSearchCell {
|
| + NSString* defaultSearchEngineName =
|
| + base::SysUTF16ToNSString(GetDefaultSearchEngineName(
|
| + ios::TemplateURLServiceFactory::GetForBrowserState(
|
| + _mainBrowserState)));
|
| +
|
| + _defaultSearchEngineItem.get().detailText = defaultSearchEngineName;
|
| + [self reconfigureCellsForItems:@[ _defaultSearchEngineItem ]
|
| + inSectionWithIdentifier:SectionIdentifierBasics];
|
| +}
|
| +
|
| +#pragma mark Item Constructors
|
| +
|
| +- (CollectionViewDetailItem*)detailItemWithType:(NSInteger)type
|
| + text:(NSString*)text
|
| + detailText:(NSString*)detailText {
|
| + CollectionViewDetailItem* detailItem =
|
| + [[[CollectionViewDetailItem alloc] initWithType:type] autorelease];
|
| + detailItem.text = text;
|
| + detailItem.detailText = detailText;
|
| + detailItem.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
|
| + detailItem.accessibilityTraits |= UIAccessibilityTraitButton;
|
| +
|
| + return detailItem;
|
| +}
|
| +
|
| +- (CollectionViewSwitchItem*)switchItemWithType:(NSInteger)type
|
| + title:(NSString*)title
|
| + withDefaultsKey:(NSString*)key {
|
| + CollectionViewSwitchItem* switchItem =
|
| + [[[CollectionViewSwitchItem alloc] initWithType:type] autorelease];
|
| + switchItem.text = title;
|
| + if (key) {
|
| + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
| + switchItem.on = [defaults boolForKey:key];
|
| + }
|
| +
|
| + 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];
|
| +
|
| + if ([cell isKindOfClass:[CollectionViewDetailCell class]]) {
|
| + CollectionViewDetailCell* detailCell =
|
| + base::mac::ObjCCastStrict<CollectionViewDetailCell>(cell);
|
| + if (itemType == ItemTypeSavedPasswords) {
|
| + scoped_refptr<password_manager::PasswordStore> passwordStore =
|
| + IOSChromePasswordStoreFactory::GetForBrowserState(
|
| + _mainBrowserState, ServiceAccessType::EXPLICIT_ACCESS);
|
| + if (!passwordStore) {
|
| + // The password store factory returns a NULL password store if something
|
| + // goes wrong during the password store initialization. Disable the save
|
| + // passwords cell in this case.
|
| + LOG(ERROR) << "Save passwords cell was disabled as the password store"
|
| + " cannot be created.";
|
| + [detailCell setUserInteractionEnabled:NO];
|
| + detailCell.textLabel.textColor = [[MDCPalette greyPalette] tint500];
|
| + detailCell.detailTextLabel.textColor =
|
| + [[MDCPalette greyPalette] tint400];
|
| + }
|
| + } else {
|
| + [detailCell setUserInteractionEnabled:YES];
|
| + detailCell.textLabel.textColor = [[MDCPalette greyPalette] tint900];
|
| + detailCell.detailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
|
| + }
|
| + }
|
| +
|
| + switch (itemType) {
|
| + case ItemTypeMemoryDebugging: {
|
| + CollectionViewSwitchCell* switchCell =
|
| + base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell);
|
| + [switchCell.switchView addTarget:self
|
| + action:@selector(memorySwitchToggled:)
|
| + forControlEvents:UIControlEventValueChanged];
|
| + break;
|
| + }
|
| + case ItemTypeViewSource: {
|
| + CollectionViewSwitchCell* switchCell =
|
| + base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell);
|
| + [switchCell.switchView addTarget:self
|
| + action:@selector(viewSourceSwitchToggled:)
|
| + forControlEvents:UIControlEventValueChanged];
|
| + break;
|
| + }
|
| + case ItemTypeLogJavascript: {
|
| + CollectionViewSwitchCell* switchCell =
|
| + base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell);
|
| + [switchCell.switchView addTarget:self
|
| + action:@selector(logJSSwitchToggled:)
|
| + forControlEvents:UIControlEventValueChanged];
|
| + break;
|
| + }
|
| + case ItemTypeShowAutofillTypePredictions: {
|
| + CollectionViewSwitchCell* switchCell =
|
| + base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell);
|
| + [switchCell.switchView addTarget:self
|
| + action:@selector(showAutoFillSwitchToggled:)
|
| + forControlEvents:UIControlEventValueChanged];
|
| + break;
|
| + }
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return cell;
|
| +}
|
| +
|
| +- (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 UICollectionViewDelegate
|
| +
|
| +- (void)collectionView:(UICollectionView*)collectionView
|
| + didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
|
| + [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
|
| +
|
| + id object = [self.collectionViewModel itemAtIndexPath:indexPath];
|
| + if ([object respondsToSelector:@selector(isEnabled)] &&
|
| + ![object performSelector:@selector(isEnabled)]) {
|
| + // Don't perform any action if the cell isn't enabled.
|
| + return;
|
| + }
|
| +
|
| + NSInteger itemType =
|
| + [self.collectionViewModel itemTypeForIndexPath:indexPath];
|
| +
|
| + base::scoped_nsobject<UIViewController> controller;
|
| +
|
| + switch (itemType) {
|
| + case ItemTypeSignInButton:
|
| + [self showSignIn];
|
| + break;
|
| + case ItemTypeAccount:
|
| + controller.reset([[AccountsCollectionViewController alloc]
|
| + initWithBrowserState:_mainBrowserState
|
| + closeSettingsOnAddAccount:NO]);
|
| + break;
|
| + case ItemTypeSearchEngine:
|
| + controller.reset([[SearchEngineSettingsCollectionViewController alloc]
|
| + initWithBrowserState:_mainBrowserState]);
|
| + break;
|
| + case ItemTypeSavedPasswords: {
|
| + controller.reset([[SavePasswordsCollectionViewController alloc]
|
| + initWithBrowserState:_mainBrowserState]);
|
| + break;
|
| + }
|
| + case ItemTypeAutofill:
|
| + controller.reset([[AutofillCollectionViewController alloc]
|
| + initWithBrowserState:_mainBrowserState]);
|
| + break;
|
| + case ItemTypeNativeApps:
|
| + controller.reset([[NativeAppsCollectionViewController alloc]
|
| + initWithURLRequestContextGetter:_currentBrowserState
|
| + ->GetRequestContext()]);
|
| + break;
|
| + case ItemTypeVoiceSearch:
|
| + controller.reset([[VoicesearchCollectionViewController alloc]
|
| + initWithPrefs:_mainBrowserState->GetPrefs()]);
|
| + break;
|
| + case ItemTypePrivacy:
|
| + controller.reset([[PrivacyCollectionViewController alloc]
|
| + initWithBrowserState:_mainBrowserState]);
|
| + break;
|
| + case ItemTypeContentSettings:
|
| + controller.reset([[ContentSettingsCollectionViewController alloc]
|
| + initWithBrowserState:_mainBrowserState]);
|
| + break;
|
| + case ItemTypeBandwidth:
|
| + controller.reset([[BandwidthManagementCollectionViewController alloc]
|
| + initWithBrowserState:_mainBrowserState]);
|
| + break;
|
| + case ItemTypeAboutChrome:
|
| + controller.reset([[AboutChromeCollectionViewController alloc] init]);
|
| + break;
|
| + case ItemTypeMemoryDebugging:
|
| + case ItemTypeViewSource:
|
| + case ItemTypeLogJavascript:
|
| + case ItemTypeShowAutofillTypePredictions:
|
| + // Taps on these don't do anything. They have a switch as accessory view
|
| + // and only the switch is tappable.
|
| + break;
|
| + case ItemTypeCellCatalog:
|
| + controller.reset([[MaterialCellCatalogViewController alloc] init]);
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + if (controller) {
|
| + [self.navigationController pushViewController:controller animated:YES];
|
| + }
|
| +}
|
| +
|
| +#pragma mark MDCCollectionViewStylingDelegate
|
| +
|
| +- (CGFloat)collectionView:(UICollectionView*)collectionView
|
| + cellHeightAtIndexPath:(NSIndexPath*)indexPath {
|
| + CollectionViewItem* item =
|
| + [self.collectionViewModel itemAtIndexPath:indexPath];
|
| +
|
| + if (item.type == ItemTypeAccount) {
|
| + return MDCCellDefaultTwoLineHeight;
|
| + }
|
| +
|
| + if (item.type == ItemTypeSignInButton) {
|
| + return MDCCellDefaultThreeLineHeight;
|
| + }
|
| +
|
| + return MDCCellDefaultOneLineHeight;
|
| +}
|
| +
|
| +- (BOOL)collectionView:(UICollectionView*)collectionView
|
| + hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
|
| + NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
|
| + switch (type) {
|
| + case ItemTypeMemoryDebugging:
|
| + case ItemTypeViewSource:
|
| + case ItemTypeLogJavascript:
|
| + case ItemTypeShowAutofillTypePredictions:
|
| + return YES;
|
| + default:
|
| + return NO;
|
| + }
|
| +}
|
| +
|
| +#pragma mark Switch Actions
|
| +
|
| +- (void)memorySwitchToggled:(UISwitch*)sender {
|
| + NSIndexPath* switchPath =
|
| + [self.collectionViewModel indexPathForItemType:ItemTypeMemoryDebugging
|
| + sectionIdentifier:SectionIdentifierDebug];
|
| +
|
| + CollectionViewSwitchItem* switchItem =
|
| + base::mac::ObjCCastStrict<CollectionViewSwitchItem>(
|
| + [self.collectionViewModel itemAtIndexPath:switchPath]);
|
| +
|
| + BOOL newSwitchValue = sender.isOn;
|
| + switchItem.on = newSwitchValue;
|
| + [_showMemoryDebugToolsEnabled setValue:newSwitchValue];
|
| +}
|
| +
|
| +#if CHROMIUM_BUILD && !defined(NDEBUG)
|
| +- (void)viewSourceSwitchToggled:(UISwitch*)sender {
|
| + NSIndexPath* switchPath =
|
| + [self.collectionViewModel indexPathForItemType:ItemTypeViewSource
|
| + sectionIdentifier:SectionIdentifierDebug];
|
| +
|
| + CollectionViewSwitchItem* switchItem =
|
| + base::mac::ObjCCastStrict<CollectionViewSwitchItem>(
|
| + [self.collectionViewModel itemAtIndexPath:switchPath]);
|
| +
|
| + BOOL newSwitchValue = sender.isOn;
|
| + switchItem.on = newSwitchValue;
|
| + [self setBooleanNSUserDefaultsValue:newSwitchValue forKey:kDevViewSourceKey];
|
| +}
|
| +
|
| +- (void)logJSSwitchToggled:(UISwitch*)sender {
|
| + NSIndexPath* switchPath =
|
| + [self.collectionViewModel indexPathForItemType:ItemTypeLogJavascript
|
| + sectionIdentifier:SectionIdentifierDebug];
|
| +
|
| + CollectionViewSwitchItem* switchItem =
|
| + base::mac::ObjCCastStrict<CollectionViewSwitchItem>(
|
| + [self.collectionViewModel itemAtIndexPath:switchPath]);
|
| +
|
| + BOOL newSwitchValue = sender.isOn;
|
| + switchItem.on = newSwitchValue;
|
| + [self setBooleanNSUserDefaultsValue:newSwitchValue forKey:kLogJavascriptKey];
|
| +}
|
| +
|
| +- (void)showAutoFillSwitchToggled:(UISwitch*)sender {
|
| + NSIndexPath* switchPath = [self.collectionViewModel
|
| + indexPathForItemType:ItemTypeShowAutofillTypePredictions
|
| + sectionIdentifier:SectionIdentifierDebug];
|
| +
|
| + CollectionViewSwitchItem* switchItem =
|
| + base::mac::ObjCCastStrict<CollectionViewSwitchItem>(
|
| + [self.collectionViewModel itemAtIndexPath:switchPath]);
|
| +
|
| + BOOL newSwitchValue = sender.isOn;
|
| + switchItem.on = newSwitchValue;
|
| + [self setBooleanNSUserDefaultsValue:newSwitchValue
|
| + forKey:kShowAutofillTypePredictionsKey];
|
| +}
|
| +#endif // CHROMIUM_BUILD && !defined(NDEBUG)
|
| +
|
| +#pragma mark Private methods
|
| +
|
| +// Sets the NSUserDefaults BOOL |value| for |key|.
|
| +- (void)setBooleanNSUserDefaultsValue:(BOOL)value forKey:(NSString*)key {
|
| + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
| + [defaults setBool:value forKey:key];
|
| + [defaults synchronize];
|
| +}
|
| +
|
| +// Returns YES if a "Debug" section should be shown. This is always true for
|
| +// Chromium builds, but for official builds it is gated by an experimental flag
|
| +// because the "Debug" section should never be showing in stable channel.
|
| +- (BOOL)hasDebugSection {
|
| +#if CHROMIUM_BUILD && !defined(NDEBUG)
|
| + return YES;
|
| +#else
|
| + if (experimental_flags::IsMemoryDebuggingEnabled()) {
|
| + return YES;
|
| + }
|
| + return NO;
|
| +#endif // CHROMIUM_BUILD && !defined(NDEBUG)
|
| +}
|
| +
|
| +// Updates the identity cell.
|
| +- (void)updateIdentityAccountItem:
|
| + (CollectionViewAccountItem*)identityAccountItem {
|
| + AuthenticationService* authService =
|
| + AuthenticationServiceFactory::GetForBrowserState(_mainBrowserState);
|
| + _identity.reset([authService->GetAuthenticatedIdentity() retain]);
|
| + if (!_identity) {
|
| + // This could occur during the sign out process. Just ignore as the account
|
| + // cell will be replaced by the "Sign in" button.
|
| + return;
|
| + }
|
| + identityAccountItem.image = [self userAccountImage];
|
| +
|
| + SyncSetupService* syncSetupService =
|
| + SyncSetupServiceFactory::GetForBrowserState(_mainBrowserState);
|
| +
|
| + if (!syncSetupService->HasFinishedInitialSetup()) {
|
| + identityAccountItem.detailText =
|
| + l10n_util::GetNSString(IDS_IOS_SYNC_SETUP_IN_PROGRESS);
|
| + identityAccountItem.shouldDisplayError = NO;
|
| + return;
|
| + }
|
| + identityAccountItem.shouldDisplayError =
|
| + !ios_internal::sync::IsTransientSyncError(
|
| + syncSetupService->GetSyncServiceState());
|
| + identityAccountItem.text = [_identity userFullName];
|
| + if (identityAccountItem.shouldDisplayError) {
|
| + identityAccountItem.detailText =
|
| + ios_internal::sync::GetSyncErrorDescriptionForBrowserState(
|
| + _mainBrowserState);
|
| + } else {
|
| + identityAccountItem.detailText =
|
| + syncSetupService->IsSyncEnabled()
|
| + ? l10n_util::GetNSStringF(
|
| + IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SYNCING,
|
| + base::SysNSStringToUTF16([_identity userEmail]))
|
| + : l10n_util::GetNSString(
|
| + IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SYNC_OFF);
|
| + }
|
| +}
|
| +
|
| +- (void)reloadAccountCell {
|
| + if (![self.collectionViewModel hasItemForItemType:ItemTypeAccount
|
| + sectionIdentifier:SectionIdentifierSignIn]) {
|
| + return;
|
| + }
|
| + NSIndexPath* accountCellIndexPath =
|
| + [self.collectionViewModel indexPathForItemType:ItemTypeAccount
|
| + sectionIdentifier:SectionIdentifierSignIn];
|
| + CollectionViewAccountItem* identityAccountItem =
|
| + base::mac::ObjCCast<CollectionViewAccountItem>(
|
| + [self.collectionViewModel itemAtIndexPath:accountCellIndexPath]);
|
| + if (identityAccountItem) {
|
| + [self updateIdentityAccountItem:identityAccountItem];
|
| + [self reconfigureCellsForItems:@[ identityAccountItem ]
|
| + inSectionWithIdentifier:SectionIdentifierSignIn];
|
| + }
|
| +}
|
| +
|
| +#pragma mark Sign in
|
| +
|
| +- (void)showSignIn {
|
| + base::RecordAction(base::UserMetricsAction("Signin_Signin_FromSettings"));
|
| + DCHECK(!_signinInteractionController);
|
| + _signinInteractionController.reset([[SigninInteractionController alloc]
|
| + initWithBrowserState:_mainBrowserState
|
| + presentingViewController:self.navigationController
|
| + isPresentedOnSettings:YES
|
| + signInAccessPoint:signin_metrics::AccessPoint::
|
| + ACCESS_POINT_SETTINGS]);
|
| +
|
| + base::WeakNSObject<SettingsCollectionViewController> weakSelf(self);
|
| + [_signinInteractionController signInWithCompletion:^(BOOL success) {
|
| + [weakSelf didFinishSignin:success];
|
| + }
|
| + viewController:self];
|
| +}
|
| +
|
| +- (void)didFinishSignin:(BOOL)signedIn {
|
| + _signinInteractionController.reset();
|
| +}
|
| +
|
| +#pragma mark NotificationBridgeDelegate
|
| +
|
| +- (void)onSignInStateChanged {
|
| + // Sign in state changes are rare. Just reload the entire collection when this
|
| + // happens.
|
| + [self reloadData];
|
| +}
|
| +
|
| +#pragma mark SettingsControllerProtocol
|
| +
|
| +- (void)settingsWillBeDismissed {
|
| + [_signinInteractionController cancel];
|
| + [self stopBrowserStateServiceObservers];
|
| +}
|
| +
|
| +#pragma mark SyncObserverModelBridge
|
| +
|
| +- (void)onSyncStateChanged {
|
| + [self reloadAccountCell];
|
| +}
|
| +
|
| +#pragma mark - IdentityRefreshLogic
|
| +
|
| +// Image used for loggedin user account that supports caching.
|
| +- (UIImage*)userAccountImage {
|
| + UIImage* image = ios::GetChromeBrowserProvider()
|
| + ->GetChromeIdentityService()
|
| + ->GetCachedAvatarForIdentity(_identity);
|
| + if (!image) {
|
| + image = ios::GetChromeBrowserProvider()
|
| + ->GetSigninResourcesProvider()
|
| + ->GetDefaultAvatar();
|
| + // No cached image, trigger a fetch, which will notify all observers
|
| + // (including the corresponding AccountViewBase).
|
| + ios::GetChromeBrowserProvider()
|
| + ->GetChromeIdentityService()
|
| + ->GetAvatarForIdentity(_identity, ^(UIImage*){
|
| + });
|
| + }
|
| +
|
| + // If the currently used image has already been resized, use it.
|
| + if (_resizedImage && _oldImage.get() == image)
|
| + return _resizedImage;
|
| +
|
| + _oldImage.reset(image);
|
| +
|
| + // Resize the profile image.
|
| + CGFloat dimension = kAccountProfilePhotoDimension;
|
| + if (image.size.width != dimension || image.size.height != dimension) {
|
| + image = ResizeImage(image, CGSizeMake(dimension, dimension),
|
| + ProjectionMode::kAspectFit);
|
| + }
|
| + _resizedImage.reset([image retain]);
|
| + return _resizedImage;
|
| +}
|
| +
|
| +#pragma mark ChromeIdentityServiceObserver
|
| +
|
| +- (void)onProfileUpdate:(ChromeIdentity*)identity {
|
| + if (identity == _identity) {
|
| + [self reloadAccountCell];
|
| + }
|
| +}
|
| +
|
| +- (void)onChromeIdentityServiceWillBeDestroyed {
|
| + _identityServiceObserver.reset();
|
| +}
|
| +
|
| +#pragma mark - BooleanObserver
|
| +
|
| +- (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean {
|
| + DCHECK_EQ(observableBoolean, _showMemoryDebugToolsEnabled.get());
|
| + // Update the Item.
|
| + _showMemoryDebugToolsItem.get().on = [_showMemoryDebugToolsEnabled value];
|
| +
|
| + // Update the Cell.
|
| + [self reconfigureCellsForItems:@[ _showMemoryDebugToolsItem ]
|
| + inSectionWithIdentifier:SectionIdentifierDebug];
|
| +}
|
| +
|
| +#pragma mark - PrefObserverDelegate
|
| +
|
| +- (void)onPreferenceChanged:(const std::string&)preferenceName {
|
| + if (preferenceName == prefs::kVoiceSearchLocale) {
|
| + voice::SpeechInputLocaleConfig* localeConfig =
|
| + voice::SpeechInputLocaleConfig::GetInstance();
|
| + voice::SpeechInputLocale locale =
|
| + _voiceLocaleCode.GetValue().length()
|
| + ? localeConfig->GetLocaleForCode(_voiceLocaleCode.GetValue())
|
| + : localeConfig->GetDefaultLocale();
|
| + NSString* languageName = base::SysUTF16ToNSString(locale.display_name);
|
| + _voiceSearchDetailItem.get().detailText = languageName;
|
| + [self reconfigureCellsForItems:@[ _voiceSearchDetailItem ]
|
| + inSectionWithIdentifier:SectionIdentifierAdvanced];
|
| + }
|
| +
|
| + if (preferenceName ==
|
| + password_manager::prefs::kPasswordManagerSavingEnabled) {
|
| + BOOL savePasswordsEnabled =
|
| + _mainBrowserState->GetPrefs()->GetBoolean(preferenceName);
|
| + NSString* passwordsDetail =
|
| + savePasswordsEnabled ? l10n_util::GetNSString(IDS_IOS_SETTING_ON)
|
| + : l10n_util::GetNSString(IDS_IOS_SETTING_OFF);
|
| +
|
| + _savePasswordsDetailItem.get().detailText = passwordsDetail;
|
| + [self reconfigureCellsForItems:@[ _savePasswordsDetailItem ]
|
| + inSectionWithIdentifier:SectionIdentifierBasics];
|
| + }
|
| +
|
| + if (preferenceName == autofill::prefs::kAutofillEnabled) {
|
| + BOOL autofillEnabled =
|
| + _mainBrowserState->GetPrefs()->GetBoolean(preferenceName);
|
| + NSString* autofillDetail =
|
| + autofillEnabled ? l10n_util::GetNSString(IDS_IOS_SETTING_ON)
|
| + : l10n_util::GetNSString(IDS_IOS_SETTING_OFF);
|
| + _autoFillDetailItem.get().detailText = autofillDetail;
|
| + [self reconfigureCellsForItems:@[ _autoFillDetailItem ]
|
| + inSectionWithIdentifier:SectionIdentifierBasics];
|
| + }
|
| +}
|
| +
|
| +@end
|
|
|