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

Side by Side Diff: ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_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_tablet_ntp_controller.h"
6
7 #include <memory>
8
9 #include "base/ios/block_types.h"
10 #import "base/ios/weak_nsobject.h"
11 #include "base/logging.h"
12 #include "base/mac/objc_property_releaser.h"
13 #include "base/mac/scoped_nsobject.h"
14 #include "base/metrics/user_metrics.h"
15 #include "base/metrics/user_metrics_action.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "components/bookmarks/browser/bookmark_model.h"
18 #include "components/strings/grit/components_strings.h"
19 #include "google_apis/gaia/google_service_auth_error.h"
20 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
21 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h"
22 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
23 #import "ios/chrome/browser/metrics/new_tab_page_uma.h"
24 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
25 #import "ios/chrome/browser/ui/bookmarks/bars/bookmark_editing_bar.h"
26 #import "ios/chrome/browser/ui/bookmarks/bars/bookmark_navigation_bar.h"
27 #import "ios/chrome/browser/ui/bookmarks/bookmark_all_collection_view.h"
28 #import "ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h"
29 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_collection_view.h"
30 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller. h"
31 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
32 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_primary_view.h"
33 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_waiting_view.h"
34 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_item.h"
35 #import "ios/chrome/browser/ui/bookmarks/bookmark_menu_view.h"
36 #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
37 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
38 #import "ios/chrome/browser/ui/bookmarks/bookmark_panel_view.h"
39 #import "ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.h"
40 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
41 #import "ios/chrome/browser/ui/rtl_geometry.h"
42 #import "ios/chrome/browser/ui/uikit_ui_util.h"
43 #import "ios/chrome/browser/ui/url_loader.h"
44 #include "ios/chrome/grit/ios_strings.h"
45 #include "ios/web/public/referrer.h"
46 #include "ui/base/l10n/l10n_util.h"
47 #include "ui/base/l10n/l10n_util_mac.h"
48 #include "ui/base/page_transition_types.h"
49
50 using bookmarks::BookmarkNode;
51
52 namespace {
53 // The width of the bookmark menu, displaying the different sections.
54 const CGFloat kMenuWidth = 264.0;
55 // The margin on top to the navigation bar.
56 const CGFloat kNavigationBarTopMargin = 8.0;
57 } // namespace
58
59 // A simple UIView subclass to pass on relayout information to its delegate.
60 @protocol ContentViewDelegate<NSObject>
61 - (void)willLayoutSubviews;
62 @end
63
64 @interface ContentView : UIView
65 @property(nonatomic, assign) id<ContentViewDelegate> delegate;
66 @end
67
68 @implementation ContentView
69 @synthesize delegate = _delegate;
70
71 - (void)layoutSubviews {
72 [self.delegate willLayoutSubviews];
73 [super layoutSubviews];
74 }
75 @end
76
77 @interface BookmarkHomeTabletNTPController ()<
78 BookmarkEditViewControllerDelegate,
79 BookmarkFolderCollectionViewDelegate,
80 BookmarkFolderEditorViewControllerDelegate,
81 BookmarkFolderViewControllerDelegate,
82 BookmarkMenuViewDelegate,
83 BookmarkModelBridgeObserver,
84 BookmarkPromoControllerDelegate,
85 ContentViewDelegate> {
86 // Bridge to register for bookmark changes.
87 std::unique_ptr<bookmarks::BookmarkModelBridge> _bridge;
88 ios::ChromeBrowserState* _browserState; // Weak.
89 id<UrlLoader> _loader; // Weak.
90
91 // The following 2 ivars both represent the set of nodes being edited.
92 // The set is for fast lookup.
93 // The vector maintains the order that edit nodes were added.
94 // Use the relevant instance methods to modify these two ivars in tandem.
95 // DO NOT modify these two ivars directly.
96 std::set<const BookmarkNode*> _editNodes;
97 std::vector<const BookmarkNode*> _editNodesOrdered;
98
99 base::mac::ObjCPropertyReleaser
100 _propertyReleaser_BookmarkHomeTabletNTPController;
101 }
102
103 @property(nonatomic, retain) BookmarkPanelView* panelView;
104
105 #pragma mark - Properties and methods akin to BookmarkHomeViewController
106
107 // Whether the view controller is in editing mode.
108 @property(nonatomic, assign) BOOL editing;
109 // The set of edited index paths.
110 @property(nonatomic, retain) NSMutableArray* editIndexPaths;
111 // The bookmark model used.
112 @property(nonatomic, assign, readonly) bookmarks::BookmarkModel* bookmarks;
113 // The user's browser state model used.
114 @property(nonatomic, assign, readonly)
115 ios::ChromeBrowserState* browserState; // from superclass.
116
117 // Replaces |_editNodes| and |_editNodesOrdered| with new container objects.
118 - (void)resetEditNodes;
119 // Adds |node| corresponding to a |cell| if it isn't already present.
120 - (void)insertEditNode:(const BookmarkNode*)node
121 atIndexPath:(NSIndexPath*)indexPath;
122 // Removes |node| corresponding to a |cell| if it's present.
123 - (void)removeEditNode:(const BookmarkNode*)node
124 atIndexPath:(NSIndexPath*)indexPath;
125 // This method updates the property, and resets the edit nodes.
126 - (void)setEditing:(BOOL)editing animated:(BOOL)animated;
127
128 #pragma mark - Properties and methods akin to BookmarkHomeHandsetViewController
129
130 // This views holds the primary content of this controller. At any point in
131 // time, it contains exactly one of the BookmarkCollectionView subclasses.
132 @property(nonatomic, retain) ContentView* contentView;
133 // The possible views that can be shown from the menu.
134 @property(nonatomic, retain) BookmarkAllCollectionView* allItemsView;
135 @property(nonatomic, retain) BookmarkFolderCollectionView* folderView;
136 // This view is created and used if the model is not fully loaded yet by the
137 // time this controller starts.
138 @property(nonatomic, retain) BookmarkHomeWaitingView* waitForModelView;
139
140 // The menu with all the folders and special entries.
141 @property(nonatomic, retain) BookmarkMenuView* menuView;
142 // At any point in time, there is exactly one collection view whose view is part
143 // of the view hierarchy. This property determines which collection view is
144 // visible. Not by accident, this property also reflects the selected menu item
145 // in the BookmarkMenuView.
146 @property(nonatomic, retain) BookmarkMenuItem* primaryMenuItem;
147 // When the view is first shown on the screen, this property represents the
148 // cached value of the y of the content offset of the primary view. This
149 // property is set to nil after it is used.
150 @property(nonatomic, retain)
151 NSNumber* cachedContentPosition; // FIXME: INACTIVE
152
153 // The navigation bar sits on top of the main content.
154 @property(nonatomic, retain) BookmarkNavigationBar* navigationBar;
155 // The editing bar present when items are selected.
156 @property(nonatomic, retain) BookmarkEditingBar* editingBar;
157
158 // The action sheet coordinator used when trying to edit a single bookmark.
159 @property(nonatomic, retain) ActionSheetCoordinator* actionSheetCoordinator;
160 // The view controller used to view and edit a single bookmark.
161 @property(nonatomic, retain) BookmarkEditViewController* editViewController;
162 // The view controller used to pick a folder in which to move the selected
163 // bookmarks.
164 @property(nonatomic, retain) BookmarkFolderViewController* folderSelector;
165 // The view controller to present when editing the current folder.
166 @property(nonatomic, retain)
167 BookmarkFolderEditorViewController* folderEditor; // FIX
168 // The controller managing the display of the promo cell and the promo view
169 // controller.
170 @property(nonatomic, retain) BookmarkPromoController* bookmarkPromoController;
171
172 #pragma mark Specific to this class.
173
174 // Either the menu or the primaryView can scrollToTop.
175 @property(nonatomic, assign) BOOL scrollToTop;
176
177 // Opens the url.
178 - (void)loadURL:(const GURL&)url;
179 #pragma mark View loading, laying out, and switching.
180 // This method is called if the view needs to be loaded and the model is not
181 // ready yet.
182 - (void)loadWaitingView;
183 // This method should be called at most once in the life-cycle of the class.
184 // It should be called at the soonest possible time after the view has been
185 // loaded, and the bookmark model is loaded.
186 - (void)loadBookmarkViews;
187 // If the view doesn't exist, create it.
188 - (void)ensureAllViewExists;
189 - (void)ensureFolderViewExists;
190 // Updates the property 'primaryMenuItem'.
191 // Updates the UI to reflect the new state of 'primaryMenuItem'.
192 - (void)updatePrimaryMenuItem:(BookmarkMenuItem*)menuItem
193 animated:(BOOL)animated;
194 // The active collection view that corresponds to primaryMenuItem.
195 - (UIView<BookmarkHomePrimaryView>*)primaryView;
196 // Returns whether the menu should be in a side panel that slides in.
197 - (BOOL)shouldPresentMenuInSlideInPanel;
198 // Returns the width of the menu.
199 - (CGFloat)menuWidth;
200 // Returns the leading margin of the primary view.
201 - (CGFloat)primaryViewLeadingMargin;
202 // Moves the menu and primary view to their correct parent views depending on
203 // the layout.
204 - (void)moveMenuAndPrimaryViewToAdequateParent;
205 // Updates the frame of the primary view.
206 - (void)refreshFrameOfPrimaryView;
207 // Returns the frame of the primary view.
208 - (CGRect)frameForPrimaryView;
209
210 #pragma mark Editing related methods
211 // This method statelessly updates the editing top bar from |_editNodes| and
212 // |editing|.
213 - (void)updateEditingStateAnimated:(BOOL)animated;
214 // Shows or hides the editing bar.
215 - (void)showEditingBarAnimated:(BOOL)animated;
216 - (void)hideEditingBarAnimated:(BOOL)animated;
217 // Instaneously updates the shadow of the edit bar.
218 // This method should be called anytime:
219 // (1)|editing| property changes.
220 // (2)The primary view changes.
221 // (3)The primary view's collection view is scrolled.
222 // When |editing| is NO, the shadow is never shown.
223 - (void)updateEditBarShadow;
224
225 #pragma mark Editing bar callbacks
226 // The cancel button was tapped on the editing bar.
227 - (void)editingBarCancel;
228 // The move button was tapped on the editing bar.
229 - (void)editingBarMove;
230 // The delete button was tapped on the editing bar.
231 - (void)editingBarDelete;
232 // The edit button was tapped on the editing bar.
233 - (void)editingBarEdit;
234 // The menu button is pressed on the editing bar.
235 - (void)toggleMenuAnimated;
236
237 #pragma mark Action sheet callbacks
238 // Enters into edit mode by selecting the given node corresponding to the
239 // given cell.
240 - (void)selectFirstNode:(const BookmarkNode*)node
241 withCell:(UICollectionViewCell*)cell;
242 // Opens the editor on the given node and cell.
243 - (void)editNode:(const BookmarkNode*)node withCell:(UICollectionViewCell*)cell;
244 // Opens the folder move editor for the given node.
245 - (void)moveNodes:(const std::set<const BookmarkNode*>&)nodes;
246 // Deletes the current node.
247 - (void)deleteNodes:(const std::set<const BookmarkNode*>&)nodes;
248
249 #pragma mark private utility methods
250 // Deletes the nodes, and presents a toast with an undo button.
251 - (void)deleteSelectedNodes;
252
253 #pragma mark Navigation bar
254 // Updates the UI of the navigation bar with the primaryMenuItem.
255 // This method should be called anytime:
256 // (1)The primary view changes.
257 // (2)The primary view has type folder, and the relevant folder has changed.
258 // (3)The interface orientation changes.
259 // (4)viewWillAppear, as the interface orientation may have changed.
260 - (void)updateNavigationBarAnimated:(BOOL)animated
261 orientation:(UIInterfaceOrientation)orientation;
262 - (void)updateNavigationBarWithDuration:(CGFloat)duration
263 orientation:(UIInterfaceOrientation)orientation;
264 // Whether the edit button on the navigation bar should be shown.
265 - (BOOL)shouldShowEditButton;
266 // Whether the back button on the navigation bar should be shown.
267 - (BOOL)shouldShowBackButton;
268 // Called when the edit button is pressed on the navigation bar.
269 - (void)navigationBarWantsEditing:(id)sender;
270 // Called when the back button is pressed on the navigation bar.
271 - (void)navigationBarBack:(id)sender;
272
273 // TODO(crbug.com/450646): This should not be needed but require refactoring of
274 // the BookmarkCollectionViewDelegate.
275 - (NSIndexPath*)indexPathForCell:(UICollectionViewCell*)cell;
276
277 @end
278
279 @implementation BookmarkHomeTabletNTPController
280 @synthesize editing = _editing;
281 @synthesize editIndexPaths = _editIndexPaths;
282 @synthesize bookmarks = _bookmarks;
283
284 @synthesize contentView = _contentView;
285 @synthesize allItemsView = _allItemsView;
286 @synthesize folderView = _folderView;
287 @synthesize waitForModelView = _waitForModelView;
288
289 @synthesize menuView = _menuView;
290 @synthesize primaryMenuItem = _primaryMenuItem;
291 @synthesize cachedContentPosition = _cachedContentPosition;
292 @synthesize navigationBar = _navigationBar;
293 @synthesize editingBar = _editingBar;
294 @synthesize panelView = _panelView;
295
296 @synthesize actionSheetCoordinator = _actionSheetCoordinator;
297 @synthesize editViewController = _editViewController;
298 @synthesize folderSelector = _folderSelector;
299 @synthesize folderEditor = _folderEditor;
300 @synthesize bookmarkPromoController = _bookmarkPromoController;
301
302 @synthesize scrollToTop = _scrollToTop;
303
304 // Property declared in NewTabPagePanelProtocol.
305 @synthesize delegate = _delegate;
306
307 - (id)initWithLoader:(id<UrlLoader>)loader
308 browserState:(ios::ChromeBrowserState*)browserState {
309 self = [super init];
310 if (self) {
311 DCHECK(browserState);
312 _browserState = browserState->GetOriginalChromeBrowserState();
313 _loader = loader;
314 _propertyReleaser_BookmarkHomeTabletNTPController.Init(
315 self, [BookmarkHomeTabletNTPController class]);
316
317 _bookmarks = ios::BookmarkModelFactory::GetForBrowserState(_browserState);
318 _bridge.reset(new bookmarks::BookmarkModelBridge(self, _bookmarks));
319 _editIndexPaths = [[NSMutableArray alloc] init];
320 // It is important to initialize the promo controller with the browser state
321 // passed in, as it could be incognito.
322 _bookmarkPromoController =
323 [[BookmarkPromoController alloc] initWithBrowserState:browserState
324 delegate:self];
325 }
326 return self;
327 }
328
329 - (void)dealloc {
330 _contentView.delegate = nil;
331
332 _allItemsView.delegate = nil;
333 _folderView.delegate = nil;
334
335 _menuView.delegate = nil;
336
337 _editViewController.delegate = nil;
338 _folderSelector.delegate = nil;
339
340 [super dealloc];
341 }
342
343 - (ios::ChromeBrowserState*)browserState {
344 return _browserState;
345 }
346
347 #pragma mark - ContentViewDelegate method.
348
349 - (void)willLayoutSubviews {
350 if (![self primaryView] && ![self primaryMenuItem] &&
351 self.bookmarks->loaded()) {
352 BookmarkMenuItem* item = nil;
353 CGFloat position = 0;
354 BOOL found =
355 bookmark_utils_ios::GetPositionCache(self.bookmarks, &item, &position);
356 if (!found)
357 item = [self.menuView defaultMenuItem];
358
359 [self updatePrimaryMenuItem:item animated:NO];
360 }
361
362 [self moveMenuAndPrimaryViewToAdequateParent];
363 CGFloat leadingMargin = [self primaryViewLeadingMargin];
364
365 // Prevent the panelView from hijacking the gestures so that the
366 // NTPController's scrollview can still scroll with the gestures.
367 [self.panelView enableSideSwiping:NO];
368
369 CGFloat width = self.contentView.bounds.size.width;
370 LayoutRect navBarLayout =
371 LayoutRectMake(leadingMargin, width, 0, width - leadingMargin,
372 CGRectGetHeight([self navigationBarFrame]));
373 self.navigationBar.frame = LayoutRectGetRect(navBarLayout);
374 [self.editingBar setFrame:[self editingBarFrame]];
375
376 UIInterfaceOrientation orient = GetInterfaceOrientation();
377 [self refreshFrameOfPrimaryView];
378 [[self primaryView] changeOrientation:orient];
379 [self updateNavigationBarWithDuration:0 orientation:orient];
380 if (![self shouldPresentMenuInSlideInPanel])
381 [self updateMenuViewLayout];
382 }
383
384 #pragma mark HomeViewController simili methods.
385
386 - (void)resetEditNodes {
387 _editNodes = std::set<const BookmarkNode*>();
388 _editNodesOrdered = std::vector<const BookmarkNode*>();
389 [self.editIndexPaths removeAllObjects];
390 }
391
392 - (void)insertEditNode:(const BookmarkNode*)node
393 atIndexPath:(NSIndexPath*)indexPath {
394 if (_editNodes.find(node) != _editNodes.end())
395 return;
396 _editNodes.insert(node);
397 _editNodesOrdered.push_back(node);
398 if (indexPath) {
399 [self.editIndexPaths addObject:indexPath];
400 } else {
401 // Insert null to keep the index valid.
402 [self.editIndexPaths addObject:[NSNull null]];
403 }
404 }
405
406 - (void)removeEditNode:(const BookmarkNode*)node
407 atIndexPath:(NSIndexPath*)indexPath {
408 if (_editNodes.find(node) == _editNodes.end())
409 return;
410 _editNodes.erase(node);
411 std::vector<const BookmarkNode*>::iterator it =
412 std::find(_editNodesOrdered.begin(), _editNodesOrdered.end(), node);
413 DCHECK(it != _editNodesOrdered.end());
414 _editNodesOrdered.erase(it);
415 if (indexPath) {
416 [self.editIndexPaths removeObject:indexPath];
417 } else {
418 // If we don't have the cell, we remove it by using its index.
419 const NSUInteger index = std::distance(_editNodesOrdered.begin(), it);
420 if (index < self.editIndexPaths.count) {
421 [self.editIndexPaths removeObjectAtIndex:index];
422 }
423 }
424
425 if (_editNodes.size() == 0)
426 [self setEditing:NO animated:YES];
427 else
428 [self updateEditingStateAnimated:YES];
429 }
430
431 #pragma mark - private methods
432
433 - (void)loadURL:(const GURL&)url {
434 if (url == GURL() || url.SchemeIs(url::kJavaScriptScheme))
435 return;
436
437 new_tab_page_uma::RecordAction(self.browserState,
438 new_tab_page_uma::ACTION_OPENED_BOOKMARK);
439 base::RecordAction(base::UserMetricsAction("MobileNTPBookmark"));
440 [_loader loadURL:url
441 referrer:web::Referrer()
442 transition:ui::PAGE_TRANSITION_AUTO_BOOKMARK
443 rendererInitiated:NO];
444 }
445
446 #pragma mark - Views
447
448 - (void)loadWaitingView {
449 DCHECK(!self.waitForModelView);
450 DCHECK(self.contentView);
451
452 // Present a waiting view.
453 base::scoped_nsobject<BookmarkHomeWaitingView> waitingView(
454 [[BookmarkHomeWaitingView alloc] initWithFrame:self.view.bounds]);
455 self.waitForModelView = waitingView;
456 [self.view addSubview:self.waitForModelView];
457 [self.waitForModelView startWaiting];
458 }
459
460 - (void)updateMenuViewLayout {
461 LayoutRect menuLayout =
462 LayoutRectMake(0, self.view.bounds.size.width, 0, self.menuWidth,
463 self.view.bounds.size.height);
464 self.menuView.frame = LayoutRectGetRect(menuLayout);
465 }
466
467 - (void)loadBookmarkViews {
468 DCHECK(self.bookmarks->loaded());
469
470 // Create the menu.
471 LayoutRect menuLayout =
472 LayoutRectMake(0, self.view.bounds.size.width, 0, self.menuWidth,
473 self.view.bounds.size.height);
474 self.menuView =
475 base::scoped_nsobject<BookmarkMenuView>([[BookmarkMenuView alloc]
476 initWithBrowserState:self.browserState
477 frame:LayoutRectGetRect(menuLayout)]);
478 self.menuView.delegate = self;
479 self.menuView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
480
481 [self moveMenuAndPrimaryViewToAdequateParent];
482
483 // Load the last primary menu item which the user had active.
484 BookmarkMenuItem* item = nil;
485 CGFloat position = 0;
486 BOOL found =
487 bookmark_utils_ios::GetPositionCache(self.bookmarks, &item, &position);
488 if (!found)
489 item = [self.menuView defaultMenuItem];
490
491 [self updatePrimaryMenuItem:item animated:NO];
492
493 [[self primaryView] applyContentPosition:position];
494
495 if (found) {
496 // If the view has already been laid out, then immediately apply the content
497 // position.
498 if (self.view.window) {
499 [[self primaryView] applyContentPosition:position];
500 } else {
501 // Otherwise, save the position to be applied once the view has been laid
502 // out.
503 self.cachedContentPosition = [NSNumber numberWithFloat:position];
504 }
505 }
506 }
507
508 - (void)ensureAllViewExists {
509 if (self.allItemsView)
510 return;
511
512 base::scoped_nsobject<BookmarkAllCollectionView> view(
513 [[BookmarkAllCollectionView alloc] initWithBrowserState:self.browserState
514 frame:CGRectZero]);
515 self.allItemsView = view;
516 self.allItemsView.delegate = self;
517 [self.allItemsView setEditing:self.editing animated:NO];
518 self.allItemsView.autoresizingMask =
519 UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
520 }
521
522 - (void)ensureFolderViewExists {
523 if (self.folderView)
524 return;
525
526 base::scoped_nsobject<BookmarkFolderCollectionView> view(
527 [[BookmarkFolderCollectionView alloc]
528 initWithBrowserState:self.browserState
529 frame:CGRectZero]);
530 self.folderView = view;
531 self.folderView.delegate = self;
532 [self.folderView setEditing:self.editing animated:NO];
533 self.folderView.autoresizingMask =
534 UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
535 }
536
537 - (void)updatePrimaryMenuItem:(BookmarkMenuItem*)menuItem
538 animated:(BOOL)animated {
539 if ([self.primaryMenuItem isEqual:menuItem])
540 return;
541
542 if (![self.contentView superview])
543 return;
544
545 [[self primaryView] removeFromSuperview];
546 self.primaryMenuItem = menuItem;
547
548 switch (self.primaryMenuItem.type) {
549 case bookmarks::MenuItemAll:
550 [self ensureAllViewExists];
551 break;
552 case bookmarks::MenuItemFolder:
553 [self ensureFolderViewExists];
554 [self.folderView resetFolder:self.primaryMenuItem.folder];
555 [self.folderView promoStateChangedAnimated:NO];
556 break;
557 case bookmarks::MenuItemDivider:
558 case bookmarks::MenuItemSectionHeader:
559 NOTREACHED();
560 break;
561 }
562
563 [[self primaryView] changeOrientation:GetInterfaceOrientation()];
564 [[self primaryView] setScrollsToTop:self.scrollToTop];
565
566 [self moveMenuAndPrimaryViewToAdequateParent];
567
568 // [self.contentView sendSubviewToBack:primaryView];
569 [self refreshFrameOfPrimaryView];
570
571 self.navigationBar.hidden = NO;
572 [self updateNavigationBarAnimated:animated
573 orientation:GetInterfaceOrientation()];
574
575 [self.menuView updatePrimaryMenuItem:self.primaryMenuItem];
576 [self updateEditBarShadow];
577 }
578
579 - (UIView<BookmarkHomePrimaryView>*)primaryView {
580 if (!self.primaryMenuItem)
581 return nil;
582 DCHECK([self contentView]);
583
584 switch (self.primaryMenuItem.type) {
585 case bookmarks::MenuItemAll:
586 return self.allItemsView;
587 case bookmarks::MenuItemFolder:
588 return self.folderView;
589 case bookmarks::MenuItemDivider:
590 case bookmarks::MenuItemSectionHeader:
591 NOTREACHED();
592 return nil;
593 }
594 }
595
596 - (BOOL)shouldPresentMenuInSlideInPanel {
597 return IsCompactTablet();
598 }
599
600 - (CGFloat)menuWidth {
601 return kMenuWidth;
602 }
603
604 - (CGFloat)primaryViewLeadingMargin {
605 if ([self shouldPresentMenuInSlideInPanel])
606 return 0;
607 return [self menuWidth];
608 }
609
610 - (void)moveMenuAndPrimaryViewToAdequateParent {
611 // Remove the menuView, panelView, and primaryView from the view hierarchy.
612 if ([self.menuView superview])
613 [self.menuView removeFromSuperview];
614 if ([self.panelView superview])
615 [self.panelView removeFromSuperview];
616 UIView* primaryView = [self primaryView];
617 if ([primaryView superview])
618 [primaryView removeFromSuperview];
619
620 if ([self shouldPresentMenuInSlideInPanel]) {
621 // Create (if needed), and add the panelView to the view hierarchy.
622 if (!self.panelView) {
623 self.panelView = base::scoped_nsobject<BookmarkPanelView>(
624 [[BookmarkPanelView alloc] initWithFrame:CGRectZero
625 menuViewWidth:[self menuWidth]]);
626 }
627 [self.view addSubview:self.panelView];
628 CGSize size = self.contentView.bounds.size;
629 CGFloat navBarHeight = CGRectGetHeight([self navigationBarFrame]);
630 LayoutRect panelLayout = LayoutRectMake(
631 0, size.width, navBarHeight, size.width, size.height - navBarHeight);
632
633 // Initialize the panelView with the menuView and the primaryView.
634 [self.panelView setFrame:LayoutRectGetRect(panelLayout)];
635 [self.panelView.menuView addSubview:self.menuView];
636 self.menuView.frame = self.panelView.menuView.bounds;
637 [self.panelView.contentView addSubview:primaryView];
638 } else {
639 [self.view addSubview:self.menuView];
640 [self.view addSubview:primaryView];
641 }
642
643 // Make sure the navigation bar is the frontmost subview.
644 [self.view bringSubviewToFront:self.navigationBar];
645 }
646
647 - (void)refreshFrameOfPrimaryView {
648 [self primaryView].frame = [self frameForPrimaryView];
649 }
650
651 - (CGRect)frameForPrimaryView {
652 CGFloat topInset = 0;
653 if (!IsCompactTablet())
654 topInset = CGRectGetHeight([self navigationBarFrame]);
655
656 CGFloat leadingMargin = [self primaryViewLeadingMargin];
657 CGSize size = self.view.bounds.size;
658 LayoutRect primaryViewLayout =
659 LayoutRectMake(leadingMargin, size.width, topInset,
660 size.width - leadingMargin, size.height - topInset);
661 return LayoutRectGetRect(primaryViewLayout);
662 }
663
664 #pragma mark - Editing bar methods.
665
666 - (CGRect)editingBarFrame {
667 return CGRectInset(self.navigationBar.frame, 24.0, 0);
668 }
669
670 - (void)updateEditingStateAnimated:(BOOL)animated {
671 if (!self.editing) {
672 [self hideEditingBarAnimated:animated];
673 [self updateEditBarShadow];
674 return;
675 }
676
677 if (!self.editingBar) {
678 self.editingBar = base::scoped_nsobject<BookmarkEditingBar>(
679 [[BookmarkEditingBar alloc] initWithFrame:[self editingBarFrame]]);
680 [self.editingBar setCancelTarget:self action:@selector(editingBarCancel)];
681 [self.editingBar setDeleteTarget:self action:@selector(editingBarDelete)];
682 [self.editingBar setMoveTarget:self action:@selector(editingBarMove)];
683 [self.editingBar setEditTarget:self action:@selector(editingBarEdit)];
684
685 [self.view addSubview:self.editingBar];
686 self.editingBar.hidden = YES;
687 }
688
689 int bookmarkCount = 0;
690 int folderCount = 0;
691 for (auto node : _editNodes) {
692 if (node->is_url())
693 ++bookmarkCount;
694 else
695 ++folderCount;
696 }
697 [self.editingBar updateUIWithBookmarkCount:bookmarkCount
698 folderCount:folderCount];
699
700 [self showEditingBarAnimated:animated];
701 [self updateEditBarShadow];
702 }
703
704 - (void)setEditing:(BOOL)editing animated:(BOOL)animated {
705 if (_editing == editing)
706 return;
707
708 _editing = editing;
709
710 if (editing) {
711 self.bookmarkPromoController.promoState = NO;
712 } else {
713 // Only reset the editing state when leaving edit mode. This allows
714 // subclasses to add nodes for editing before entering edit mode.
715 [self resetEditNodes];
716 [self.bookmarkPromoController updatePromoState];
717 }
718
719 [self updateEditingStateAnimated:animated];
720 if ([[self primaryMenuItem] supportsEditing])
721 [[self primaryView] setEditing:editing animated:animated];
722 }
723
724 - (void)showEditingBarAnimated:(BOOL)animated {
725 CGRect endFrame = [self editingBarFrame];
726 if (self.editingBar.hidden) {
727 CGRect startFrame = endFrame;
728 startFrame.origin.y = -CGRectGetHeight(startFrame);
729 self.editingBar.frame = startFrame;
730 }
731 self.editingBar.hidden = NO;
732 [UIView animateWithDuration:animated ? 0.2 : 0
733 delay:0
734 options:UIViewAnimationOptionBeginFromCurrentState
735 animations:^{
736 self.editingBar.frame = endFrame;
737 }
738 completion:^(BOOL finished) {
739 if (finished)
740 self.navigationBar.hidden = YES;
741 }];
742 }
743
744 - (void)hideEditingBarAnimated:(BOOL)animated {
745 CGRect frame = [self editingBarFrame];
746 if (!self.editingBar.hidden) {
747 frame.origin.y = -CGRectGetHeight(frame);
748 }
749 self.navigationBar.hidden = NO;
750 [UIView animateWithDuration:animated ? 0.2 : 0
751 delay:0
752 options:UIViewAnimationOptionBeginFromCurrentState
753 animations:^{
754 self.editingBar.frame = frame;
755 }
756 completion:^(BOOL finished) {
757 if (finished)
758 self.editingBar.hidden = YES;
759 }];
760 }
761
762 - (void)updateEditBarShadow {
763 [self.editingBar showShadow:self.editing];
764 }
765
766 #pragma mark Editing Bar Callbacks
767
768 - (void)editingBarCancel {
769 [self setEditing:NO animated:YES];
770 }
771
772 - (void)editingBarMove {
773 [self moveNodes:_editNodes];
774 }
775
776 - (void)editingBarDelete {
777 [self deleteSelectedNodes];
778 [self setEditing:NO animated:YES];
779 }
780
781 - (void)editingBarEdit {
782 DCHECK_EQ(_editNodes.size(), 1u);
783 const BookmarkNode* node = *(_editNodes.begin());
784 BookmarkItemCell* itemCell = nil;
785 if (self.editIndexPaths.count > 0) {
786 NSIndexPath* indexPath = [self.editIndexPaths firstObject];
787 if (indexPath && ![indexPath isKindOfClass:[NSNull class]]) {
788 UICollectionViewCell* cell =
789 [[self primaryView].collectionView cellForItemAtIndexPath:indexPath];
790 if ([cell isKindOfClass:[BookmarkItemCell class]]) {
791 itemCell = static_cast<BookmarkItemCell*>(cell);
792 }
793 }
794 }
795 [self editNode:node withCell:itemCell];
796 }
797
798 - (void)toggleMenuAnimated {
799 if ([self.panelView userDrivenAnimationInProgress])
800 return;
801
802 if (self.panelView.showingMenu) {
803 [self.panelView hideMenuAnimated:YES];
804 } else {
805 [self.panelView showMenuAnimated:YES];
806 }
807 }
808
809 #pragma mark - BookmarkMenuViewDelegate
810
811 - (void)bookmarkMenuView:(BookmarkMenuView*)view
812 selectedMenuItem:(BookmarkMenuItem*)menuItem {
813 BOOL menuItemChanged = ![[self primaryMenuItem] isEqual:menuItem];
814 [self toggleMenuAnimated];
815 if (menuItemChanged) {
816 [self setEditing:NO animated:YES];
817 [self updatePrimaryMenuItem:menuItem animated:YES];
818 }
819 }
820
821 #pragma mark - BookmarkCollectionViewDelegate
822 // This class owns multiple views that have a delegate that conforms to
823 // BookmarkCollectionViewDelegate, or a subprotocol of
824 // BookmarkCollectionViewDelegate.
825 - (void)bookmarkCollectionView:(BookmarkCollectionView*)view
826 cell:(UICollectionViewCell*)cell
827 addNodeForEditing:(const BookmarkNode*)node {
828 [self insertEditNode:node atIndexPath:[self indexPathForCell:cell]];
829 [self updateEditingStateAnimated:YES];
830 }
831
832 - (void)bookmarkCollectionView:(BookmarkCollectionView*)view
833 cell:(UICollectionViewCell*)cell
834 removeNodeForEditing:(const BookmarkNode*)node {
835 [self removeEditNode:node atIndexPath:[self indexPathForCell:cell]];
836 }
837
838 - (const std::set<const BookmarkNode*>&)nodesBeingEdited {
839 return _editNodes;
840 }
841
842 - (void)bookmarkCollectionViewDidScroll:(BookmarkCollectionView*)view {
843 [self updateEditBarShadow];
844 }
845
846 - (void)bookmarkCollectionView:(BookmarkCollectionView*)view
847 selectedUrlForNavigation:(const GURL&)url {
848 [self cachePosition];
849 // Before passing the URL to the block, make sure the block has a copy of the
850 // URL and not just a reference.
851 const GURL localUrl(url);
852 dispatch_async(dispatch_get_main_queue(), ^{
853 [self loadURL:localUrl];
854 });
855 }
856
857 - (void)bookmarkCollectionView:(BookmarkCollectionView*)collectionView
858 wantsMenuForBookmark:(const BookmarkNode*)node
859 onView:(UIView*)view
860 forCell:(BookmarkItemCell*)cell {
861 DCHECK(!self.editViewController);
862 DCHECK(!self.actionSheetCoordinator);
863 self.actionSheetCoordinator = [[[ActionSheetCoordinator alloc]
864 initWithBaseViewController:self.view.window.rootViewController
865 title:nil
866 message:nil
867 rect:view.bounds
868 view:view] autorelease];
869 base::WeakNSObject<BookmarkHomeTabletNTPController> weakSelf(self);
870
871 // Select action.
872 [self.actionSheetCoordinator
873 addItemWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_ACTION_SELECT)
874 action:^{
875 [weakSelf selectFirstNode:node withCell:cell];
876 weakSelf.get().actionSheetCoordinator = nil;
877 }
878 style:UIAlertActionStyleDefault];
879
880 // Edit action.
881 [self.actionSheetCoordinator
882 addItemWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_ACTION_EDIT)
883 action:^{
884 BookmarkItemCell* itemCell = nil;
885 if ([cell isKindOfClass:[BookmarkItemCell class]])
886 itemCell = static_cast<BookmarkItemCell*>(cell);
887 [weakSelf editNode:node withCell:itemCell];
888 weakSelf.get().actionSheetCoordinator = nil;
889 }
890 style:UIAlertActionStyleDefault];
891
892 // Move action.
893 [self.actionSheetCoordinator
894 addItemWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_ACTION_MOVE)
895 action:^{
896 std::set<const BookmarkNode*> nodes;
897 nodes.insert(node);
898 [weakSelf moveNodes:nodes];
899 weakSelf.get().actionSheetCoordinator = nil;
900 }
901 style:UIAlertActionStyleDefault];
902
903 // Delete action.
904 [self.actionSheetCoordinator
905 addItemWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_ACTION_DELETE)
906 action:^{
907 std::set<const BookmarkNode*> nodes;
908 nodes.insert(node);
909 [weakSelf deleteNodes:nodes];
910 weakSelf.get().actionSheetCoordinator = nil;
911 }
912 style:UIAlertActionStyleDestructive];
913
914 // Cancel action.
915 [self.actionSheetCoordinator
916 addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
917 action:^{
918 weakSelf.get().actionSheetCoordinator = nil;
919 }
920 style:UIAlertActionStyleCancel];
921
922 [self.actionSheetCoordinator start];
923 }
924
925 - (void)bookmarkCollectionView:(BookmarkCollectionView*)view
926 didLongPressCell:(UICollectionViewCell*)cell
927 forBookmark:(const BookmarkNode*)node {
928 DCHECK(!self.editing);
929 [self selectFirstNode:node withCell:cell];
930 }
931
932 - (BOOL)bookmarkCollectionViewShouldShowPromoCell:
933 (BookmarkCollectionView*)collectionView {
934 return self.bookmarkPromoController.promoState;
935 }
936
937 - (void)bookmarkCollectionViewShowSignIn:(BookmarkCollectionView*)view {
938 [self.bookmarkPromoController showSignIn];
939 }
940
941 - (void)bookmarkCollectionViewDismissPromo:(BookmarkCollectionView*)view {
942 [self.bookmarkPromoController hidePromoCell];
943 }
944
945 #pragma mark Action Sheet Callbacks
946
947 - (void)selectFirstNode:(const BookmarkNode*)node
948 withCell:(UICollectionViewCell*)cell {
949 DCHECK(!self.editing);
950 [self insertEditNode:node atIndexPath:[self indexPathForCell:cell]];
951 [self setEditing:YES animated:YES];
952 }
953
954 - (void)editNode:(const BookmarkNode*)node withCell:(BookmarkItemCell*)cell {
955 DCHECK(!self.editViewController);
956 DCHECK(!self.folderEditor);
957 UIViewController* editorController = nil;
958 if (node->is_folder()) {
959 BookmarkFolderEditorViewController* folderEditor =
960 [BookmarkFolderEditorViewController
961 folderEditorWithBookmarkModel:self.bookmarks
962 folder:node
963 browserState:self.browserState];
964 folderEditor.delegate = self;
965 self.folderEditor = folderEditor;
966 editorController = folderEditor;
967 } else {
968 base::scoped_nsobject<BookmarkEditViewController> controller([
969 [BookmarkEditViewController alloc] initWithBookmark:node
970 browserState:self.browserState]);
971 self.editViewController = controller;
972 self.editViewController.delegate = self;
973 editorController = self.editViewController;
974 }
975 DCHECK(editorController);
976 base::scoped_nsobject<UINavigationController> navController(
977 [[BookmarkNavigationController alloc]
978 initWithRootViewController:editorController]);
979 navController.get().modalPresentationStyle = UIModalPresentationFormSheet;
980 [self.view.window.rootViewController presentViewController:navController
981 animated:YES
982 completion:NULL];
983 }
984
985 - (void)moveNodes:(const std::set<const BookmarkNode*>&)nodes {
986 DCHECK(!self.folderSelector);
987 DCHECK(nodes.size() > 0);
988 const BookmarkNode* editedNode = *(nodes.begin());
989 const BookmarkNode* selectedFolder = editedNode->parent();
990 self.folderSelector = base::scoped_nsobject<BookmarkFolderViewController>(
991 [[BookmarkFolderViewController alloc]
992 initWithBookmarkModel:self.bookmarks
993 allowsNewFolders:YES
994 editedNodes:nodes
995 allowsCancel:YES
996 selectedFolder:selectedFolder]);
997 self.folderSelector.delegate = self;
998 base::scoped_nsobject<UINavigationController> controller(
999 [[BookmarkNavigationController alloc]
1000 initWithRootViewController:self.folderSelector]);
1001 controller.get().modalPresentationStyle = UIModalPresentationFormSheet;
1002 [self.view.window.rootViewController presentViewController:controller
1003 animated:YES
1004 completion:NULL];
1005 }
1006
1007 - (void)deleteNodes:(const std::set<const BookmarkNode*>&)nodes {
1008 DCHECK_GE(nodes.size(), 1u);
1009 bookmark_utils_ios::DeleteBookmarksWithUndoToast(nodes, self.bookmarks,
1010 self.browserState);
1011 }
1012
1013 #pragma mark - BookmarkFolderCollectionViewDelegate
1014
1015 - (void)bookmarkFolderCollectionView:(BookmarkFolderCollectionView*)view
1016 selectedFolderForNavigation:(const BookmarkNode*)folder {
1017 BookmarkMenuItem* menuItem = nil;
1018 if (view == self.folderView) {
1019 const BookmarkNode* parent = RootLevelFolderForNode(folder, self.bookmarks);
1020 menuItem =
1021 [BookmarkMenuItem folderMenuItemForNode:folder rootAncestor:parent];
1022 } else {
1023 NOTREACHED();
1024 return;
1025 }
1026 [self updatePrimaryMenuItem:menuItem animated:YES];
1027 }
1028
1029 #pragma mark - BookmarkEditViewControllerDelegate
1030
1031 - (BOOL)bookmarkEditor:(BookmarkEditViewController*)controller
1032 shoudDeleteAllOccurencesOfBookmark:(const BookmarkNode*)bookmark {
1033 return NO;
1034 }
1035
1036 - (void)bookmarkEditorWantsDismissal:(BookmarkEditViewController*)controller {
1037 self.editViewController.delegate = nil;
1038 self.editViewController = nil;
1039 [controller dismissViewControllerAnimated:YES completion:NULL];
1040
1041 // The editViewController can be displayed from the menu button, or from the
1042 // edit button in edit mode. Either way, after it's dismissed, edit mode
1043 // should be off.
1044 [self setEditing:NO animated:NO];
1045 }
1046
1047 #pragma mark - BookmarkFolderViewControllerDelegate
1048
1049 - (void)folderPicker:(BookmarkFolderViewController*)folderPicker
1050 didFinishWithFolder:(const BookmarkNode*)folder {
1051 DCHECK(folder);
1052 DCHECK(!folder->is_url());
1053 DCHECK_GE(folderPicker.editedNodes.size(), 1u);
1054
1055 bookmark_utils_ios::MoveBookmarksWithUndoToast(
1056 folderPicker.editedNodes, self.bookmarks, folder, self.browserState);
1057
1058 [self setEditing:NO animated:NO];
1059 [[folderPicker presentingViewController] dismissViewControllerAnimated:YES
1060 completion:nil];
1061 self.folderSelector.delegate = nil;
1062 self.folderSelector = nil;
1063 }
1064
1065 - (void)folderPickerDidCancel:(BookmarkFolderViewController*)folderPicker {
1066 [self setEditing:NO animated:NO];
1067 [[folderPicker presentingViewController] dismissViewControllerAnimated:YES
1068 completion:nil];
1069 self.folderSelector.delegate = nil;
1070 self.folderSelector = nil;
1071 }
1072
1073 #pragma mark - BookmarkFolderEditorViewControllerDelegate
1074
1075 - (void)bookmarkFolderEditor:(BookmarkFolderEditorViewController*)folderEditor
1076 didFinishEditingFolder:(const BookmarkNode*)folder {
1077 DCHECK(folder);
1078 [[folderEditor presentingViewController] dismissViewControllerAnimated:YES
1079 completion:nil];
1080 self.folderEditor.delegate = nil;
1081 self.folderEditor = nil;
1082 }
1083
1084 - (void)bookmarkFolderEditorDidDeleteEditedFolder:
1085 (BookmarkFolderEditorViewController*)folderEditor {
1086 [[folderEditor presentingViewController] dismissViewControllerAnimated:YES
1087 completion:nil];
1088 self.folderEditor.delegate = nil;
1089 self.folderEditor = nil;
1090 }
1091
1092 - (void)bookmarkFolderEditorDidCancel:
1093 (BookmarkFolderEditorViewController*)folderEditor {
1094 [[folderEditor presentingViewController] dismissViewControllerAnimated:YES
1095 completion:nil];
1096 self.folderEditor.delegate = nil;
1097 self.folderEditor = nil;
1098 }
1099
1100 #pragma mark - Internal Utility Methods
1101
1102 - (void)deleteSelectedNodes {
1103 [self deleteNodes:_editNodes];
1104 }
1105
1106 - (void)moveEditingNodesToFolder:(const BookmarkNode*)folder {
1107 // The UI only supports moving nodes when there are at least one selected.
1108 DCHECK_GE(_editNodes.size(), 1u);
1109
1110 bookmark_utils_ios::MoveBookmarksWithUndoToast(_editNodes, self.bookmarks,
1111 folder, self.browserState);
1112 }
1113
1114 - (void)cachePosition {
1115 if ([self primaryView]) {
1116 bookmark_utils_ios::CachePosition(
1117 [[self primaryView] contentPositionInPortraitOrientation],
1118 [self primaryMenuItem]);
1119 }
1120 }
1121
1122 #pragma mark - Navigation bar
1123
1124 - (CGRect)navigationBarFrame {
1125 return CGRectMake(0, 0, CGRectGetWidth(self.view.bounds),
1126 [BookmarkNavigationBar expectedContentViewHeight] +
1127 kNavigationBarTopMargin);
1128 }
1129
1130 - (void)updateNavigationBarAnimated:(BOOL)animated
1131 orientation:(UIInterfaceOrientation)orientation {
1132 CGFloat duration = animated ? bookmark_utils_ios::menuAnimationDuration : 0;
1133 [self updateNavigationBarWithDuration:duration orientation:orientation];
1134 }
1135
1136 - (void)updateNavigationBarWithDuration:(CGFloat)duration
1137 orientation:(UIInterfaceOrientation)orientation {
1138 [self.navigationBar setTitle:[self.primaryMenuItem titleForNavigationBar]];
1139 if ([self shouldShowEditButton])
1140 [self.navigationBar showEditButtonWithAnimationDuration:duration];
1141 else
1142 [self.navigationBar hideEditButtonWithAnimationDuration:duration];
1143
1144 if ([self shouldShowBackButton])
1145 [self.navigationBar showBackButtonInsteadOfMenuButton:duration];
1146 else
1147 [self.navigationBar showMenuButtonInsteadOfBackButton:duration];
1148 }
1149
1150 - (BOOL)shouldShowEditButton {
1151 if (self.primaryMenuItem.type != bookmarks::MenuItemFolder)
1152 return NO;
1153 // The type is MenuItemFolder, so it is safe to access |folder|.
1154 return !self.bookmarks->is_permanent_node(self.primaryMenuItem.folder);
1155 }
1156
1157 - (BOOL)shouldShowBackButton {
1158 if (self.primaryMenuItem.type != bookmarks::MenuItemFolder)
1159 return NO;
1160 // The type is MenuItemFolder, so it is safe to access |folder|.
1161 const BookmarkNode* folder = self.primaryMenuItem.folder;
1162 // Show the back button iff the folder or its immediate parent is a permanent
1163 // primary folder.
1164 BOOL isTopFolder = IsPrimaryPermanentNode(folder, self.bookmarks) ||
1165 IsPrimaryPermanentNode(folder->parent(), self.bookmarks);
1166 return !isTopFolder;
1167 }
1168
1169 #pragma mark Navigation Bar Callbacks
1170
1171 - (void)navigationBarWantsEditing:(id)sender {
1172 DCHECK(self.primaryMenuItem.type == bookmarks::MenuItemFolder);
1173 const BookmarkNode* folder = self.primaryMenuItem.folder;
1174 BookmarkFolderEditorViewController* folderEditor =
1175 [BookmarkFolderEditorViewController
1176 folderEditorWithBookmarkModel:self.bookmarks
1177 folder:folder
1178 browserState:self.browserState];
1179 folderEditor.delegate = self;
1180 self.folderEditor = folderEditor;
1181
1182 base::scoped_nsobject<BookmarkNavigationController> navController(
1183 [[BookmarkNavigationController alloc]
1184 initWithRootViewController:self.folderEditor]);
1185 navController.get().modalPresentationStyle = UIModalPresentationFormSheet;
1186 [self.view.window.rootViewController presentViewController:navController
1187 animated:YES
1188 completion:NULL];
1189 }
1190
1191 - (void)navigationBarBack:(id)sender {
1192 DCHECK([self shouldShowBackButton]);
1193
1194 // Go to the parent folder.
1195 DCHECK(self.primaryMenuItem.type == bookmarks::MenuItemFolder);
1196 const BookmarkNode* parentFolder = self.primaryMenuItem.folder->parent();
1197 const BookmarkNode* rootAncestor =
1198 RootLevelFolderForNode(parentFolder, self.bookmarks);
1199 BookmarkMenuItem* menuItem =
1200 [BookmarkMenuItem folderMenuItemForNode:parentFolder
1201 rootAncestor:rootAncestor];
1202 [self updatePrimaryMenuItem:menuItem animated:YES];
1203 }
1204
1205 #pragma mark - NewTabPagePanelProtocol
1206
1207 - (void)reload {
1208 }
1209
1210 - (void)wasShown {
1211 }
1212
1213 - (void)wasHidden {
1214 [self cachePosition];
1215 }
1216
1217 - (void)dismissModals {
1218 [self.actionSheetCoordinator stop];
1219 self.actionSheetCoordinator = nil;
1220 [self.editViewController dismiss];
1221 }
1222
1223 - (void)dismissKeyboard {
1224 // Uses self.contentView directly instead of going throught self.view to
1225 // avoid creating the view hierarchy unnecessarily.
1226 [self.contentView endEditing:YES];
1227 }
1228
1229 - (void)setScrollsToTop:(BOOL)enabled {
1230 self.scrollToTop = enabled;
1231 [[self primaryView] setScrollsToTop:self.scrollToTop];
1232 }
1233
1234 - (UIView*)view {
1235 if (!self.contentView) {
1236 _contentView = [[ContentView alloc] initWithFrame:CGRectZero];
1237 _contentView.delegate = self;
1238 self.contentView.backgroundColor =
1239 bookmark_utils_ios::mainBackgroundColor();
1240 base::scoped_nsobject<BookmarkNavigationBar> bar(
1241 [[BookmarkNavigationBar alloc] initWithFrame:CGRectZero]);
1242 self.navigationBar = bar;
1243 self.navigationBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
1244
1245 [self.navigationBar setEditTarget:self
1246 action:@selector(navigationBarWantsEditing:)];
1247 [self.navigationBar setBackTarget:self
1248 action:@selector(navigationBarBack:)];
1249
1250 [self.navigationBar setMenuTarget:self
1251 action:@selector(toggleMenuAnimated)];
1252
1253 [self.view addSubview:self.navigationBar];
1254
1255 if (self.bookmarks->loaded())
1256 [self loadBookmarkViews];
1257 else
1258 [self loadWaitingView];
1259 }
1260 return self.contentView;
1261 }
1262
1263 - (CGFloat)alphaForBottomShadow {
1264 return 0;
1265 }
1266
1267 #pragma mark - BookmarkModelBridgeObserver
1268
1269 - (void)bookmarkModelLoaded {
1270 if (!self.contentView)
1271 return;
1272
1273 DCHECK(self.waitForModelView);
1274 base::WeakNSObject<BookmarkHomeTabletNTPController> weakSelf(self);
1275 [self.waitForModelView stopWaitingWithCompletion:^{
1276 base::scoped_nsobject<BookmarkHomeTabletNTPController> strongSelf(
1277 [weakSelf retain]);
1278 // Early return if the controller has been deallocated.
1279 if (!strongSelf)
1280 return;
1281 [UIView animateWithDuration:0.2
1282 animations:^{
1283 strongSelf.get().waitForModelView.alpha = 0.0;
1284 }
1285 completion:^(BOOL finished) {
1286 [strongSelf.get().waitForModelView removeFromSuperview];
1287 strongSelf.get().waitForModelView = nil;
1288 }];
1289 [strongSelf loadBookmarkViews];
1290 }];
1291 }
1292
1293 - (void)bookmarkNodeChanged:(const BookmarkNode*)bookmarkNode {
1294 // The title of the folder may have changed.
1295 if (self.primaryMenuItem.type == bookmarks::MenuItemFolder &&
1296 self.primaryMenuItem.folder == bookmarkNode) {
1297 UIInterfaceOrientation orient = GetInterfaceOrientation();
1298 [self updateNavigationBarAnimated:NO orientation:orient];
1299 }
1300 }
1301
1302 - (void)bookmarkNodeChildrenChanged:(const BookmarkNode*)bookmarkNode {
1303 // The node has not changed, but the ordering and existence of its children
1304 // have changed.
1305 }
1306
1307 - (void)bookmarkNode:(const BookmarkNode*)bookmarkNode
1308 movedFromParent:(const BookmarkNode*)oldParent
1309 toParent:(const BookmarkNode*)newParent {
1310 // The node has moved to a new parent folder.
1311 }
1312
1313 - (void)bookmarkNodeDeleted:(const BookmarkNode*)node
1314 fromFolder:(const BookmarkNode*)folder {
1315 [self removeEditNode:node atIndexPath:nil];
1316 }
1317
1318 - (void)bookmarkModelRemovedAllNodes {
1319 // All non-permanent nodes have been removed.
1320 [self setEditing:NO animated:YES];
1321 }
1322
1323 #pragma mark - BookmarkPromoControllerDelegate
1324
1325 - (void)promoStateChanged:(BOOL)promoEnabled {
1326 [self.allItemsView.collectionView reloadData];
1327 // This is required to workaround a crash seen once on iOS 7.1 when
1328 // the collection gets two reloadData without getting a call to layout
1329 // subviews, the collection view will reuse some cached data for the perfoming
1330 // the layout which are invalid after the second call to reloadData.
1331 // Forcing the layout invalidation after each reloadData seems to fix the
1332 // issue.
1333 [self.allItemsView.collectionView.collectionViewLayout invalidateLayout];
1334 [self.folderView
1335 promoStateChangedAnimated:self.folderView == [self primaryView]];
1336 }
1337
1338 - (NSIndexPath*)indexPathForCell:(UICollectionViewCell*)cell {
1339 DCHECK([self primaryView].collectionView);
1340 NSIndexPath* indexPath =
1341 [[self primaryView].collectionView indexPathForCell:cell];
1342 return indexPath;
1343 }
1344
1345 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698