| Index: ios/chrome/browser/ui/settings/settings_navigation_controller.mm
|
| diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8c4e774e626c0a8b367c59b12c4c7f09c0b8a394
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
|
| @@ -0,0 +1,636 @@
|
| +// Copyright 2013 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_navigation_controller.h"
|
| +
|
| +#include "base/ios/ios_util.h"
|
| +#import "base/ios/weak_nsobject.h"
|
| +#include "base/mac/foundation_util.h"
|
| +#import "base/mac/scoped_nsobject.h"
|
| +#include "components/strings/grit/components_strings.h"
|
| +#include "ios/chrome/browser/browser_state/chrome_browser_state.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/commands/UIKit+ChromeExecuteCommand.h"
|
| +#import "ios/chrome/browser/ui/commands/clear_browsing_data_command.h"
|
| +#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
|
| +#import "ios/chrome/browser/ui/commands/show_signin_command.h"
|
| +#import "ios/chrome/browser/ui/icons/chrome_icon.h"
|
| +#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
|
| +#import "ios/chrome/browser/ui/material_components/app_bar_presenting.h"
|
| +#import "ios/chrome/browser/ui/material_components/utils.h"
|
| +#import "ios/chrome/browser/ui/settings/accounts_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/contextual_search_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/import_data_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/settings_utils.h"
|
| +#import "ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.h"
|
| +#import "ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.h"
|
| +#include "ios/chrome/browser/ui/ui_util.h"
|
| +#import "ios/chrome/browser/ui/uikit_ui_util.h"
|
| +#include "ios/chrome/grit/ios_strings.h"
|
| +#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
|
| +#import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h"
|
| +#import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +#include "ui/base/l10n/l10n_util_mac.h"
|
| +
|
| +// TODO(crbug.com/620361): Remove the entire class when iOS 9 is dropped.
|
| +@interface SettingsAppBarContainerViewController
|
| + : MDCAppBarContainerViewController
|
| +@end
|
| +
|
| +@implementation SettingsAppBarContainerViewController
|
| +
|
| +#pragma mark - Status bar
|
| +
|
| +- (UIViewController*)childViewControllerForStatusBarHidden {
|
| + if (!base::ios::IsRunningOnIOS10OrLater()) {
|
| + // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is
|
| + // dropped.
|
| + return self.contentViewController;
|
| + } else {
|
| + return [super childViewControllerForStatusBarHidden];
|
| + }
|
| +}
|
| +
|
| +- (UIViewController*)childViewControllerForStatusBarStyle {
|
| + if (!base::ios::IsRunningOnIOS10OrLater()) {
|
| + // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is
|
| + // dropped.
|
| + return self.contentViewController;
|
| + } else {
|
| + return [super childViewControllerForStatusBarStyle];
|
| + }
|
| +}
|
| +
|
| +@end
|
| +
|
| +@interface SettingsNavigationController ()<UIGestureRecognizerDelegate>
|
| +
|
| +// Sets up the UI. Used by both initializers.
|
| +- (void)configureUI;
|
| +
|
| +// Closes the settings by calling |closeSettings| on |delegate|.
|
| +- (void)closeSettings;
|
| +
|
| +// Creates an autoreleased "X" button that closes the settings when tapped.
|
| +- (UIBarButtonItem*)closeButton;
|
| +
|
| +// Creates an autoreleased "CANCEL" button that closes the settings when tapped.
|
| +- (UIBarButtonItem*)cancelButton;
|
| +
|
| +// Intercepts the chrome command |sender|. If |sender| is an
|
| +// |IDC_CLOSE_SETTINGS_AND_OPEN_URL| and |delegate_| is not nil, then it
|
| +// calls [delegate closeSettingsAndOpenUrl:sender], otherwise it forwards the
|
| +// command up the responder chain.
|
| +- (void)chromeExecuteCommand:(id)sender;
|
| +
|
| +@end
|
| +
|
| +@implementation SettingsNavigationController {
|
| + ios::ChromeBrowserState* mainBrowserState_; // weak
|
| + base::WeakNSProtocol<id<SettingsNavigationControllerDelegate>> delegate_;
|
| + // Keeps a mapping between the view controllers that are wrapped to display an
|
| + // app bar and the containers that wrap them.
|
| + base::scoped_nsobject<NSMutableDictionary> appBarContainedViewControllers_;
|
| +}
|
| +
|
| +@synthesize shouldCommitSyncChangesOnDismissal =
|
| + shouldCommitSyncChangesOnDismissal_;
|
| +
|
| +#pragma mark - SettingsNavigationController methods.
|
| +
|
| +// clang-format off
|
| ++ (SettingsNavigationController*)newSettingsMainControllerWithMainBrowserState:
|
| + (ios::ChromeBrowserState*)browserState
|
| + currentBrowserState:
|
| + (ios::ChromeBrowserState*)currentBrowserState
|
| + delegate:
|
| + (id<SettingsNavigationControllerDelegate>)delegate {
|
| + // clang-format on
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[SettingsCollectionViewController alloc]
|
| + initWithBrowserState:browserState
|
| + currentBrowserState:currentBrowserState]);
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| + [controller navigationItem].rightBarButtonItem = [nc doneButton];
|
| + return nc;
|
| +}
|
| +
|
| ++ (SettingsNavigationController*)
|
| +newAccountsController:(ios::ChromeBrowserState*)browserState
|
| + delegate:(id<SettingsNavigationControllerDelegate>)delegate {
|
| + base::scoped_nsobject<UIViewController> controller([
|
| + [AccountsCollectionViewController alloc] initWithBrowserState:browserState
|
| + closeSettingsOnAddAccount:YES]);
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| + [controller navigationItem].leftBarButtonItem = [nc closeButton];
|
| + return nc;
|
| +}
|
| +
|
| ++ (SettingsNavigationController*)
|
| + newSyncController:(ios::ChromeBrowserState*)browserState
|
| +allowSwitchSyncAccount:(BOOL)allowSwitchSyncAccount
|
| + delegate:(id<SettingsNavigationControllerDelegate>)delegate {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[SyncSettingsCollectionViewController alloc]
|
| + initWithBrowserState:browserState
|
| + allowSwitchSyncAccount:allowSwitchSyncAccount]);
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| + [controller navigationItem].rightBarButtonItem = [nc doneButton];
|
| + return nc;
|
| +}
|
| +
|
| ++ (SettingsNavigationController*)
|
| +newUserFeedbackController:(ios::ChromeBrowserState*)browserState
|
| + delegate:(id<SettingsNavigationControllerDelegate>)delegate
|
| + feedbackDataSource:(id<UserFeedbackDataSource>)dataSource {
|
| + DCHECK(ios::GetChromeBrowserProvider()
|
| + ->GetUserFeedbackProvider()
|
| + ->IsUserFeedbackEnabled());
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + ios::GetChromeBrowserProvider()
|
| + ->GetUserFeedbackProvider()
|
| + ->CreateViewController(dataSource));
|
| + DCHECK(controller);
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| + [controller navigationItem].rightBarButtonItem = [nc cancelButton];
|
| + return nc;
|
| +}
|
| +
|
| ++ (SettingsNavigationController*)
|
| +newClearBrowsingDataController:(ios::ChromeBrowserState*)browserState
|
| + delegate:
|
| + (id<SettingsNavigationControllerDelegate>)delegate {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[ClearBrowsingDataCollectionViewController alloc]
|
| + initWithBrowserState:browserState]);
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| + [controller navigationItem].rightBarButtonItem = [nc doneButton];
|
| + return nc;
|
| +}
|
| +
|
| ++ (SettingsNavigationController*)
|
| +newContextualSearchController:(ios::ChromeBrowserState*)browserState
|
| + delegate:
|
| + (id<SettingsNavigationControllerDelegate>)delegate {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[ContextualSearchCollectionViewController alloc]
|
| + initWithBrowserState:browserState]);
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| + [controller navigationItem].rightBarButtonItem = [nc doneButton];
|
| + return nc;
|
| +}
|
| +
|
| ++ (SettingsNavigationController*)
|
| +newSyncEncryptionPassphraseController:(ios::ChromeBrowserState*)browserState
|
| + delegate:(id<SettingsNavigationControllerDelegate>)
|
| + delegate {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[SyncEncryptionPassphraseCollectionViewController alloc]
|
| + initWithBrowserState:browserState]);
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| + [controller navigationItem].leftBarButtonItem = [nc closeButton];
|
| + return nc;
|
| +}
|
| +
|
| ++ (SettingsNavigationController*)
|
| +newNativeAppsController:(ios::ChromeBrowserState*)browserState
|
| + delegate:(id<SettingsNavigationControllerDelegate>)delegate {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[NativeAppsCollectionViewController alloc]
|
| + initWithURLRequestContextGetter:browserState->GetRequestContext()]);
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| + return nc;
|
| +}
|
| +
|
| ++ (SettingsNavigationController*)
|
| +newSavePasswordsController:(ios::ChromeBrowserState*)browserState
|
| + delegate:(id<SettingsNavigationControllerDelegate>)delegate {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[SavePasswordsCollectionViewController alloc]
|
| + initWithBrowserState:browserState]);
|
| +
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| + [controller navigationItem].rightBarButtonItem = [nc doneButton];
|
| +
|
| + // Make sure the close button is always present, as the Save Passwords screen
|
| + // isn't just shown from Settings.
|
| + [controller navigationItem].leftBarButtonItem = [nc closeButton];
|
| + return nc;
|
| +}
|
| +
|
| ++ (SettingsNavigationController*)
|
| +newImportDataController:(ios::ChromeBrowserState*)browserState
|
| + delegate:(id<SettingsNavigationControllerDelegate>)delegate
|
| + importDataDelegate:(id<ImportDataControllerDelegate>)importDataDelegate
|
| + fromEmail:(NSString*)fromEmail
|
| + toEmail:(NSString*)toEmail
|
| + isSignedIn:(BOOL)isSignedIn {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[ImportDataCollectionViewController alloc]
|
| + initWithDelegate:importDataDelegate
|
| + fromEmail:fromEmail
|
| + toEmail:toEmail
|
| + isSignedIn:isSignedIn]);
|
| +
|
| + SettingsNavigationController* nc = [[SettingsNavigationController alloc]
|
| + initWithRootViewController:controller
|
| + browserState:browserState
|
| + delegate:delegate];
|
| +
|
| + // Make sure the close button is always present, as the Save Passwords screen
|
| + // isn't just shown from Settings.
|
| + [controller navigationItem].leftBarButtonItem = [nc closeButton];
|
| + return nc;
|
| +}
|
| +
|
| +#pragma mark - Lifecycle
|
| +
|
| +- (instancetype)
|
| +initWithRootViewController:(UIViewController*)rootViewController
|
| + browserState:(ios::ChromeBrowserState*)browserState
|
| + delegate:(id<SettingsNavigationControllerDelegate>)delegate {
|
| + DCHECK(browserState);
|
| + DCHECK(!browserState->IsOffTheRecord());
|
| + self = [super initWithRootViewController:rootViewController];
|
| + if (self) {
|
| + mainBrowserState_ = browserState;
|
| + delegate_.reset(delegate);
|
| + shouldCommitSyncChangesOnDismissal_ = YES;
|
| + [self configureUI];
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (void)settingsWillBeDismissed {
|
| + // Notify all controllers that settings are about to be dismissed.
|
| + for (UIViewController* controller in [self viewControllers]) {
|
| + if ([controller respondsToSelector:@selector(settingsWillBeDismissed)]) {
|
| + [controller performSelector:@selector(settingsWillBeDismissed)];
|
| + }
|
| + }
|
| +
|
| + // Sync changes cannot be cancelled and they must always be commited when
|
| + // existing settings.
|
| + if (shouldCommitSyncChangesOnDismissal_) {
|
| + SyncSetupServiceFactory::GetForBrowserState([self mainBrowserState])
|
| + ->CommitChanges();
|
| + }
|
| +
|
| + // Reset the delegate to prevent any queued transitions from attempting to
|
| + // close the settings.
|
| + delegate_.reset();
|
| +}
|
| +
|
| +- (void)closeSettings {
|
| + [delegate_ closeSettings];
|
| +}
|
| +
|
| +- (void)popViewControllerOrCloseSettingsAnimated:(BOOL)animated {
|
| + if (self.viewControllers.count > 1) {
|
| + // Pop the top view controller to reveal the view controller underneath.
|
| + [self popViewControllerAnimated:animated];
|
| + } else {
|
| + // If there is only one view controller in the navigation stack,
|
| + // simply close settings.
|
| + [self closeSettings];
|
| + }
|
| +}
|
| +
|
| +- (void)configureUI {
|
| + [self setModalPresentationStyle:UIModalPresentationFormSheet];
|
| + [self setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
|
| + // Since the navigation bar is hidden, the gesture to swipe to go back can
|
| + // become inactive. Setting the delegate to self is an MDC workaround to have
|
| + // it consistently work with AppBar.
|
| + // https://github.com/material-components/material-components-ios/issues/720
|
| + [self setNavigationBarHidden:YES];
|
| + [self.interactivePopGestureRecognizer setDelegate:self];
|
| +}
|
| +
|
| +- (BOOL)hasRightDoneButton {
|
| + UIBarButtonItem* rightButton =
|
| + self.topViewController.navigationItem.rightBarButtonItem;
|
| + if (!rightButton)
|
| + return NO;
|
| + base::scoped_nsobject<UIBarButtonItem> doneButton([self doneButton]);
|
| + return [rightButton style] == [doneButton style] &&
|
| + [[rightButton title] compare:[doneButton title]] == NSOrderedSame;
|
| +}
|
| +
|
| +- (UIBarButtonItem*)doneButton {
|
| + // Create a custom Done bar button item, as Material Navigation Bar does not
|
| + // handle a system UIBarButtonSystemItemDone item.
|
| + return [[[UIBarButtonItem alloc]
|
| + initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON)
|
| + style:UIBarButtonItemStyleDone
|
| + target:self
|
| + action:@selector(closeSettings)] autorelease];
|
| +}
|
| +
|
| +- (UIBarButtonItem*)closeButton {
|
| + UIBarButtonItem* closeButton =
|
| + [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon closeIcon]
|
| + target:self
|
| + action:@selector(closeSettings)];
|
| + closeButton.accessibilityLabel = l10n_util::GetNSString(IDS_ACCNAME_CLOSE);
|
| + return closeButton;
|
| +}
|
| +
|
| +- (UIBarButtonItem*)cancelButton {
|
| + // Create a custom Cancel bar button item, as Material Navigation Bar does not
|
| + // handle a system UIBarButtonSystemItemCancel item.
|
| + return [[[UIBarButtonItem alloc]
|
| + initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_CANCEL_BUTTON)
|
| + style:UIBarButtonItemStyleDone
|
| + target:self
|
| + action:@selector(closeSettings)] autorelease];
|
| +}
|
| +
|
| +- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
| + return [self.topViewController supportedInterfaceOrientations];
|
| +}
|
| +
|
| +- (BOOL)shouldAutorotate {
|
| + return [self.topViewController shouldAutorotate];
|
| +}
|
| +
|
| +#pragma mark - UIGestureRecognizerDelegate
|
| +
|
| +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer {
|
| + DCHECK_EQ(gestureRecognizer, self.interactivePopGestureRecognizer);
|
| + return self.viewControllers.count > 1;
|
| +}
|
| +
|
| +#pragma mark - Accessibility
|
| +
|
| +- (BOOL)accessibilityPerformEscape {
|
| + UIViewController* poppedController = [self popViewControllerAnimated:YES];
|
| + if (!poppedController)
|
| + [self closeSettings];
|
| + return YES;
|
| +}
|
| +
|
| +#pragma mark - UINavigationController
|
| +
|
| +- (void)pushViewController:(UIViewController*)viewController
|
| + animated:(BOOL)animated {
|
| + // Wrap the view controller in an MDCAppBarContainerViewController if needed.
|
| + [super pushViewController:[self wrappedControllerIfNeeded:viewController]
|
| + animated:animated];
|
| +}
|
| +
|
| +- (UIViewController*)popViewControllerAnimated:(BOOL)animated {
|
| + UIViewController* viewController = [super popViewControllerAnimated:animated];
|
| + // Unwrap the view controller from its MDCAppBarContainerViewController if
|
| + // needed.
|
| + return [self unwrappedControllerIfNeeded:viewController];
|
| +}
|
| +
|
| +- (NSArray*)popToViewController:(UIViewController*)viewController
|
| + animated:(BOOL)animated {
|
| + // First, check if the view controller was wrapped in an app bar container.
|
| + MDCAppBarContainerViewController* appBarContainer =
|
| + [self appBarContainerForController:viewController];
|
| + // Pop the view controllers.
|
| + NSArray* poppedViewControllers =
|
| + [super popToViewController:appBarContainer ?: viewController
|
| + animated:animated];
|
| + // Unwrap the popped view controllers from their
|
| + // MDCAppBarContainerViewController if needed.
|
| + NSMutableArray* viewControllers = [NSMutableArray array];
|
| + [poppedViewControllers
|
| + enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop) {
|
| + [viewControllers
|
| + addObject:[self unwrappedControllerIfNeeded:viewController]];
|
| + }];
|
| + return viewControllers;
|
| +}
|
| +
|
| +// Ensures that the keyboard is always dismissed during a navigation transition.
|
| +- (BOOL)disablesAutomaticKeyboardDismissal {
|
| + return NO;
|
| +}
|
| +
|
| +#pragma mark - UIResponder (ChromeExecuteCommand)
|
| +
|
| +- (void)chromeExecuteCommand:(id)sender {
|
| + switch ([sender tag]) {
|
| + case IDC_CLOSE_SETTINGS: {
|
| + [delegate_ closeSettings];
|
| + return;
|
| + }
|
| + case IDC_OPEN_URL:
|
| + NOTREACHED() << "You should probably use the command "
|
| + << "IDC_CLOSE_SETTINGS_AND_OPEN_URL instead of IDC_OPEN_URL";
|
| + case IDC_CLOSE_SETTINGS_AND_OPEN_URL: {
|
| + [delegate_ closeSettingsAndOpenUrl:sender];
|
| + return;
|
| + }
|
| + case IDC_CLOSE_SETTINGS_AND_OPEN_NEW_INCOGNITO_TAB: {
|
| + [delegate_ closeSettingsAndOpenNewIncognitoTab];
|
| + return;
|
| + }
|
| + case IDC_SHOW_SIGNIN_IOS:
|
| + // Sign-in actions can only happen on the main browser state (not on
|
| + // incognito browser state), which is unique. The command can just be
|
| + // forwarded up the responder chain.
|
| + break;
|
| + case IDC_CLEAR_BROWSING_DATA_IOS: {
|
| + // Check that the data for the right browser state is being cleared before
|
| + // forwarding it up the responder chain.
|
| + ios::ChromeBrowserState* commandBrowserState =
|
| + [base::mac::ObjCCast<ClearBrowsingDataCommand>(sender) browserState];
|
| +
|
| + // Clearing browsing data for the wrong profile is a destructive action.
|
| + // Executing it on the wrong profile is a privacy issue. Kill the
|
| + // app if this ever happens.
|
| + CHECK_EQ(commandBrowserState, [self mainBrowserState]);
|
| + break;
|
| + }
|
| + case IDC_RESET_ALL_WEBVIEWS:
|
| + // The command to reset all webview is not related to the browser state so
|
| + // it can just be forwarded it up the responder chain.
|
| + break;
|
| + case IDC_SHOW_ACCOUNTS_SETTINGS: {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[AccountsCollectionViewController alloc]
|
| + initWithBrowserState:mainBrowserState_
|
| + closeSettingsOnAddAccount:NO]);
|
| + [self pushViewController:controller animated:YES];
|
| + return;
|
| + }
|
| + case IDC_SHOW_SYNC_SETTINGS: {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[SyncSettingsCollectionViewController alloc]
|
| + initWithBrowserState:mainBrowserState_
|
| + allowSwitchSyncAccount:YES]);
|
| + [self pushViewController:controller animated:YES];
|
| + return;
|
| + }
|
| + case IDC_SHOW_SYNC_PASSPHRASE_SETTINGS: {
|
| + base::scoped_nsobject<UIViewController> controller(
|
| + [[SyncEncryptionPassphraseCollectionViewController alloc]
|
| + initWithBrowserState:mainBrowserState_]);
|
| + [self pushViewController:controller animated:YES];
|
| + return;
|
| + }
|
| + default:
|
| + NOTREACHED()
|
| + << "Unexpected command " << [sender tag]
|
| + << " Settings commands must execute on the main browser state.";
|
| + }
|
| + [[self nextResponder] chromeExecuteCommand:sender];
|
| +}
|
| +
|
| +#pragma mark - UIResponder
|
| +
|
| +- (NSArray*)keyCommands {
|
| + base::WeakNSObject<SettingsNavigationController> weakSelf(self);
|
| + return @[
|
| + [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape
|
| + modifierFlags:Cr_UIKeyModifierNone
|
| + title:nil
|
| + action:^{
|
| + [weakSelf closeSettings];
|
| + }],
|
| + ];
|
| +}
|
| +
|
| +#pragma mark - Profile
|
| +
|
| +- (ios::ChromeBrowserState*)mainBrowserState {
|
| + return mainBrowserState_;
|
| +}
|
| +
|
| +#pragma mark - Status bar
|
| +
|
| +- (BOOL)modalPresentationCapturesStatusBarAppearance {
|
| + if (!base::ios::IsRunningOnIOS10OrLater()) {
|
| + // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is
|
| + // dropped.
|
| + return YES;
|
| + } else {
|
| + return [super modalPresentationCapturesStatusBarAppearance];
|
| + }
|
| +}
|
| +
|
| +- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
|
| + [super traitCollectionDidChange:previousTraitCollection];
|
| + if (!base::ios::IsRunningOnIOS10OrLater()) {
|
| + // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is
|
| + // dropped.
|
| + [self setNeedsStatusBarAppearanceUpdate];
|
| + }
|
| +}
|
| +
|
| +#pragma mark - AppBar Containment
|
| +
|
| +// If viewController doesn't implement the AppBarPresenting protocol, it is
|
| +// wrapped in an MDCAppBarContainerViewController, which is returned. Otherwise,
|
| +// viewController is returned.
|
| +- (UIViewController*)wrappedControllerIfNeeded:(UIViewController*)controller {
|
| + // If the controller can't be presented with an app bar, it needs to be
|
| + // wrapped in an MDCAppBarContainerViewController.
|
| + if (![controller conformsToProtocol:@protocol(AppBarPresenting)]) {
|
| + MDCAppBarContainerViewController* appBarContainer =
|
| + [[[SettingsAppBarContainerViewController alloc]
|
| + initWithContentViewController:controller] autorelease];
|
| +
|
| + // Configure the style.
|
| + ConfigureAppBarWithCardStyle(appBarContainer.appBar);
|
| +
|
| + // Adjust the frame of the contained view controller's view to be below the
|
| + // app bar.
|
| + CGRect contentFrame = controller.view.frame;
|
| + CGSize headerSize = [appBarContainer.appBar.headerViewController.headerView
|
| + sizeThatFits:contentFrame.size];
|
| + contentFrame = UIEdgeInsetsInsetRect(
|
| + contentFrame, UIEdgeInsetsMake(headerSize.height, 0, 0, 0));
|
| + controller.view.frame = contentFrame;
|
| +
|
| + // Register the app bar container and return it.
|
| + [self registerAppBarContainer:appBarContainer];
|
| + return appBarContainer;
|
| + } else {
|
| + return controller;
|
| + }
|
| +}
|
| +
|
| +// If controller is an MDCAppBarContainerViewController, it returns its content
|
| +// view controller. Otherwise, it returns viewController.
|
| +- (UIViewController*)unwrappedControllerIfNeeded:(UIViewController*)controller {
|
| + MDCAppBarContainerViewController* potentialAppBarController =
|
| + base::mac::ObjCCast<MDCAppBarContainerViewController>(controller);
|
| + if (potentialAppBarController) {
|
| + // Unregister the app bar container and return it.
|
| + [self unregisterAppBarContainer:potentialAppBarController];
|
| + return [potentialAppBarController contentViewController];
|
| + } else {
|
| + return controller;
|
| + }
|
| +}
|
| +
|
| +// Adds an app bar container in a dictionary mapping its content view
|
| +// controller's pointer to itself.
|
| +- (void)registerAppBarContainer:(MDCAppBarContainerViewController*)container {
|
| + if (!appBarContainedViewControllers_) {
|
| + appBarContainedViewControllers_.reset([[NSMutableDictionary alloc] init]);
|
| + }
|
| + NSValue* key = [self keyForController:[container contentViewController]];
|
| + [appBarContainedViewControllers_ setObject:container forKey:key];
|
| +}
|
| +
|
| +// Removes the app bar container entry from the aforementioned dictionary.
|
| +- (void)unregisterAppBarContainer:(MDCAppBarContainerViewController*)container {
|
| + NSValue* key = [self keyForController:[container contentViewController]];
|
| + [appBarContainedViewControllers_ removeObjectForKey:key];
|
| +}
|
| +
|
| +// Returns the app bar container containing |controller| if it is contained.
|
| +// Otherwise, returns nil.
|
| +- (MDCAppBarContainerViewController*)appBarContainerForController:
|
| + (UIViewController*)controller {
|
| + NSValue* key = [self keyForController:controller];
|
| + return [appBarContainedViewControllers_ objectForKey:key];
|
| +}
|
| +
|
| +// Returns the dictionary key to use when dealing with |controller|.
|
| +- (NSValue*)keyForController:(UIViewController*)controller {
|
| + return [NSValue valueWithPointer:controller];
|
| +}
|
| +
|
| +@end
|
|
|