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

Side by Side Diff: ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.mm

Issue 2586993002: Upstream Chrome on iOS source code [3/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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/bookmarks/bookmark_home_handset_view_controller.h "
6
7 #include <memory>
8
9 #import "base/ios/weak_nsobject.h"
10 #include "base/logging.h"
11 #include "base/mac/objc_property_releaser.h"
12 #include "base/mac/scoped_nsobject.h"
13 #include "base/metrics/user_metrics.h"
14 #include "base/metrics/user_metrics_action.h"
15 #include "base/strings/sys_string_conversions.h"
16 #include "components/bookmarks/browser/bookmark_model.h"
17 #include "components/strings/grit/components_strings.h"
18 #include "google_apis/gaia/google_service_auth_error.h"
19 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h"
20 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
21 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
22 #import "ios/chrome/browser/ui/bookmarks/bars/bookmark_editing_bar.h"
23 #import "ios/chrome/browser/ui/bookmarks/bars/bookmark_navigation_bar.h"
24 #import "ios/chrome/browser/ui/bookmarks/bookmark_all_collection_view.h"
25 #import "ios/chrome/browser/ui/bookmarks/bookmark_collection_cells.h"
26 #import "ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h"
27 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_collection_view.h"
28 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller. h"
29 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
30 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_primary_view.h"
31 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_waiting_view.h"
32 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_item.h"
33 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_view.h"
34 #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
35 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
36 #import "ios/chrome/browser/ui/bookmarks/bookmark_panel_view.h"
37 #import "ios/chrome/browser/ui/bookmarks/bookmark_position_cache.h"
38 #import "ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.h"
39 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
40 #include "ios/chrome/browser/ui/ui_util.h"
41 #import "ios/chrome/browser/ui/uikit_ui_util.h"
42 #include "ios/chrome/grit/ios_strings.h"
43 #include "ui/base/l10n/l10n_util.h"
44 #include "ui/base/l10n/l10n_util_mac.h"
45
46 using bookmarks::BookmarkNode;
47
48 namespace {
49 const CGFloat kBookmarkMenuWidth = 264;
50 } // namespace
51
52 @interface BookmarkHomeHandsetViewController ()<
53 BookmarkEditViewControllerDelegate,
54 BookmarkFolderCollectionViewDelegate,
55 BookmarkFolderEditorViewControllerDelegate,
56 BookmarkFolderViewControllerDelegate,
57 BookmarkMenuViewDelegate,
58 BookmarkModelBridgeObserver,
59 BookmarkPanelViewDelegate,
60 BookmarkPromoControllerDelegate> {
61 // Bridge to register for bookmark changes.
62 std::unique_ptr<bookmarks::BookmarkModelBridge> _bridge;
63 base::mac::ObjCPropertyReleaser
64 _propertyReleaser_BookmarkHomeHandsetViewController;
65 }
66
67 // This views holds the primary content of this view controller. At any point in
68 // time, it contains exactly one of the BookmarkCollectionView subclasses.
69 @property(nonatomic, retain) UIView* contentView;
70 // The possible views that can be shown from the menu.
71 @property(nonatomic, retain) BookmarkAllCollectionView* allItemsView;
72 @property(nonatomic, retain) BookmarkFolderCollectionView* folderView;
73 // This view is created and used if the model is not fully loaded yet by the
74 // time this controller starts.
75 @property(nonatomic, retain) BookmarkHomeWaitingView* waitForModelView;
76
77 // The menu with all the folders and special entries.
78 @property(nonatomic, retain) BookmarkMenuView* menuView;
79 // At any point in time, there is exactly one collection view whose view is part
80 // of the view hierarchy. This property determine which collection view is
81 // visible. Not by accident, this property also reflects the selected menu item
82 // in the BookmarkMenuView.
83 @property(nonatomic, retain) BookmarkMenuItem* primaryMenuItem;
84 // When the view is first shown on the screen, this property represents the
85 // cached value of the y of the content offset of the primary view. This
86 // property is set to nil after it is used.
87 @property(nonatomic, retain) NSNumber* cachedContentPosition;
88
89 // The navigation bar sits on top of the main content.
90 @property(nonatomic, retain) BookmarkNavigationBar* navigationBar;
91 // The layout code in this class relies on the assumption that the editingBar
92 // has the same frame as the navigationBar.
93 @property(nonatomic, retain) BookmarkEditingBar* editingBar;
94
95 // The action sheet coordinator used when trying to edit a single bookmark.
96 @property(nonatomic, retain) ActionSheetCoordinator* actionSheetCoordinator;
97 // The view controller used to view and edit a single bookmark.
98 @property(nonatomic, retain) BookmarkEditViewController* editViewController;
99 // The view controller used to pick a folder in which to move the selected
100 // bookmarks.
101 @property(nonatomic, retain) BookmarkFolderViewController* folderSelector;
102 // The view controller to present when editing the current folder.
103 @property(nonatomic, retain) BookmarkFolderEditorViewController* folderEditor;
104 #pragma mark Specific to this class.
105
106 // The panel view slides on top of the content to display the menu.
107 @property(nonatomic, retain) BookmarkPanelView* panelView;
108
109 // Either the menu or the primaryView can scrollToTop.
110 @property(nonatomic, assign) BOOL scrollingMenuToTop;
111 // The controller managing the display of the promo cell and the promo view
112 // controller.
113 @property(nonatomic, retain) BookmarkPromoController* bookmarkPromoController;
114
115 #pragma mark View loading and switching
116 // This method is called if the view needs to be loaded and the model is not
117 // ready yet.
118 - (void)loadWaitingView;
119 // This method should be called at most once in the life-cycle of the
120 // class. It should be called at the soonest possible time after the
121 // view has been loaded, and the bookmark model is loaded.
122 - (void)loadBookmarkViews;
123 // If the view doesn't exist, create it.
124 - (void)ensureAllViewExists;
125 - (void)ensureFolderViewExists;
126 // Updates the property 'primaryMenuItem'.
127 // Updates the UI to reflect the new state of 'primaryMenuItem'.
128 - (void)updatePrimaryMenuItem:(BookmarkMenuItem*)menuItem
129 animated:(BOOL)animated;
130
131 #pragma mark Editing related methods
132 // This method statelessly updates the editing top bar from |_editNodes| and
133 // |editing|.
134 - (void)updateEditingStateAnimated:(BOOL)animated;
135 // Shows or hides the editing bar.
136 - (void)showEditingBarAnimated:(BOOL)animated;
137 - (void)hideEditingBarAnimated:(BOOL)animated;
138 // Instaneously updates the shadow of the edit bar.
139 // This method should be called anytime:
140 // (1)|editing| property changes.
141 // (2)The primary view changes.
142 // (3)The primary view's collection view is scrolled.
143 // (2) is not necessary right now, as it is only possible to switch primary
144 // views when |editing| is NO. When |editing| is NO, the shadow is never shown.
145 - (void)updateEditBarShadow;
146
147 #pragma mark Editing bar callbacks
148 // The cancel button was tapped on the editing bar.
149 - (void)editingBarCancel;
150 // The move button was tapped on the editing bar.
151 - (void)editingBarMove;
152 // The delete button was tapped on the editing bar.
153 - (void)editingBarDelete;
154 // The edit button was tapped on the editing bar.
155 - (void)editingBarEdit;
156
157 #pragma mark Action sheet callbacks
158 // Enters into edit mode by selecting the given node and cell.
159 - (void)selectFirstNode:(const BookmarkNode*)node
160 withCell:(UICollectionViewCell*)cell;
161 // Opens the editor on the given node with a transition from cell.
162 - (void)editNode:(const BookmarkNode*)node;
163 // Opens the folder move editor for the given node.
164 - (void)moveNodes:(const std::set<const BookmarkNode*>&)nodes;
165 // Deletes the current node.
166 - (void)deleteNodes:(const std::set<const BookmarkNode*>&)nodes;
167
168 #pragma mark private utility methods
169 // Deletes the nodes, and presents a toast with an undo button.
170 - (void)deleteSelectedNodes;
171
172 #pragma mark Navigation bar
173 // Updates the UI of the navigation bar with the primaryMenuItem.
174 // This method should be called anytime:
175 // (1)The primary view changes.
176 // (2)The menu is shown or hidden.
177 // (3)The primary view has type folder, and the relevant folder has changed.
178 // (4)The interface orientation changes.
179 // (5)viewWillAppear, as the interface orientation may have changed.
180 - (void)updateNavigationBarAnimated:(BOOL)animated
181 orientation:(UIInterfaceOrientation)orientation;
182 - (void)updateNavigationBarWithDuration:(CGFloat)duration
183 orientation:(UIInterfaceOrientation)orientation;
184 // Whether the edit button on the navigation bar should be shown.
185 - (BOOL)shouldShowEditButtonWithMenuVisibility:(BOOL)visible;
186 // Whether the back button on the navigation bar should be preferred to the menu
187 // button.
188 - (BOOL)shouldShowBackButtonInsteadOfMenuButton;
189 // Called when the edit button is pressed on the navigation bar.
190 - (void)navigationBarWantsEditing:(id)sender;
191 // Called when the cancel button is pressed on the navigation bar.
192 - (void)navigationBarCancel:(id)sender;
193 // Called when the menu button is pressed on the navigation bar.
194 - (void)navigationBarToggledMenu:(id)sender;
195 // Called when the back button is pressed on the navigation bar.
196 - (void)navigationBarBack:(id)sender;
197
198 #pragma mark private methods
199 // The active collection view that corresponds to primaryMenuItem.
200 // This must be implemented by subclass.
201 - (UIView<BookmarkHomePrimaryView>*)primaryView;
202 // Returns the size of the primary view.
203 - (CGRect)frameForPrimaryView;
204 // Updates the UI to reflect the given orientation, with an animation lasting
205 // |duration|.
206 - (void)updateUIForInterfaceOrientation:(UIInterfaceOrientation)orientation
207 duration:(NSTimeInterval)duration;
208 // Shows or hides the menu.
209 - (void)showMenuAnimated:(BOOL)animated;
210 - (void)hideMenuAnimated:(BOOL)animated updateNavigationBar:(BOOL)update;
211
212 // Saves the current position and asks the delegate to open the url.
213 - (void)delegateDismiss:(const GURL&)url;
214
215 // TODO(crbug.com/450646): This should not be needed but require refactoring of
216 // the BookmarkCollectionViewDelegate.
217 - (NSIndexPath*)indexPathForCell:(UICollectionViewCell*)cell;
218
219 @end
220
221 @implementation BookmarkHomeHandsetViewController
222 @synthesize allItemsView = _allItemsView;
223 @synthesize contentView = _contentView;
224 @synthesize folderView = _folderView;
225 @synthesize waitForModelView = _waitForModelView;
226
227 @synthesize menuView = _menuView;
228 @synthesize primaryMenuItem = _primaryMenuItem;
229 @synthesize cachedContentPosition = _cachedContentPosition;
230 @synthesize navigationBar = _navigationBar;
231 @synthesize editingBar = _editingBar;
232
233 @synthesize actionSheetCoordinator = _actionSheetCoordinator;
234 @synthesize editViewController = _editViewController;
235 @synthesize folderSelector = _folderSelector;
236 @synthesize folderEditor = _folderEditor;
237
238 @synthesize panelView = _panelView;
239 @synthesize scrollingMenuToTop = _scrollingMenuToTop;
240 @synthesize bookmarkPromoController = _bookmarkPromoController;
241
242 - (instancetype)initWithLoader:(id<UrlLoader>)loader
243 browserState:(ios::ChromeBrowserState*)browserState {
244 self = [super initWithLoader:loader browserState:browserState];
245 if (self) {
246 _propertyReleaser_BookmarkHomeHandsetViewController.Init(
247 self, [BookmarkHomeHandsetViewController class]);
248
249 _bridge.reset(new bookmarks::BookmarkModelBridge(self, self.bookmarks));
250 // It is important to initialize the promo controller with the browser state
251 // passed in, as it could be incognito.
252 _bookmarkPromoController =
253 [[BookmarkPromoController alloc] initWithBrowserState:browserState
254 delegate:self];
255 }
256 return self;
257 }
258
259 - (void)dealloc {
260 _allItemsView.delegate = nil;
261 _folderView.delegate = nil;
262
263 _menuView.delegate = nil;
264
265 _editViewController.delegate = nil;
266 _folderSelector.delegate = nil;
267
268 _panelView.delegate = nil;
269 [super dealloc];
270 }
271
272 - (void)removeEditNode:(const BookmarkNode*)node
273 cell:(UICollectionViewCell*)cell {
274 [super removeEditNode:node atIndexPath:[self indexPathForCell:cell]];
275 if (_editNodes.size() == 0)
276 [self setEditing:NO animated:YES];
277 else
278 [self updateEditingStateAnimated:YES];
279 }
280
281 #pragma mark - UIViewController methods
282
283 - (void)viewDidLoad {
284 [super viewDidLoad];
285
286 base::scoped_nsobject<BookmarkNavigationBar> bar(
287 [[BookmarkNavigationBar alloc] initWithFrame:[self navigationBarFrame]]);
288 self.navigationBar = bar;
289 [self.navigationBar setEditTarget:self
290 action:@selector(navigationBarWantsEditing:)];
291 [self.navigationBar setMenuTarget:self
292 action:@selector(navigationBarToggledMenu:)];
293 [self.navigationBar setBackTarget:self action:@selector(navigationBarBack:)];
294 [self.navigationBar setCancelTarget:self
295 action:@selector(navigationBarCancel:)];
296
297 [self.view addSubview:self.navigationBar];
298 [self.view bringSubviewToFront:self.navigationBar];
299
300 if (self.bookmarks->loaded())
301 [self loadBookmarkViews];
302 else
303 [self loadWaitingView];
304 }
305
306 - (BOOL)prefersStatusBarHidden {
307 return NO;
308 }
309
310 #pragma mark - Accessibility
311
312 - (BOOL)accessibilityPerformEscape {
313 [self delegateDismiss:GURL()];
314 return YES;
315 }
316
317 #pragma mark - Methods duplicated from BookmarkHomeTabletNTPController.
318
319 - (void)loadWaitingView {
320 DCHECK(!self.waitForModelView);
321 DCHECK([self isViewLoaded]);
322
323 // Present a waiting view.
324 base::scoped_nsobject<BookmarkHomeWaitingView> waitingView(
325 [[BookmarkHomeWaitingView alloc] initWithFrame:self.view.bounds]);
326 self.waitForModelView = waitingView;
327 [self.view addSubview:self.waitForModelView];
328 [self.waitForModelView startWaiting];
329 }
330
331 - (void)loadBookmarkViews {
332 DCHECK(self.bookmarks->loaded());
333 DCHECK([self isViewLoaded]);
334
335 self.panelView = base::scoped_nsobject<BookmarkPanelView>(
336 [[BookmarkPanelView alloc] initWithFrame:[self frameForPrimaryView]
337 menuViewWidth:kBookmarkMenuWidth]);
338 self.panelView.autoresizingMask =
339 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
340 self.panelView.delegate = self;
341 [self.view insertSubview:self.panelView atIndex:0];
342
343 self.contentView = base::scoped_nsobject<UIView>([[UIView alloc] init]);
344 self.contentView.frame = self.panelView.contentView.bounds;
345 self.contentView.autoresizingMask =
346 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
347 [self.panelView.contentView addSubview:self.contentView];
348
349 // The user can swipe the BookmarkPanelView to show the menuView.
350 // Therefore, it must be created here.
351 self.menuView =
352 base::scoped_nsobject<BookmarkMenuView>([[BookmarkMenuView alloc]
353 initWithBrowserState:self.browserState
354 frame:self.panelView.menuView.bounds]);
355 self.menuView.delegate = self;
356 [self.panelView.menuView addSubview:self.menuView];
357 self.menuView.autoresizingMask =
358 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
359
360 // Load the last primary menu item which the user had active.
361 BookmarkMenuItem* item = nil;
362 CGFloat position = 0;
363 BOOL found =
364 bookmark_utils_ios::GetPositionCache(self.bookmarks, &item, &position);
365 if (!found)
366 item = [self.menuView defaultMenuItem];
367
368 [self updatePrimaryMenuItem:item animated:NO];
369
370 if (found) {
371 // If the view has already been laid out, then immediately apply the content
372 // position.
373 if (self.view.window) {
374 [[self primaryView] applyContentPosition:position];
375 } else {
376 // Otherwise, save the position to be applied once the view has been laid
377 // out.
378 self.cachedContentPosition = [NSNumber numberWithFloat:position];
379 }
380 }
381 }
382
383 - (void)ensureAllViewExists {
384 if (self.allItemsView)
385 return;
386
387 base::scoped_nsobject<BookmarkAllCollectionView> view(
388 [[BookmarkAllCollectionView alloc]
389 initWithBrowserState:self.browserState
390 frame:[self frameForPrimaryView]]);
391 self.allItemsView = view;
392 self.allItemsView.delegate = self;
393 [self.allItemsView setEditing:self.editing animated:NO];
394 self.allItemsView.autoresizingMask =
395 UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
396 }
397
398 - (void)ensureFolderViewExists {
399 if (self.folderView)
400 return;
401
402 base::scoped_nsobject<BookmarkFolderCollectionView> view(
403 [[BookmarkFolderCollectionView alloc]
404 initWithBrowserState:self.browserState
405 frame:[self frameForPrimaryView]]);
406 self.folderView = view;
407 self.folderView.delegate = self;
408 [self.folderView setEditing:self.editing animated:NO];
409 self.folderView.autoresizingMask =
410 UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
411 }
412
413 - (void)updatePrimaryMenuItem:(BookmarkMenuItem*)menuItem
414 animated:(BOOL)animated {
415 if ([self.primaryMenuItem isEqual:menuItem])
416 return;
417
418 // Disable editing on previous primary view before dismissing it. No need to
419 // animate because this view is immediately removed from hierarchy.
420 [self.primaryView setEditing:NO animated:NO];
421
422 [[self primaryView] removeFromSuperview];
423 self.primaryMenuItem = menuItem;
424
425 switch (self.primaryMenuItem.type) {
426 case bookmarks::MenuItemAll:
427 [self ensureAllViewExists];
428 break;
429 case bookmarks::MenuItemFolder:
430 [self ensureFolderViewExists];
431 [self.folderView resetFolder:self.primaryMenuItem.folder];
432 [self.folderView promoStateChangedAnimated:NO];
433 break;
434 case bookmarks::MenuItemDivider:
435 case bookmarks::MenuItemSectionHeader:
436 NOTREACHED();
437 break;
438 }
439
440 UIView* primaryView = [self primaryView];
441 [[self primaryView] changeOrientation:GetInterfaceOrientation()];
442 [[self primaryView] setScrollsToTop:!self.scrollingMenuToTop];
443
444 [self.contentView insertSubview:primaryView atIndex:0];
445 primaryView.frame = self.contentView.bounds;
446
447 [self updateNavigationBarAnimated:animated
448 orientation:GetInterfaceOrientation()];
449
450 [self.menuView updatePrimaryMenuItem:self.primaryMenuItem];
451 }
452
453 - (UIView<BookmarkHomePrimaryView>*)primaryView {
454 switch (self.primaryMenuItem.type) {
455 case bookmarks::MenuItemAll:
456 return self.allItemsView;
457 case bookmarks::MenuItemFolder:
458 return self.folderView;
459 case bookmarks::MenuItemDivider:
460 case bookmarks::MenuItemSectionHeader:
461 NOTREACHED();
462 return nil;
463 }
464 }
465
466 #pragma mark - Editing bar methods.
467
468 - (void)updateEditingStateAnimated:(BOOL)animated {
469 if (!self.editing) {
470 [self hideEditingBarAnimated:animated];
471 [self updateEditBarShadow];
472 [self.panelView enableSideSwiping:YES];
473 return;
474 }
475
476 if (!self.editingBar) {
477 self.editingBar = base::scoped_nsobject<BookmarkEditingBar>(
478 [[BookmarkEditingBar alloc] initWithFrame:self.navigationBar.frame]);
479 [self.editingBar setCancelTarget:self action:@selector(editingBarCancel)];
480 [self.editingBar setDeleteTarget:self action:@selector(editingBarDelete)];
481 [self.editingBar setMoveTarget:self action:@selector(editingBarMove)];
482 [self.editingBar setEditTarget:self action:@selector(editingBarEdit)];
483
484 [self.view addSubview:self.editingBar];
485 self.editingBar.alpha = 0;
486 }
487
488 int bookmarkCount = 0;
489 int folderCount = 0;
490 for (auto node : _editNodes) {
491 if (node->is_url())
492 ++bookmarkCount;
493 else
494 ++folderCount;
495 }
496 [self.editingBar updateUIWithBookmarkCount:bookmarkCount
497 folderCount:folderCount];
498
499 [self showEditingBarAnimated:animated];
500 [self updateEditBarShadow];
501 [self.panelView enableSideSwiping:NO];
502 }
503
504 - (void)setEditing:(BOOL)editing animated:(BOOL)animated {
505 [super setEditing:editing animated:animated];
506
507 [self updateEditingStateAnimated:animated];
508 if ([[self primaryMenuItem] supportsEditing])
509 [[self primaryView] setEditing:editing animated:animated];
510
511 if (editing)
512 self.bookmarkPromoController.promoState = NO;
513 else
514 [self.bookmarkPromoController updatePromoState];
515 }
516
517 - (void)showEditingBarAnimated:(BOOL)animated {
518 CGRect frame = self.navigationBar.frame;
519 self.editingBar.hidden = NO;
520 if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)])
521 [self setNeedsStatusBarAppearanceUpdate];
522 [UIView animateWithDuration:animated ? 0.2 : 0
523 delay:0
524 options:UIViewAnimationOptionBeginFromCurrentState
525 animations:^{
526 self.editingBar.alpha = 1;
527 self.editingBar.frame = frame;
528 }
529 completion:^(BOOL finished) {
530 if (finished) {
531 self.navigationBar.hidden = YES;
532 } else {
533 if ([self respondsToSelector:@selector(
534 setNeedsStatusBarAppearanceUpdate)])
535 [self setNeedsStatusBarAppearanceUpdate];
536 }
537 }];
538 }
539
540 - (void)hideEditingBarAnimated:(BOOL)animated {
541 CGRect frame = self.navigationBar.frame;
542 self.navigationBar.hidden = NO;
543 if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)])
544 [self setNeedsStatusBarAppearanceUpdate];
545 [UIView animateWithDuration:animated ? 0.2 : 0
546 delay:0
547 options:UIViewAnimationOptionBeginFromCurrentState
548 animations:^{
549 self.editingBar.alpha = 0;
550 self.editingBar.frame = frame;
551 }
552 completion:^(BOOL finished) {
553 if (finished) {
554 self.editingBar.hidden = YES;
555 } else {
556 if ([self respondsToSelector:@selector(
557 setNeedsStatusBarAppearanceUpdate)])
558 [self setNeedsStatusBarAppearanceUpdate];
559 }
560 }];
561 }
562
563 - (void)updateEditBarShadow {
564 [self.editingBar showShadow:self.editing];
565 }
566
567 #pragma mark Editing Bar Callbacks
568
569 - (void)editingBarCancel {
570 [self setEditing:NO animated:YES];
571 }
572
573 - (void)editingBarMove {
574 [self moveNodes:_editNodes];
575 }
576
577 - (void)editingBarDelete {
578 [self deleteSelectedNodes];
579 [self setEditing:NO animated:YES];
580 }
581
582 - (void)editingBarEdit {
583 DCHECK_EQ(_editNodes.size(), 1u);
584 const BookmarkNode* node = *(_editNodes.begin());
585 [self editNode:node];
586 }
587
588 #pragma mark - BookmarkMenuViewDelegate
589
590 - (void)bookmarkMenuView:(BookmarkMenuView*)view
591 selectedMenuItem:(BookmarkMenuItem*)menuItem {
592 BOOL menuItemChanged = ![[self primaryMenuItem] isEqual:menuItem];
593 // If the primary menu item has changed, then updatePrimaryMenuItem: will
594 // update the navigation bar, and there's no need for hideMenuAnimated: to do
595 // so.
596 [self hideMenuAnimated:YES updateNavigationBar:!menuItemChanged];
597 if (menuItemChanged)
598 [self updatePrimaryMenuItem:menuItem animated:YES];
599 }
600
601 #pragma mark - BookmarkCollectionViewDelegate
602 // This class owns multiple views that have a delegate that conforms to
603 // BookmarkCollectionViewDelegate, or a subprotocol of
604 // BookmarkCollectionViewDelegate.
605 - (void)bookmarkCollectionView:(BookmarkCollectionView*)view
606 cell:(UICollectionViewCell*)cell
607 addNodeForEditing:(const BookmarkNode*)node {
608 [self insertEditNode:node atIndexPath:[self indexPathForCell:cell]];
609 [self updateEditingStateAnimated:YES];
610 }
611
612 - (void)bookmarkCollectionView:(BookmarkCollectionView*)view
613 cell:(UICollectionViewCell*)cell
614 removeNodeForEditing:(const BookmarkNode*)node {
615 [self removeEditNode:node atIndexPath:[self indexPathForCell:cell]];
616 if (_editNodes.size() == 0)
617 [self setEditing:NO animated:YES];
618 else
619 [self updateEditingStateAnimated:YES];
620 }
621
622 - (const std::set<const BookmarkNode*>&)nodesBeingEdited {
623 return _editNodes;
624 }
625
626 - (void)bookmarkCollectionViewDidScroll:(BookmarkCollectionView*)view {
627 [self updateEditBarShadow];
628 }
629
630 - (void)bookmarkCollectionView:(BookmarkCollectionView*)view
631 selectedUrlForNavigation:(const GURL&)url {
632 [self delegateDismiss:url];
633 }
634
635 - (void)bookmarkCollectionView:(BookmarkCollectionView*)collectionView
636 wantsMenuForBookmark:(const BookmarkNode*)node
637 onView:(UIView*)view
638 forCell:(BookmarkItemCell*)cell {
639 DCHECK(!self.editViewController);
640 DCHECK(!self.actionSheetCoordinator);
641 self.actionSheetCoordinator = [[[ActionSheetCoordinator alloc]
642 initWithBaseViewController:self
643 title:nil
644 message:nil
645 rect:CGRectZero
646 view:nil] autorelease];
647 base::WeakNSObject<BookmarkHomeHandsetViewController> weakSelf(self);
648
649 // Select action.
650 [self.actionSheetCoordinator
651 addItemWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_ACTION_SELECT)
652 action:^{
653 [weakSelf selectFirstNode:node withCell:cell];
654 weakSelf.get().actionSheetCoordinator = nil;
655 }
656 style:UIAlertActionStyleDefault];
657
658 // Edit action.
659 [self.actionSheetCoordinator
660 addItemWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_ACTION_EDIT)
661 action:^{
662 [weakSelf editNode:node];
663 weakSelf.get().actionSheetCoordinator = nil;
664 }
665 style:UIAlertActionStyleDefault];
666
667 // Move action.
668 [self.actionSheetCoordinator
669 addItemWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_ACTION_MOVE)
670 action:^{
671 std::set<const BookmarkNode*> nodes;
672 nodes.insert(node);
673 [weakSelf moveNodes:nodes];
674 weakSelf.get().actionSheetCoordinator = nil;
675 }
676 style:UIAlertActionStyleDefault];
677
678 // Delete action.
679 [self.actionSheetCoordinator
680 addItemWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_ACTION_DELETE)
681 action:^{
682 std::set<const BookmarkNode*> nodes;
683 nodes.insert(node);
684 [weakSelf deleteNodes:nodes];
685 weakSelf.get().actionSheetCoordinator = nil;
686 }
687 style:UIAlertActionStyleDestructive];
688
689 // Cancel action.
690 [self.actionSheetCoordinator
691 addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
692 action:^{
693 weakSelf.get().actionSheetCoordinator = nil;
694 }
695 style:UIAlertActionStyleCancel];
696
697 [self.actionSheetCoordinator start];
698 }
699
700 - (void)bookmarkCollectionView:(BookmarkCollectionView*)view
701 didLongPressCell:(UICollectionViewCell*)cell
702 forBookmark:(const BookmarkNode*)node {
703 [self selectFirstNode:node withCell:cell];
704 }
705
706 - (BOOL)bookmarkCollectionViewShouldShowPromoCell:
707 (BookmarkCollectionView*)collectionView {
708 return self.bookmarkPromoController.promoState;
709 }
710
711 - (void)bookmarkCollectionViewShowSignIn:(BookmarkCollectionView*)view {
712 [self.bookmarkPromoController showSignIn];
713 }
714
715 - (void)bookmarkCollectionViewDismissPromo:(BookmarkCollectionView*)view {
716 [self.bookmarkPromoController hidePromoCell];
717 }
718
719 #pragma mark Action Sheet Callbacks
720
721 - (void)selectFirstNode:(const BookmarkNode*)node
722 withCell:(UICollectionViewCell*)cell {
723 DCHECK(!self.editing);
724 [self insertEditNode:node atIndexPath:[self indexPathForCell:cell]];
725 [self setEditing:YES animated:YES];
726 }
727
728 - (void)editNode:(const BookmarkNode*)node {
729 DCHECK(!self.editViewController);
730 DCHECK(!self.folderEditor);
731 UIViewController* editorController = nil;
732 if (node->is_folder()) {
733 BookmarkFolderEditorViewController* folderEditor =
734 [BookmarkFolderEditorViewController
735 folderEditorWithBookmarkModel:self.bookmarks
736 folder:node
737 browserState:self.browserState];
738 folderEditor.delegate = self;
739 self.folderEditor = folderEditor;
740 editorController = folderEditor;
741 } else {
742 base::scoped_nsobject<BookmarkEditViewController> controller([
743 [BookmarkEditViewController alloc] initWithBookmark:node
744 browserState:self.browserState]);
745 self.editViewController = controller;
746 self.editViewController.delegate = self;
747 editorController = self.editViewController;
748 }
749 DCHECK(editorController);
750 base::scoped_nsobject<UINavigationController> navController(
751 [[BookmarkNavigationController alloc]
752 initWithRootViewController:editorController]);
753 [navController setModalPresentationStyle:UIModalPresentationFormSheet];
754 [self presentViewController:navController animated:YES completion:NULL];
755 }
756
757 - (void)moveNodes:(const std::set<const BookmarkNode*>&)nodes {
758 DCHECK(!self.folderSelector);
759 DCHECK(nodes.size() > 0);
760 const BookmarkNode* editedNode = *(nodes.begin());
761 const BookmarkNode* selectedFolder = editedNode->parent();
762 self.folderSelector = base::scoped_nsobject<BookmarkFolderViewController>(
763 [[BookmarkFolderViewController alloc]
764 initWithBookmarkModel:self.bookmarks
765 allowsNewFolders:YES
766 editedNodes:nodes
767 allowsCancel:YES
768 selectedFolder:selectedFolder]);
769 self.folderSelector.delegate = self;
770 base::scoped_nsobject<UINavigationController> navController(
771 [[BookmarkNavigationController alloc]
772 initWithRootViewController:self.folderSelector]);
773 [navController setModalPresentationStyle:UIModalPresentationFormSheet];
774 [self presentViewController:navController animated:YES completion:NULL];
775 }
776
777 - (void)deleteNodes:(const std::set<const BookmarkNode*>&)nodes {
778 DCHECK_GE(nodes.size(), 1u);
779 bookmark_utils_ios::DeleteBookmarksWithUndoToast(nodes, self.bookmarks,
780 self.browserState);
781 }
782
783 #pragma mark - BookmarkFolderCollectionViewDelegate
784
785 - (void)bookmarkFolderCollectionView:(BookmarkFolderCollectionView*)view
786 selectedFolderForNavigation:(const BookmarkNode*)folder {
787 BookmarkMenuItem* menuItem = nil;
788 if (view == self.folderView) {
789 const BookmarkNode* parent = RootLevelFolderForNode(folder, self.bookmarks);
790 menuItem =
791 [BookmarkMenuItem folderMenuItemForNode:folder rootAncestor:parent];
792 } else {
793 NOTREACHED();
794 return;
795 }
796 [self updatePrimaryMenuItem:menuItem animated:YES];
797 }
798
799 #pragma mark - BookmarkEditViewControllerDelegate
800
801 - (BOOL)bookmarkEditor:(BookmarkEditViewController*)controller
802 shoudDeleteAllOccurencesOfBookmark:(const BookmarkNode*)bookmark {
803 return NO;
804 }
805
806 - (void)bookmarkEditorWantsDismissal:(BookmarkEditViewController*)controller {
807 self.editViewController.delegate = nil;
808 self.editViewController = nil;
809 [self dismissViewControllerAnimated:YES completion:NULL];
810
811 // The editViewController can be displayed from the menu button, or from the
812 // edit button in edit mode. Either way, after it's dismissed, edit mode
813 // should be off.
814 [self setEditing:NO animated:NO];
815 }
816
817 #pragma mark - BookmarkFolderViewControllerDelegate
818
819 - (void)folderPicker:(BookmarkFolderViewController*)folderPicker
820 didFinishWithFolder:(const BookmarkNode*)folder {
821 DCHECK(folder);
822 DCHECK(!folder->is_url());
823 DCHECK_GE(folderPicker.editedNodes.size(), 1u);
824
825 bookmark_utils_ios::MoveBookmarksWithUndoToast(
826 folderPicker.editedNodes, self.bookmarks, folder, self.browserState);
827
828 [self setEditing:NO animated:NO];
829 [self dismissViewControllerAnimated:YES completion:NULL];
830 self.folderSelector.delegate = nil;
831 self.folderSelector = nil;
832 }
833
834 - (void)folderPickerDidCancel:(BookmarkFolderViewController*)folderPicker {
835 [self setEditing:NO animated:NO];
836 [self dismissViewControllerAnimated:YES completion:NULL];
837 self.folderSelector.delegate = nil;
838 self.folderSelector = nil;
839 }
840
841 #pragma mark - BookmarkFolderEditorViewControllerDelegate
842
843 - (void)bookmarkFolderEditor:(BookmarkFolderEditorViewController*)folderEditor
844 didFinishEditingFolder:(const BookmarkNode*)folder {
845 DCHECK(folder);
846 [self dismissViewControllerAnimated:YES completion:nil];
847 self.folderEditor.delegate = nil;
848 self.folderEditor = nil;
849 }
850
851 - (void)bookmarkFolderEditorDidDeleteEditedFolder:
852 (BookmarkFolderEditorViewController*)folderEditor {
853 [self dismissViewControllerAnimated:YES completion:nil];
854 self.folderEditor.delegate = nil;
855 self.folderEditor = nil;
856 }
857
858 - (void)bookmarkFolderEditorDidCancel:
859 (BookmarkFolderEditorViewController*)folderEditor {
860 [self dismissViewControllerAnimated:YES completion:nil];
861 self.folderEditor.delegate = nil;
862 self.folderEditor = nil;
863 }
864
865 #pragma mark - Internal Utility Methods
866
867 - (void)deleteSelectedNodes {
868 [self deleteNodes:_editNodes];
869 }
870
871 #pragma mark - Navigation bar
872
873 - (CGRect)navigationBarFrame {
874 return CGRectMake(0, 0, CGRectGetWidth(self.view.bounds),
875 [BookmarkNavigationBar expectedContentViewHeight] +
876 [self.topLayoutGuide length]);
877 }
878
879 - (void)updateNavigationBarAnimated:(BOOL)animated
880 orientation:(UIInterfaceOrientation)orientation {
881 CGFloat duration = animated ? bookmark_utils_ios::menuAnimationDuration : 0;
882 [self updateNavigationBarWithDuration:duration orientation:orientation];
883 }
884
885 - (void)updateNavigationBarWithDuration:(CGFloat)duration
886 orientation:(UIInterfaceOrientation)orientation {
887 if ([self.panelView userDrivenAnimationInProgress])
888 return;
889
890 [self.navigationBar setTitle:[self.primaryMenuItem titleForNavigationBar]];
891 BOOL isMenuVisible = self.panelView.showingMenu;
892 if ([self shouldShowEditButtonWithMenuVisibility:isMenuVisible])
893 [self.navigationBar showEditButtonWithAnimationDuration:duration];
894 else
895 [self.navigationBar hideEditButtonWithAnimationDuration:duration];
896
897 if ([self shouldShowBackButtonInsteadOfMenuButton])
898 [self.navigationBar showBackButtonInsteadOfMenuButton:duration];
899 else
900 [self.navigationBar showMenuButtonInsteadOfBackButton:duration];
901 }
902
903 - (BOOL)shouldShowEditButtonWithMenuVisibility:(BOOL)visible {
904 if (visible)
905 return NO;
906 if (self.primaryMenuItem.type != bookmarks::MenuItemFolder)
907 return NO;
908 // The type is MenuItemFolder, so it is safe to access |folder|.
909 return !self.bookmarks->is_permanent_node(self.primaryMenuItem.folder);
910 }
911
912 - (BOOL)shouldShowBackButtonInsteadOfMenuButton {
913 if (self.primaryMenuItem.type != bookmarks::MenuItemFolder)
914 return NO;
915 // The type is MenuItemFolder, so it is safe to access |folder|.
916 const BookmarkNode* folder = self.primaryMenuItem.folder;
917 // Show the back button iff the folder or its immediate parent is a permanent
918 // primary folder.
919 BOOL isTopFolder = IsPrimaryPermanentNode(folder, self.bookmarks) ||
920 IsPrimaryPermanentNode(folder->parent(), self.bookmarks);
921 return !isTopFolder;
922 }
923
924 #pragma mark Navigation Bar Callbacks
925
926 - (void)navigationBarWantsEditing:(id)sender {
927 DCHECK(self.primaryMenuItem.type == bookmarks::MenuItemFolder);
928 const BookmarkNode* folder = self.primaryMenuItem.folder;
929 BookmarkFolderEditorViewController* folderEditor =
930 [BookmarkFolderEditorViewController
931 folderEditorWithBookmarkModel:self.bookmarks
932 folder:folder
933 browserState:self.browserState];
934 folderEditor.delegate = self;
935 self.folderEditor = folderEditor;
936
937 base::scoped_nsobject<BookmarkNavigationController> navController(
938 [[BookmarkNavigationController alloc]
939 initWithRootViewController:self.folderEditor]);
940 [navController setModalPresentationStyle:UIModalPresentationFormSheet];
941 [self presentViewController:navController animated:YES completion:NULL];
942 }
943
944 - (void)navigationBarCancel:(id)sender {
945 [self delegateDismiss:GURL()];
946 }
947
948 - (void)navigationBarToggledMenu:(id)sender {
949 if ([self.panelView userDrivenAnimationInProgress])
950 return;
951
952 if (self.panelView.showingMenu)
953 [self hideMenuAnimated:YES updateNavigationBar:YES];
954 else
955 [self showMenuAnimated:YES];
956 }
957
958 - (void)navigationBarBack:(id)sender {
959 DCHECK([self shouldShowBackButtonInsteadOfMenuButton]);
960
961 // Go to the parent folder.
962 DCHECK(self.primaryMenuItem.type == bookmarks::MenuItemFolder);
963 const BookmarkNode* parentFolder = self.primaryMenuItem.folder->parent();
964 const BookmarkNode* rootAncestor =
965 RootLevelFolderForNode(parentFolder, self.bookmarks);
966 BookmarkMenuItem* menuItem =
967 [BookmarkMenuItem folderMenuItemForNode:parentFolder
968 rootAncestor:rootAncestor];
969 [self updatePrimaryMenuItem:menuItem animated:YES];
970 }
971
972 #pragma mark - Other internal methods.
973
974 - (CGRect)frameForPrimaryView {
975 CGFloat margin;
976 if (self.editing)
977 margin = CGRectGetMaxY(self.editingBar.frame);
978 else
979 margin = CGRectGetMaxY(self.navigationBar.frame);
980 CGFloat height = CGRectGetHeight(self.view.frame) - margin;
981 CGFloat width = CGRectGetWidth(self.view.frame);
982 return CGRectMake(0, margin, width, height);
983 }
984
985 - (void)updateUIForInterfaceOrientation:(UIInterfaceOrientation)orientation
986 duration:(NSTimeInterval)duration {
987 [[self primaryView] changeOrientation:orientation];
988 [self updateNavigationBarWithDuration:duration orientation:orientation];
989 }
990
991 - (void)showMenuAnimated:(BOOL)animated {
992 [self.menuView setScrollsToTop:YES];
993 [[self primaryView] setScrollsToTop:NO];
994 self.scrollingMenuToTop = YES;
995 [self.panelView showMenuAnimated:animated];
996 [self updateNavigationBarAnimated:animated
997 orientation:GetInterfaceOrientation()];
998 }
999
1000 - (void)hideMenuAnimated:(BOOL)animated updateNavigationBar:(BOOL)update {
1001 [self.menuView setScrollsToTop:NO];
1002 [[self primaryView] setScrollsToTop:YES];
1003 self.scrollingMenuToTop = NO;
1004 [self.panelView hideMenuAnimated:animated];
1005 if (update) {
1006 UIInterfaceOrientation orient = GetInterfaceOrientation();
1007 [self updateNavigationBarAnimated:animated orientation:orient];
1008 }
1009 }
1010
1011 #pragma mark - BookmarkHomeViewController
1012
1013 - (void)dismissModals:(BOOL)animated {
1014 [self.actionSheetCoordinator stop];
1015 self.actionSheetCoordinator = nil;
1016 }
1017
1018 #pragma mark - BookmarkPanelViewDelegate
1019
1020 - (void)bookmarkPanelView:(BookmarkPanelView*)view
1021 willShowMenu:(BOOL)showMenu
1022 withAnimationDuration:(CGFloat)duration {
1023 if (showMenu) {
1024 [self.menuView setScrollsToTop:YES];
1025 [[self primaryView] setScrollsToTop:NO];
1026 self.scrollingMenuToTop = YES;
1027 } else {
1028 [self.menuView setScrollsToTop:NO];
1029 [[self primaryView] setScrollsToTop:YES];
1030 self.scrollingMenuToTop = NO;
1031 }
1032
1033 if ([self shouldShowEditButtonWithMenuVisibility:showMenu])
1034 [self.navigationBar showEditButtonWithAnimationDuration:duration];
1035 else
1036 [self.navigationBar hideEditButtonWithAnimationDuration:duration];
1037 }
1038
1039 - (void)bookmarkPanelView:(BookmarkPanelView*)view
1040 updatedMenuVisibility:(CGFloat)visibility {
1041 // As the menu becomes more visible, the edit button will always fade out.
1042 if ([self shouldShowEditButtonWithMenuVisibility:NO])
1043 [self.navigationBar updateEditButtonVisibility:1 - visibility];
1044 else
1045 [self.navigationBar updateEditButtonVisibility:0];
1046 }
1047
1048 #pragma mark - BookmarkModelBridgeObserver
1049
1050 - (void)bookmarkModelLoaded {
1051 if (![self isViewLoaded])
1052 return;
1053
1054 DCHECK(self.waitForModelView);
1055 base::WeakNSObject<BookmarkHomeHandsetViewController> weakSelf(self);
1056 [self.waitForModelView stopWaitingWithCompletion:^{
1057 base::scoped_nsobject<BookmarkHomeHandsetViewController> strongSelf(
1058 [weakSelf retain]);
1059 // Early return if the controller has been deallocated.
1060 if (!strongSelf)
1061 return;
1062 [UIView animateWithDuration:0.2
1063 animations:^{
1064 strongSelf.get().waitForModelView.alpha = 0.0;
1065 }
1066 completion:^(BOOL finished) {
1067 [strongSelf.get().waitForModelView removeFromSuperview];
1068 strongSelf.get().waitForModelView = nil;
1069 }];
1070 [strongSelf loadBookmarkViews];
1071 }];
1072 }
1073
1074 - (void)bookmarkNodeChanged:(const BookmarkNode*)node {
1075 // The title of the folder may have changed.
1076 if (self.primaryMenuItem.type == bookmarks::MenuItemFolder &&
1077 self.primaryMenuItem.folder == node) {
1078 UIInterfaceOrientation orient = GetInterfaceOrientation();
1079 [self updateNavigationBarAnimated:NO orientation:orient];
1080 }
1081 }
1082
1083 - (void)bookmarkNodeChildrenChanged:(const BookmarkNode*)bookmarkNode {
1084 // The node has not changed, but the ordering and existence of its children
1085 // have changed.
1086 }
1087
1088 - (void)bookmarkNode:(const BookmarkNode*)bookmarkNode
1089 movedFromParent:(const BookmarkNode*)oldParent
1090 toParent:(const BookmarkNode*)newParent {
1091 // The node has moved to a new parent folder.
1092 }
1093
1094 - (void)bookmarkNodeDeleted:(const BookmarkNode*)node
1095 fromFolder:(const BookmarkNode*)folder {
1096 [self removeEditNode:node atIndexPath:nil];
1097 }
1098
1099 - (void)bookmarkModelRemovedAllNodes {
1100 // All non-permanent nodes have been removed.
1101 [self setEditing:NO animated:YES];
1102 }
1103
1104 - (UIStatusBarStyle)preferredStatusBarStyle {
1105 return self.editing ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault;
1106 }
1107
1108 // There are 2 UIViewController methods that could be overridden. This one and
1109 // willAnimateRotationToInterfaceOrientation:duration:. The latter is called
1110 // during an "animation block", and its unclear that reloading a collection view
1111 // will always work duratin an "animation block", although it appears to work at
1112 // first glance.
1113 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
1114 duration:(NSTimeInterval)duration {
1115 [self updateUIForInterfaceOrientation:orientation duration:duration];
1116 }
1117
1118 - (void)viewWillAppear:(BOOL)animated {
1119 [super viewWillAppear:animated];
1120 UIInterfaceOrientation orient = GetInterfaceOrientation();
1121 [self updateUIForInterfaceOrientation:orient duration:0];
1122 if (self.cachedContentPosition) {
1123 [[self primaryView]
1124 applyContentPosition:[self.cachedContentPosition floatValue]];
1125 self.cachedContentPosition = nil;
1126 }
1127 }
1128
1129 - (void)viewWillLayoutSubviews {
1130 [super viewWillLayoutSubviews];
1131 // Invalidate the layout of the collection view, as its frame might have
1132 // changed. Normally, this can be done automatically when the collection view
1133 // layout returns YES to -shouldInvalidateLayoutForBoundsChange:.
1134 // Unfortunately, it doesn't happen for all bounds changes. E.g. on iPhone 6
1135 // Plus landscape, the width of the collection is too large when created, then
1136 // resized down before being presented. Yet, the bounds change doesn't yield a
1137 // call to the flow layout, thus not invalidating the layout correctly.
1138 [[self primaryView].collectionView.collectionViewLayout invalidateLayout];
1139
1140 self.navigationBar.frame = [self navigationBarFrame];
1141 self.editingBar.frame = [self navigationBarFrame];
1142 [self.panelView setFrame:[self frameForPrimaryView]];
1143 }
1144
1145 #pragma mark - Internal non-UI Methods
1146
1147 - (void)delegateDismiss:(const GURL&)url {
1148 if ([self primaryView]) {
1149 bookmark_utils_ios::CachePosition(
1150 [[self primaryView] contentPositionInPortraitOrientation],
1151 [self primaryMenuItem]);
1152 }
1153 [self.delegate bookmarkHomeViewControllerWantsDismissal:self
1154 navigationToUrl:url];
1155 }
1156
1157 #pragma mark - BookmarkPromoControllerDelegate
1158
1159 - (void)promoStateChanged:(BOOL)promoEnabled {
1160 [self.allItemsView.collectionView reloadData];
1161 // This is required to workaround a crash seen once on iOS 7.1 when
1162 // the collection gets two reloadData without getting a call to layout
1163 // subviews, the collection view will reuse some cached data for the perfoming
1164 // the layout which are invalid after the second call to reloadData.
1165 // Forcing the layout invalidation after each reloadData seems to fix the
1166 // issue.
1167 [self.allItemsView.collectionView.collectionViewLayout invalidateLayout];
1168
1169 [self.folderView
1170 promoStateChangedAnimated:self.folderView == [self primaryView]];
1171 }
1172
1173 - (NSIndexPath*)indexPathForCell:(UICollectionViewCell*)cell {
1174 DCHECK([self primaryView].collectionView);
1175 NSIndexPath* indexPath =
1176 [[self primaryView].collectionView indexPathForCell:cell];
1177 return indexPath;
1178 }
1179
1180 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698