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

Side by Side Diff: ios/chrome/browser/ui/settings/settings_navigation_controller.mm

Issue 2587023002: Upstream Chrome on iOS source code [8/11]. (Closed)
Patch Set: Created 3 years, 12 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
6
7 #include "base/ios/ios_util.h"
8 #import "base/ios/weak_nsobject.h"
9 #include "base/mac/foundation_util.h"
10 #import "base/mac/scoped_nsobject.h"
11 #include "components/strings/grit/components_strings.h"
12 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
13 #include "ios/chrome/browser/sync/sync_setup_service.h"
14 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
15 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
16 #import "ios/chrome/browser/ui/commands/clear_browsing_data_command.h"
17 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
18 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
19 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
20 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
21 #import "ios/chrome/browser/ui/material_components/app_bar_presenting.h"
22 #import "ios/chrome/browser/ui/material_components/utils.h"
23 #import "ios/chrome/browser/ui/settings/accounts_collection_view_controller.h"
24 #import "ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_cont roller.h"
25 #import "ios/chrome/browser/ui/settings/contextual_search_collection_view_contro ller.h"
26 #import "ios/chrome/browser/ui/settings/import_data_collection_view_controller.h "
27 #import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h "
28 #import "ios/chrome/browser/ui/settings/save_passwords_collection_view_controlle r.h"
29 #import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
30 #import "ios/chrome/browser/ui/settings/settings_utils.h"
31 #import "ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_vi ew_controller.h"
32 #import "ios/chrome/browser/ui/settings/sync_settings_collection_view_controller .h"
33 #include "ios/chrome/browser/ui/ui_util.h"
34 #import "ios/chrome/browser/ui/uikit_ui_util.h"
35 #include "ios/chrome/grit/ios_strings.h"
36 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
37 #import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider .h"
38 #import "ios/third_party/material_components_ios/src/components/AppBar/src/Mater ialAppBar.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/base/l10n/l10n_util_mac.h"
41
42 // TODO(crbug.com/620361): Remove the entire class when iOS 9 is dropped.
43 @interface SettingsAppBarContainerViewController
44 : MDCAppBarContainerViewController
45 @end
46
47 @implementation SettingsAppBarContainerViewController
48
49 #pragma mark - Status bar
50
51 - (UIViewController*)childViewControllerForStatusBarHidden {
52 if (!base::ios::IsRunningOnIOS10OrLater()) {
53 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is
54 // dropped.
55 return self.contentViewController;
56 } else {
57 return [super childViewControllerForStatusBarHidden];
58 }
59 }
60
61 - (UIViewController*)childViewControllerForStatusBarStyle {
62 if (!base::ios::IsRunningOnIOS10OrLater()) {
63 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is
64 // dropped.
65 return self.contentViewController;
66 } else {
67 return [super childViewControllerForStatusBarStyle];
68 }
69 }
70
71 @end
72
73 @interface SettingsNavigationController ()<UIGestureRecognizerDelegate>
74
75 // Sets up the UI. Used by both initializers.
76 - (void)configureUI;
77
78 // Closes the settings by calling |closeSettings| on |delegate|.
79 - (void)closeSettings;
80
81 // Creates an autoreleased "X" button that closes the settings when tapped.
82 - (UIBarButtonItem*)closeButton;
83
84 // Creates an autoreleased "CANCEL" button that closes the settings when tapped.
85 - (UIBarButtonItem*)cancelButton;
86
87 // Intercepts the chrome command |sender|. If |sender| is an
88 // |IDC_CLOSE_SETTINGS_AND_OPEN_URL| and |delegate_| is not nil, then it
89 // calls [delegate closeSettingsAndOpenUrl:sender], otherwise it forwards the
90 // command up the responder chain.
91 - (void)chromeExecuteCommand:(id)sender;
92
93 @end
94
95 @implementation SettingsNavigationController {
96 ios::ChromeBrowserState* mainBrowserState_; // weak
97 base::WeakNSProtocol<id<SettingsNavigationControllerDelegate>> delegate_;
98 // Keeps a mapping between the view controllers that are wrapped to display an
99 // app bar and the containers that wrap them.
100 base::scoped_nsobject<NSMutableDictionary> appBarContainedViewControllers_;
101 }
102
103 @synthesize shouldCommitSyncChangesOnDismissal =
104 shouldCommitSyncChangesOnDismissal_;
105
106 #pragma mark - SettingsNavigationController methods.
107
108 // clang-format off
109 + (SettingsNavigationController*)newSettingsMainControllerWithMainBrowserState:
110 (ios::ChromeBrowserState*)browserState
111 currentBrowserState:
112 (ios::ChromeBrowserState*)currentBrowserState
113 delegate:
114 (id<SettingsNavigationControllerDelegate>)delegate {
115 // clang-format on
116 base::scoped_nsobject<UIViewController> controller(
117 [[SettingsCollectionViewController alloc]
118 initWithBrowserState:browserState
119 currentBrowserState:currentBrowserState]);
120 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
121 initWithRootViewController:controller
122 browserState:browserState
123 delegate:delegate];
124 [controller navigationItem].rightBarButtonItem = [nc doneButton];
125 return nc;
126 }
127
128 + (SettingsNavigationController*)
129 newAccountsController:(ios::ChromeBrowserState*)browserState
130 delegate:(id<SettingsNavigationControllerDelegate>)delegate {
131 base::scoped_nsobject<UIViewController> controller([
132 [AccountsCollectionViewController alloc] initWithBrowserState:browserState
133 closeSettingsOnAddAccount:YES]);
134 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
135 initWithRootViewController:controller
136 browserState:browserState
137 delegate:delegate];
138 [controller navigationItem].leftBarButtonItem = [nc closeButton];
139 return nc;
140 }
141
142 + (SettingsNavigationController*)
143 newSyncController:(ios::ChromeBrowserState*)browserState
144 allowSwitchSyncAccount:(BOOL)allowSwitchSyncAccount
145 delegate:(id<SettingsNavigationControllerDelegate>)delegate {
146 base::scoped_nsobject<UIViewController> controller(
147 [[SyncSettingsCollectionViewController alloc]
148 initWithBrowserState:browserState
149 allowSwitchSyncAccount:allowSwitchSyncAccount]);
150 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
151 initWithRootViewController:controller
152 browserState:browserState
153 delegate:delegate];
154 [controller navigationItem].rightBarButtonItem = [nc doneButton];
155 return nc;
156 }
157
158 + (SettingsNavigationController*)
159 newUserFeedbackController:(ios::ChromeBrowserState*)browserState
160 delegate:(id<SettingsNavigationControllerDelegate>)delegate
161 feedbackDataSource:(id<UserFeedbackDataSource>)dataSource {
162 DCHECK(ios::GetChromeBrowserProvider()
163 ->GetUserFeedbackProvider()
164 ->IsUserFeedbackEnabled());
165 base::scoped_nsobject<UIViewController> controller(
166 ios::GetChromeBrowserProvider()
167 ->GetUserFeedbackProvider()
168 ->CreateViewController(dataSource));
169 DCHECK(controller);
170 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
171 initWithRootViewController:controller
172 browserState:browserState
173 delegate:delegate];
174 [controller navigationItem].rightBarButtonItem = [nc cancelButton];
175 return nc;
176 }
177
178 + (SettingsNavigationController*)
179 newClearBrowsingDataController:(ios::ChromeBrowserState*)browserState
180 delegate:
181 (id<SettingsNavigationControllerDelegate>)delegate {
182 base::scoped_nsobject<UIViewController> controller(
183 [[ClearBrowsingDataCollectionViewController alloc]
184 initWithBrowserState:browserState]);
185 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
186 initWithRootViewController:controller
187 browserState:browserState
188 delegate:delegate];
189 [controller navigationItem].rightBarButtonItem = [nc doneButton];
190 return nc;
191 }
192
193 + (SettingsNavigationController*)
194 newContextualSearchController:(ios::ChromeBrowserState*)browserState
195 delegate:
196 (id<SettingsNavigationControllerDelegate>)delegate {
197 base::scoped_nsobject<UIViewController> controller(
198 [[ContextualSearchCollectionViewController alloc]
199 initWithBrowserState:browserState]);
200 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
201 initWithRootViewController:controller
202 browserState:browserState
203 delegate:delegate];
204 [controller navigationItem].rightBarButtonItem = [nc doneButton];
205 return nc;
206 }
207
208 + (SettingsNavigationController*)
209 newSyncEncryptionPassphraseController:(ios::ChromeBrowserState*)browserState
210 delegate:(id<SettingsNavigationControllerDelegate>)
211 delegate {
212 base::scoped_nsobject<UIViewController> controller(
213 [[SyncEncryptionPassphraseCollectionViewController alloc]
214 initWithBrowserState:browserState]);
215 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
216 initWithRootViewController:controller
217 browserState:browserState
218 delegate:delegate];
219 [controller navigationItem].leftBarButtonItem = [nc closeButton];
220 return nc;
221 }
222
223 + (SettingsNavigationController*)
224 newNativeAppsController:(ios::ChromeBrowserState*)browserState
225 delegate:(id<SettingsNavigationControllerDelegate>)delegate {
226 base::scoped_nsobject<UIViewController> controller(
227 [[NativeAppsCollectionViewController alloc]
228 initWithURLRequestContextGetter:browserState->GetRequestContext()]);
229 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
230 initWithRootViewController:controller
231 browserState:browserState
232 delegate:delegate];
233 return nc;
234 }
235
236 + (SettingsNavigationController*)
237 newSavePasswordsController:(ios::ChromeBrowserState*)browserState
238 delegate:(id<SettingsNavigationControllerDelegate>)delegate {
239 base::scoped_nsobject<UIViewController> controller(
240 [[SavePasswordsCollectionViewController alloc]
241 initWithBrowserState:browserState]);
242
243 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
244 initWithRootViewController:controller
245 browserState:browserState
246 delegate:delegate];
247 [controller navigationItem].rightBarButtonItem = [nc doneButton];
248
249 // Make sure the close button is always present, as the Save Passwords screen
250 // isn't just shown from Settings.
251 [controller navigationItem].leftBarButtonItem = [nc closeButton];
252 return nc;
253 }
254
255 + (SettingsNavigationController*)
256 newImportDataController:(ios::ChromeBrowserState*)browserState
257 delegate:(id<SettingsNavigationControllerDelegate>)delegate
258 importDataDelegate:(id<ImportDataControllerDelegate>)importDataDelegate
259 fromEmail:(NSString*)fromEmail
260 toEmail:(NSString*)toEmail
261 isSignedIn:(BOOL)isSignedIn {
262 base::scoped_nsobject<UIViewController> controller(
263 [[ImportDataCollectionViewController alloc]
264 initWithDelegate:importDataDelegate
265 fromEmail:fromEmail
266 toEmail:toEmail
267 isSignedIn:isSignedIn]);
268
269 SettingsNavigationController* nc = [[SettingsNavigationController alloc]
270 initWithRootViewController:controller
271 browserState:browserState
272 delegate:delegate];
273
274 // Make sure the close button is always present, as the Save Passwords screen
275 // isn't just shown from Settings.
276 [controller navigationItem].leftBarButtonItem = [nc closeButton];
277 return nc;
278 }
279
280 #pragma mark - Lifecycle
281
282 - (instancetype)
283 initWithRootViewController:(UIViewController*)rootViewController
284 browserState:(ios::ChromeBrowserState*)browserState
285 delegate:(id<SettingsNavigationControllerDelegate>)delegate {
286 DCHECK(browserState);
287 DCHECK(!browserState->IsOffTheRecord());
288 self = [super initWithRootViewController:rootViewController];
289 if (self) {
290 mainBrowserState_ = browserState;
291 delegate_.reset(delegate);
292 shouldCommitSyncChangesOnDismissal_ = YES;
293 [self configureUI];
294 }
295 return self;
296 }
297
298 - (void)settingsWillBeDismissed {
299 // Notify all controllers that settings are about to be dismissed.
300 for (UIViewController* controller in [self viewControllers]) {
301 if ([controller respondsToSelector:@selector(settingsWillBeDismissed)]) {
302 [controller performSelector:@selector(settingsWillBeDismissed)];
303 }
304 }
305
306 // Sync changes cannot be cancelled and they must always be commited when
307 // existing settings.
308 if (shouldCommitSyncChangesOnDismissal_) {
309 SyncSetupServiceFactory::GetForBrowserState([self mainBrowserState])
310 ->CommitChanges();
311 }
312
313 // Reset the delegate to prevent any queued transitions from attempting to
314 // close the settings.
315 delegate_.reset();
316 }
317
318 - (void)closeSettings {
319 [delegate_ closeSettings];
320 }
321
322 - (void)popViewControllerOrCloseSettingsAnimated:(BOOL)animated {
323 if (self.viewControllers.count > 1) {
324 // Pop the top view controller to reveal the view controller underneath.
325 [self popViewControllerAnimated:animated];
326 } else {
327 // If there is only one view controller in the navigation stack,
328 // simply close settings.
329 [self closeSettings];
330 }
331 }
332
333 - (void)configureUI {
334 [self setModalPresentationStyle:UIModalPresentationFormSheet];
335 [self setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
336 // Since the navigation bar is hidden, the gesture to swipe to go back can
337 // become inactive. Setting the delegate to self is an MDC workaround to have
338 // it consistently work with AppBar.
339 // https://github.com/material-components/material-components-ios/issues/720
340 [self setNavigationBarHidden:YES];
341 [self.interactivePopGestureRecognizer setDelegate:self];
342 }
343
344 - (BOOL)hasRightDoneButton {
345 UIBarButtonItem* rightButton =
346 self.topViewController.navigationItem.rightBarButtonItem;
347 if (!rightButton)
348 return NO;
349 base::scoped_nsobject<UIBarButtonItem> doneButton([self doneButton]);
350 return [rightButton style] == [doneButton style] &&
351 [[rightButton title] compare:[doneButton title]] == NSOrderedSame;
352 }
353
354 - (UIBarButtonItem*)doneButton {
355 // Create a custom Done bar button item, as Material Navigation Bar does not
356 // handle a system UIBarButtonSystemItemDone item.
357 return [[[UIBarButtonItem alloc]
358 initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON)
359 style:UIBarButtonItemStyleDone
360 target:self
361 action:@selector(closeSettings)] autorelease];
362 }
363
364 - (UIBarButtonItem*)closeButton {
365 UIBarButtonItem* closeButton =
366 [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon closeIcon]
367 target:self
368 action:@selector(closeSettings)];
369 closeButton.accessibilityLabel = l10n_util::GetNSString(IDS_ACCNAME_CLOSE);
370 return closeButton;
371 }
372
373 - (UIBarButtonItem*)cancelButton {
374 // Create a custom Cancel bar button item, as Material Navigation Bar does not
375 // handle a system UIBarButtonSystemItemCancel item.
376 return [[[UIBarButtonItem alloc]
377 initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_CANCEL_BUTTON)
378 style:UIBarButtonItemStyleDone
379 target:self
380 action:@selector(closeSettings)] autorelease];
381 }
382
383 - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
384 return [self.topViewController supportedInterfaceOrientations];
385 }
386
387 - (BOOL)shouldAutorotate {
388 return [self.topViewController shouldAutorotate];
389 }
390
391 #pragma mark - UIGestureRecognizerDelegate
392
393 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer {
394 DCHECK_EQ(gestureRecognizer, self.interactivePopGestureRecognizer);
395 return self.viewControllers.count > 1;
396 }
397
398 #pragma mark - Accessibility
399
400 - (BOOL)accessibilityPerformEscape {
401 UIViewController* poppedController = [self popViewControllerAnimated:YES];
402 if (!poppedController)
403 [self closeSettings];
404 return YES;
405 }
406
407 #pragma mark - UINavigationController
408
409 - (void)pushViewController:(UIViewController*)viewController
410 animated:(BOOL)animated {
411 // Wrap the view controller in an MDCAppBarContainerViewController if needed.
412 [super pushViewController:[self wrappedControllerIfNeeded:viewController]
413 animated:animated];
414 }
415
416 - (UIViewController*)popViewControllerAnimated:(BOOL)animated {
417 UIViewController* viewController = [super popViewControllerAnimated:animated];
418 // Unwrap the view controller from its MDCAppBarContainerViewController if
419 // needed.
420 return [self unwrappedControllerIfNeeded:viewController];
421 }
422
423 - (NSArray*)popToViewController:(UIViewController*)viewController
424 animated:(BOOL)animated {
425 // First, check if the view controller was wrapped in an app bar container.
426 MDCAppBarContainerViewController* appBarContainer =
427 [self appBarContainerForController:viewController];
428 // Pop the view controllers.
429 NSArray* poppedViewControllers =
430 [super popToViewController:appBarContainer ?: viewController
431 animated:animated];
432 // Unwrap the popped view controllers from their
433 // MDCAppBarContainerViewController if needed.
434 NSMutableArray* viewControllers = [NSMutableArray array];
435 [poppedViewControllers
436 enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* stop) {
437 [viewControllers
438 addObject:[self unwrappedControllerIfNeeded:viewController]];
439 }];
440 return viewControllers;
441 }
442
443 // Ensures that the keyboard is always dismissed during a navigation transition.
444 - (BOOL)disablesAutomaticKeyboardDismissal {
445 return NO;
446 }
447
448 #pragma mark - UIResponder (ChromeExecuteCommand)
449
450 - (void)chromeExecuteCommand:(id)sender {
451 switch ([sender tag]) {
452 case IDC_CLOSE_SETTINGS: {
453 [delegate_ closeSettings];
454 return;
455 }
456 case IDC_OPEN_URL:
457 NOTREACHED() << "You should probably use the command "
458 << "IDC_CLOSE_SETTINGS_AND_OPEN_URL instead of IDC_OPEN_URL";
459 case IDC_CLOSE_SETTINGS_AND_OPEN_URL: {
460 [delegate_ closeSettingsAndOpenUrl:sender];
461 return;
462 }
463 case IDC_CLOSE_SETTINGS_AND_OPEN_NEW_INCOGNITO_TAB: {
464 [delegate_ closeSettingsAndOpenNewIncognitoTab];
465 return;
466 }
467 case IDC_SHOW_SIGNIN_IOS:
468 // Sign-in actions can only happen on the main browser state (not on
469 // incognito browser state), which is unique. The command can just be
470 // forwarded up the responder chain.
471 break;
472 case IDC_CLEAR_BROWSING_DATA_IOS: {
473 // Check that the data for the right browser state is being cleared before
474 // forwarding it up the responder chain.
475 ios::ChromeBrowserState* commandBrowserState =
476 [base::mac::ObjCCast<ClearBrowsingDataCommand>(sender) browserState];
477
478 // Clearing browsing data for the wrong profile is a destructive action.
479 // Executing it on the wrong profile is a privacy issue. Kill the
480 // app if this ever happens.
481 CHECK_EQ(commandBrowserState, [self mainBrowserState]);
482 break;
483 }
484 case IDC_RESET_ALL_WEBVIEWS:
485 // The command to reset all webview is not related to the browser state so
486 // it can just be forwarded it up the responder chain.
487 break;
488 case IDC_SHOW_ACCOUNTS_SETTINGS: {
489 base::scoped_nsobject<UIViewController> controller(
490 [[AccountsCollectionViewController alloc]
491 initWithBrowserState:mainBrowserState_
492 closeSettingsOnAddAccount:NO]);
493 [self pushViewController:controller animated:YES];
494 return;
495 }
496 case IDC_SHOW_SYNC_SETTINGS: {
497 base::scoped_nsobject<UIViewController> controller(
498 [[SyncSettingsCollectionViewController alloc]
499 initWithBrowserState:mainBrowserState_
500 allowSwitchSyncAccount:YES]);
501 [self pushViewController:controller animated:YES];
502 return;
503 }
504 case IDC_SHOW_SYNC_PASSPHRASE_SETTINGS: {
505 base::scoped_nsobject<UIViewController> controller(
506 [[SyncEncryptionPassphraseCollectionViewController alloc]
507 initWithBrowserState:mainBrowserState_]);
508 [self pushViewController:controller animated:YES];
509 return;
510 }
511 default:
512 NOTREACHED()
513 << "Unexpected command " << [sender tag]
514 << " Settings commands must execute on the main browser state.";
515 }
516 [[self nextResponder] chromeExecuteCommand:sender];
517 }
518
519 #pragma mark - UIResponder
520
521 - (NSArray*)keyCommands {
522 base::WeakNSObject<SettingsNavigationController> weakSelf(self);
523 return @[
524 [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape
525 modifierFlags:Cr_UIKeyModifierNone
526 title:nil
527 action:^{
528 [weakSelf closeSettings];
529 }],
530 ];
531 }
532
533 #pragma mark - Profile
534
535 - (ios::ChromeBrowserState*)mainBrowserState {
536 return mainBrowserState_;
537 }
538
539 #pragma mark - Status bar
540
541 - (BOOL)modalPresentationCapturesStatusBarAppearance {
542 if (!base::ios::IsRunningOnIOS10OrLater()) {
543 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is
544 // dropped.
545 return YES;
546 } else {
547 return [super modalPresentationCapturesStatusBarAppearance];
548 }
549 }
550
551 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
552 [super traitCollectionDidChange:previousTraitCollection];
553 if (!base::ios::IsRunningOnIOS10OrLater()) {
554 // TODO(crbug.com/620361): Remove the entire method override when iOS 9 is
555 // dropped.
556 [self setNeedsStatusBarAppearanceUpdate];
557 }
558 }
559
560 #pragma mark - AppBar Containment
561
562 // If viewController doesn't implement the AppBarPresenting protocol, it is
563 // wrapped in an MDCAppBarContainerViewController, which is returned. Otherwise,
564 // viewController is returned.
565 - (UIViewController*)wrappedControllerIfNeeded:(UIViewController*)controller {
566 // If the controller can't be presented with an app bar, it needs to be
567 // wrapped in an MDCAppBarContainerViewController.
568 if (![controller conformsToProtocol:@protocol(AppBarPresenting)]) {
569 MDCAppBarContainerViewController* appBarContainer =
570 [[[SettingsAppBarContainerViewController alloc]
571 initWithContentViewController:controller] autorelease];
572
573 // Configure the style.
574 ConfigureAppBarWithCardStyle(appBarContainer.appBar);
575
576 // Adjust the frame of the contained view controller's view to be below the
577 // app bar.
578 CGRect contentFrame = controller.view.frame;
579 CGSize headerSize = [appBarContainer.appBar.headerViewController.headerView
580 sizeThatFits:contentFrame.size];
581 contentFrame = UIEdgeInsetsInsetRect(
582 contentFrame, UIEdgeInsetsMake(headerSize.height, 0, 0, 0));
583 controller.view.frame = contentFrame;
584
585 // Register the app bar container and return it.
586 [self registerAppBarContainer:appBarContainer];
587 return appBarContainer;
588 } else {
589 return controller;
590 }
591 }
592
593 // If controller is an MDCAppBarContainerViewController, it returns its content
594 // view controller. Otherwise, it returns viewController.
595 - (UIViewController*)unwrappedControllerIfNeeded:(UIViewController*)controller {
596 MDCAppBarContainerViewController* potentialAppBarController =
597 base::mac::ObjCCast<MDCAppBarContainerViewController>(controller);
598 if (potentialAppBarController) {
599 // Unregister the app bar container and return it.
600 [self unregisterAppBarContainer:potentialAppBarController];
601 return [potentialAppBarController contentViewController];
602 } else {
603 return controller;
604 }
605 }
606
607 // Adds an app bar container in a dictionary mapping its content view
608 // controller's pointer to itself.
609 - (void)registerAppBarContainer:(MDCAppBarContainerViewController*)container {
610 if (!appBarContainedViewControllers_) {
611 appBarContainedViewControllers_.reset([[NSMutableDictionary alloc] init]);
612 }
613 NSValue* key = [self keyForController:[container contentViewController]];
614 [appBarContainedViewControllers_ setObject:container forKey:key];
615 }
616
617 // Removes the app bar container entry from the aforementioned dictionary.
618 - (void)unregisterAppBarContainer:(MDCAppBarContainerViewController*)container {
619 NSValue* key = [self keyForController:[container contentViewController]];
620 [appBarContainedViewControllers_ removeObjectForKey:key];
621 }
622
623 // Returns the app bar container containing |controller| if it is contained.
624 // Otherwise, returns nil.
625 - (MDCAppBarContainerViewController*)appBarContainerForController:
626 (UIViewController*)controller {
627 NSValue* key = [self keyForController:controller];
628 return [appBarContainedViewControllers_ objectForKey:key];
629 }
630
631 // Returns the dictionary key to use when dealing with |controller|.
632 - (NSValue*)keyForController:(UIViewController*)controller {
633 return [NSValue valueWithPointer:controller];
634 }
635
636 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698