OLD | NEW |
(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_folder_view_controller.h" |
| 6 |
| 7 #include <memory> |
| 8 #include <vector> |
| 9 |
| 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/strings/sys_string_conversions.h" |
| 15 #include "components/bookmarks/browser/bookmark_model.h" |
| 16 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.
h" |
| 17 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_table_view_cell.h" |
| 18 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h" |
| 19 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h" |
| 20 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" |
| 21 #import "ios/chrome/browser/ui/icons/chrome_icon.h" |
| 22 #import "ios/chrome/browser/ui/material_components/utils.h" |
| 23 #include "ios/chrome/grit/ios_strings.h" |
| 24 #import "ios/third_party/material_components_ios/src/components/AppBar/src/Mater
ialAppBar.h" |
| 25 #include "ui/base/l10n/l10n_util_mac.h" |
| 26 |
| 27 using bookmarks::BookmarkNode; |
| 28 |
| 29 namespace { |
| 30 |
| 31 // The height of every folder cell. |
| 32 const CGFloat kFolderCellHeight = 48.0; |
| 33 |
| 34 // Height of section headers/footers. |
| 35 const CGFloat kSectionHeaderHeight = 8.0; |
| 36 const CGFloat kSectionFooterHeight = 8.0; |
| 37 |
| 38 // Enum for the available sections. |
| 39 // First section displays a cell to create a new folder. |
| 40 // The second section displays as many folders as are available. |
| 41 typedef enum { |
| 42 BookmarkFolderSectionDefault = 0, |
| 43 BookmarkFolderSectionFolders, |
| 44 } BookmarkFolderSection; |
| 45 const NSInteger BookmarkFolderSectionCount = 2; |
| 46 |
| 47 } // namespace |
| 48 |
| 49 @interface BookmarkFolderViewController ()< |
| 50 BookmarkFolderEditorViewControllerDelegate, |
| 51 BookmarkModelBridgeObserver, |
| 52 UITableViewDataSource, |
| 53 UITableViewDelegate> { |
| 54 std::set<const BookmarkNode*> _editedNodes; |
| 55 std::vector<const BookmarkNode*> _folders; |
| 56 std::unique_ptr<bookmarks::BookmarkModelBridge> _modelBridge; |
| 57 base::scoped_nsobject<MDCAppBar> _appBar; |
| 58 base::mac::ObjCPropertyReleaser |
| 59 _propertyReleaser_BookmarkFolderViewController; |
| 60 } |
| 61 |
| 62 // Should the controller setup Cancel and Done buttons instead of a back button. |
| 63 @property(nonatomic, assign) BOOL allowsCancel; |
| 64 |
| 65 // Should the controller setup a new-folder button. |
| 66 @property(nonatomic, assign) BOOL allowsNewFolders; |
| 67 |
| 68 // Reference to the main bookmark model. |
| 69 @property(nonatomic, assign) bookmarks::BookmarkModel* bookmarkModel; |
| 70 |
| 71 // The currently selected folder. |
| 72 @property(nonatomic, readonly) const BookmarkNode* selectedFolder; |
| 73 |
| 74 // The view controller to present when creating a new folder. |
| 75 @property(nonatomic, retain) |
| 76 BookmarkFolderEditorViewController* folderAddController; |
| 77 |
| 78 // A linear list of folders. |
| 79 @property(nonatomic, assign, readonly) |
| 80 const std::vector<const BookmarkNode*>& folders; |
| 81 |
| 82 // The table view that displays the options and folders. |
| 83 @property(nonatomic, retain) UITableView* tableView; |
| 84 |
| 85 // Returns the cell for the default section and the given |row|. |
| 86 - (BookmarkFolderTableViewCell*)defaultSectionCellForRow:(NSInteger)row; |
| 87 |
| 88 // Returns a folder cell for the folder at |row| in |self.folders|. |
| 89 - (BookmarkFolderTableViewCell*)folderSectionCellForRow:(NSInteger)row; |
| 90 |
| 91 // Reloads the folder list. |
| 92 - (void)reloadFolders; |
| 93 |
| 94 // Pushes on the navigation controller a view controller to create a new folder. |
| 95 - (void)pushFolderAddViewController; |
| 96 |
| 97 // Called when the user taps on a folder row. The cell is checked, the UI is |
| 98 // locked so that the user can't interact with it, then the delegate is |
| 99 // notified. Usual implementations of this delegate callback are to pop or |
| 100 // dismiss this controller on selection. The delay is here to let the user get a |
| 101 // visual feedback of the selection before this view disappears. |
| 102 - (void)delayedNotifyDelegateOfSelection; |
| 103 |
| 104 @end |
| 105 |
| 106 @implementation BookmarkFolderViewController |
| 107 |
| 108 @synthesize allowsCancel = _allowsCancel; |
| 109 @synthesize allowsNewFolders = _allowsNewFolders; |
| 110 @synthesize bookmarkModel = _bookmarkModel; |
| 111 @synthesize editedNodes = _editedNodes; |
| 112 @synthesize folderAddController = _folderAddController; |
| 113 @synthesize delegate = _delegate; |
| 114 @synthesize folders = _folders; |
| 115 @synthesize tableView = _tableView; |
| 116 @synthesize selectedFolder = _selectedFolder; |
| 117 |
| 118 - (instancetype)initWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel |
| 119 allowsNewFolders:(BOOL)allowsNewFolders |
| 120 editedNodes: |
| 121 (const std::set<const BookmarkNode*>&)nodes |
| 122 allowsCancel:(BOOL)allowsCancel |
| 123 selectedFolder:(const BookmarkNode*)selectedFolder { |
| 124 DCHECK(bookmarkModel); |
| 125 DCHECK(bookmarkModel->loaded()); |
| 126 DCHECK(selectedFolder == NULL || selectedFolder->is_folder()); |
| 127 self = [super initWithNibName:nil bundle:nil]; |
| 128 if (self) { |
| 129 _propertyReleaser_BookmarkFolderViewController.Init( |
| 130 self, [BookmarkFolderViewController class]); |
| 131 _allowsCancel = allowsCancel; |
| 132 _allowsNewFolders = allowsNewFolders; |
| 133 _bookmarkModel = bookmarkModel; |
| 134 _editedNodes = nodes; |
| 135 _selectedFolder = selectedFolder; |
| 136 |
| 137 // Set up the bookmark model oberver. |
| 138 _modelBridge.reset( |
| 139 new bookmarks::BookmarkModelBridge(self, _bookmarkModel)); |
| 140 |
| 141 _appBar.reset([[MDCAppBar alloc] init]); |
| 142 [self addChildViewController:[_appBar headerViewController]]; |
| 143 } |
| 144 return self; |
| 145 } |
| 146 |
| 147 - (void)changeSelectedFolder:(const BookmarkNode*)selectedFolder { |
| 148 DCHECK(selectedFolder); |
| 149 DCHECK(selectedFolder->is_folder()); |
| 150 _selectedFolder = selectedFolder; |
| 151 [self.tableView reloadData]; |
| 152 } |
| 153 |
| 154 - (void)dealloc { |
| 155 _tableView.dataSource = nil; |
| 156 _tableView.delegate = nil; |
| 157 _folderAddController.delegate = nil; |
| 158 [super dealloc]; |
| 159 } |
| 160 |
| 161 - (UIStatusBarStyle)preferredStatusBarStyle { |
| 162 return UIStatusBarStyleDefault; |
| 163 } |
| 164 |
| 165 #pragma mark - View lifecycle |
| 166 |
| 167 - (void)viewDidLoad { |
| 168 [super viewDidLoad]; |
| 169 if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { |
| 170 [self setEdgesForExtendedLayout:UIRectEdgeNone]; |
| 171 } |
| 172 self.view.backgroundColor = [UIColor whiteColor]; |
| 173 self.view.accessibilityIdentifier = @"Folder Picker"; |
| 174 |
| 175 self.title = l10n_util::GetNSString(IDS_IOS_BOOKMARK_CHOOSE_GROUP_BUTTON); |
| 176 |
| 177 base::scoped_nsobject<UIBarButtonItem> doneItem([[UIBarButtonItem alloc] |
| 178 initWithTitle:l10n_util::GetNSString( |
| 179 IDS_IOS_BOOKMARK_EDIT_MODE_EXIT_MOBILE) |
| 180 style:UIBarButtonItemStylePlain |
| 181 target:self |
| 182 action:@selector(done:)]); |
| 183 doneItem.get().accessibilityIdentifier = @"Done"; |
| 184 self.navigationItem.rightBarButtonItem = doneItem; |
| 185 |
| 186 if (self.allowsCancel) { |
| 187 UIBarButtonItem* cancelItem = |
| 188 [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon closeIcon] |
| 189 target:self |
| 190 action:@selector(cancel:)]; |
| 191 cancelItem.accessibilityLabel = |
| 192 l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_CANCEL_BUTTON_LABEL); |
| 193 cancelItem.accessibilityIdentifier = @"Cancel"; |
| 194 self.navigationItem.leftBarButtonItem = cancelItem; |
| 195 } else { |
| 196 UIBarButtonItem* backItem = |
| 197 [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon backIcon] |
| 198 target:self |
| 199 action:@selector(back:)]; |
| 200 backItem.accessibilityLabel = |
| 201 l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_BACK_LABEL); |
| 202 backItem.accessibilityIdentifier = @"Back"; |
| 203 self.navigationItem.leftBarButtonItem = backItem; |
| 204 } |
| 205 |
| 206 // The table view. |
| 207 base::scoped_nsobject<UITableView> tableView([[UITableView alloc] |
| 208 initWithFrame:self.view.bounds |
| 209 style:UITableViewStylePlain]); |
| 210 tableView.get().dataSource = self; |
| 211 tableView.get().delegate = self; |
| 212 tableView.get().autoresizingMask = |
| 213 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; |
| 214 tableView.get().separatorStyle = UITableViewCellSeparatorStyleNone; |
| 215 [self.view addSubview:tableView]; |
| 216 [self.view sendSubviewToBack:tableView]; |
| 217 self.tableView = tableView; |
| 218 |
| 219 // Add the app bar to the view hierarchy. This must be done last, so that the |
| 220 // app bar's views are the frontmost. |
| 221 ConfigureAppBarWithCardStyle(_appBar); |
| 222 [_appBar headerViewController].headerView.trackingScrollView = self.tableView; |
| 223 [_appBar addSubviewsToParent]; |
| 224 } |
| 225 |
| 226 - (void)viewWillAppear:(BOOL)animated { |
| 227 [super viewWillAppear:animated]; |
| 228 [self reloadFolders]; |
| 229 } |
| 230 |
| 231 - (UIViewController*)childViewControllerForStatusBarHidden { |
| 232 return [_appBar headerViewController]; |
| 233 } |
| 234 |
| 235 - (UIViewController*)childViewControllerForStatusBarStyle { |
| 236 return [_appBar headerViewController]; |
| 237 } |
| 238 |
| 239 #pragma mark - Accessibility |
| 240 |
| 241 - (BOOL)accessibilityPerformEscape { |
| 242 [self.delegate folderPickerDidCancel:self]; |
| 243 return YES; |
| 244 } |
| 245 |
| 246 #pragma mark - UIScrollViewDelegate |
| 247 |
| 248 - (void)scrollViewDidScroll:(UIScrollView*)scrollView { |
| 249 MDCFlexibleHeaderView* headerView = [_appBar headerViewController].headerView; |
| 250 if (scrollView == headerView.trackingScrollView) { |
| 251 [headerView trackingScrollViewDidScroll]; |
| 252 } |
| 253 } |
| 254 |
| 255 - (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView { |
| 256 MDCFlexibleHeaderView* headerView = [_appBar headerViewController].headerView; |
| 257 if (scrollView == headerView.trackingScrollView) { |
| 258 [headerView trackingScrollViewDidEndDecelerating]; |
| 259 } |
| 260 } |
| 261 |
| 262 - (void)scrollViewDidEndDragging:(UIScrollView*)scrollView |
| 263 willDecelerate:(BOOL)decelerate { |
| 264 MDCFlexibleHeaderView* headerView = [_appBar headerViewController].headerView; |
| 265 if (scrollView == headerView.trackingScrollView) { |
| 266 [headerView trackingScrollViewDidEndDraggingWillDecelerate:decelerate]; |
| 267 } |
| 268 } |
| 269 |
| 270 - (void)scrollViewWillEndDragging:(UIScrollView*)scrollView |
| 271 withVelocity:(CGPoint)velocity |
| 272 targetContentOffset:(inout CGPoint*)targetContentOffset { |
| 273 MDCFlexibleHeaderView* headerView = [_appBar headerViewController].headerView; |
| 274 if (scrollView == headerView.trackingScrollView) { |
| 275 [headerView |
| 276 trackingScrollViewWillEndDraggingWithVelocity:velocity |
| 277 targetContentOffset:targetContentOffset]; |
| 278 } |
| 279 } |
| 280 |
| 281 #pragma mark - UITableViewDataSource |
| 282 |
| 283 - (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView { |
| 284 return BookmarkFolderSectionCount; |
| 285 } |
| 286 |
| 287 - (NSInteger)tableView:(UITableView*)tableView |
| 288 numberOfRowsInSection:(NSInteger)section { |
| 289 switch (static_cast<BookmarkFolderSection>(section)) { |
| 290 case BookmarkFolderSectionDefault: |
| 291 return [self shouldShowDefaultSection] ? 1 : 0; |
| 292 |
| 293 case BookmarkFolderSectionFolders: |
| 294 return self.folders.size(); |
| 295 } |
| 296 NOTREACHED(); |
| 297 return 0; |
| 298 } |
| 299 |
| 300 - (UITableViewCell*)tableView:(UITableView*)tableView |
| 301 cellForRowAtIndexPath:(NSIndexPath*)indexPath { |
| 302 BookmarkFolderTableViewCell* cell = nil; |
| 303 switch (static_cast<BookmarkFolderSection>(indexPath.section)) { |
| 304 case BookmarkFolderSectionDefault: |
| 305 cell = [self defaultSectionCellForRow:indexPath.row]; |
| 306 break; |
| 307 |
| 308 case BookmarkFolderSectionFolders: |
| 309 cell = [self folderSectionCellForRow:indexPath.row]; |
| 310 break; |
| 311 } |
| 312 return cell; |
| 313 } |
| 314 |
| 315 #pragma mark - UITableViewDelegate |
| 316 |
| 317 - (CGFloat)tableView:(UITableView*)tableView |
| 318 heightForRowAtIndexPath:(NSIndexPath*)indexPath { |
| 319 return kFolderCellHeight; |
| 320 } |
| 321 |
| 322 - (CGFloat)tableView:(UITableView*)tableView |
| 323 heightForHeaderInSection:(NSInteger)section { |
| 324 switch (static_cast<BookmarkFolderSection>(section)) { |
| 325 case BookmarkFolderSectionDefault: |
| 326 return [self shouldShowDefaultSection] ? kSectionHeaderHeight : 0; |
| 327 |
| 328 case BookmarkFolderSectionFolders: |
| 329 return kSectionHeaderHeight; |
| 330 } |
| 331 NOTREACHED(); |
| 332 return 0; |
| 333 } |
| 334 |
| 335 - (UIView*)tableView:(UITableView*)tableView |
| 336 viewForHeaderInSection:(NSInteger)section { |
| 337 CGRect headerViewFrame = |
| 338 CGRectMake(0, 0, CGRectGetWidth(tableView.frame), |
| 339 [self tableView:tableView heightForHeaderInSection:section]); |
| 340 UIView* headerView = |
| 341 [[[UIView alloc] initWithFrame:headerViewFrame] autorelease]; |
| 342 if (section == BookmarkFolderSectionFolders && |
| 343 [self shouldShowDefaultSection]) { |
| 344 CGRect separatorFrame = |
| 345 CGRectMake(0, 0, CGRectGetWidth(headerView.bounds), |
| 346 1.0 / [[UIScreen mainScreen] scale]); // 1-pixel divider. |
| 347 base::scoped_nsobject<UIView> separator( |
| 348 [[UIView alloc] initWithFrame:separatorFrame]); |
| 349 separator.get().autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | |
| 350 UIViewAutoresizingFlexibleWidth; |
| 351 separator.get().backgroundColor = bookmark_utils_ios::separatorColor(); |
| 352 [headerView addSubview:separator]; |
| 353 } |
| 354 return headerView; |
| 355 } |
| 356 |
| 357 - (CGFloat)tableView:(UITableView*)tableView |
| 358 heightForFooterInSection:(NSInteger)section { |
| 359 switch (static_cast<BookmarkFolderSection>(section)) { |
| 360 case BookmarkFolderSectionDefault: |
| 361 return [self shouldShowDefaultSection] ? kSectionFooterHeight : 0; |
| 362 |
| 363 case BookmarkFolderSectionFolders: |
| 364 return kSectionFooterHeight; |
| 365 } |
| 366 NOTREACHED(); |
| 367 return 0; |
| 368 } |
| 369 |
| 370 - (UIView*)tableView:(UITableView*)tableView |
| 371 viewForFooterInSection:(NSInteger)section { |
| 372 return [[[UIView alloc] init] autorelease]; |
| 373 } |
| 374 |
| 375 - (void)tableView:(UITableView*)tableView |
| 376 didSelectRowAtIndexPath:(NSIndexPath*)indexPath { |
| 377 [tableView deselectRowAtIndexPath:indexPath animated:YES]; |
| 378 switch (static_cast<BookmarkFolderSection>(indexPath.section)) { |
| 379 case BookmarkFolderSectionDefault: |
| 380 [self pushFolderAddViewController]; |
| 381 break; |
| 382 |
| 383 case BookmarkFolderSectionFolders: { |
| 384 const BookmarkNode* folder = self.folders[indexPath.row]; |
| 385 [self changeSelectedFolder:folder]; |
| 386 [self delayedNotifyDelegateOfSelection]; |
| 387 break; |
| 388 } |
| 389 } |
| 390 } |
| 391 |
| 392 #pragma mark - BookmarkFolderEditorViewControllerDelegate |
| 393 |
| 394 - (void)bookmarkFolderEditor:(BookmarkFolderEditorViewController*)folderEditor |
| 395 didFinishEditingFolder:(const BookmarkNode*)folder { |
| 396 DCHECK(folder); |
| 397 [self reloadFolders]; |
| 398 [self changeSelectedFolder:folder]; |
| 399 [self delayedNotifyDelegateOfSelection]; |
| 400 } |
| 401 |
| 402 - (void)bookmarkFolderEditorDidDeleteEditedFolder: |
| 403 (BookmarkFolderEditorViewController*)folderEditor { |
| 404 NOTREACHED(); |
| 405 } |
| 406 |
| 407 - (void)bookmarkFolderEditorDidCancel: |
| 408 (BookmarkFolderEditorViewController*)folderEditor { |
| 409 [self.navigationController popViewControllerAnimated:YES]; |
| 410 self.folderAddController.delegate = nil; |
| 411 self.folderAddController = nil; |
| 412 } |
| 413 |
| 414 #pragma mark - BookmarkModelBridgeObserver |
| 415 |
| 416 - (void)bookmarkModelLoaded { |
| 417 // The bookmark model is assumed to be loaded when this controller is created. |
| 418 NOTREACHED(); |
| 419 } |
| 420 |
| 421 - (void)bookmarkNodeChanged:(const BookmarkNode*)bookmarkNode { |
| 422 if (!bookmarkNode->is_folder()) |
| 423 return; |
| 424 [self reloadFolders]; |
| 425 } |
| 426 |
| 427 - (void)bookmarkNodeChildrenChanged:(const BookmarkNode*)bookmarkNode { |
| 428 [self reloadFolders]; |
| 429 } |
| 430 |
| 431 - (void)bookmarkNode:(const BookmarkNode*)bookmarkNode |
| 432 movedFromParent:(const BookmarkNode*)oldParent |
| 433 toParent:(const BookmarkNode*)newParent { |
| 434 if (bookmarkNode->is_folder()) { |
| 435 [self reloadFolders]; |
| 436 } |
| 437 } |
| 438 |
| 439 - (void)bookmarkNodeDeleted:(const BookmarkNode*)bookmarkNode |
| 440 fromFolder:(const BookmarkNode*)folder { |
| 441 if (!bookmarkNode->is_folder()) |
| 442 return; |
| 443 |
| 444 if (bookmarkNode == self.selectedFolder) { |
| 445 // The selected folder has been deleted. Fallback on the Mobile Bookmarks |
| 446 // node. |
| 447 [self changeSelectedFolder:self.bookmarkModel->mobile_node()]; |
| 448 } |
| 449 [self reloadFolders]; |
| 450 } |
| 451 |
| 452 - (void)bookmarkModelRemovedAllNodes { |
| 453 // The selected folder is no longer valid. Fallback on the Mobile Bookmarks |
| 454 // node. |
| 455 [self changeSelectedFolder:self.bookmarkModel->mobile_node()]; |
| 456 [self reloadFolders]; |
| 457 } |
| 458 |
| 459 #pragma mark - Actions |
| 460 |
| 461 - (void)done:(id)sender { |
| 462 [self.delegate folderPicker:self didFinishWithFolder:self.selectedFolder]; |
| 463 } |
| 464 |
| 465 - (void)cancel:(id)sender { |
| 466 [self.delegate folderPickerDidCancel:self]; |
| 467 } |
| 468 |
| 469 - (void)back:(id)sender { |
| 470 [self.delegate folderPickerDidCancel:self]; |
| 471 } |
| 472 |
| 473 #pragma mark - Private |
| 474 |
| 475 - (BOOL)shouldShowDefaultSection { |
| 476 return self.allowsNewFolders; |
| 477 } |
| 478 |
| 479 - (BookmarkFolderTableViewCell*)defaultSectionCellForRow:(NSInteger)row { |
| 480 DCHECK([self shouldShowDefaultSection]); |
| 481 DCHECK_EQ(0, row); |
| 482 BookmarkFolderTableViewCell* cell = [self.tableView |
| 483 dequeueReusableCellWithIdentifier:[BookmarkFolderTableViewCell |
| 484 folderCreationCellReuseIdentifier]]; |
| 485 if (!cell) { |
| 486 cell = [BookmarkFolderTableViewCell folderCreationCell]; |
| 487 } |
| 488 return cell; |
| 489 } |
| 490 |
| 491 - (BookmarkFolderTableViewCell*)folderSectionCellForRow:(NSInteger)row { |
| 492 DCHECK(row < |
| 493 [self.tableView numberOfRowsInSection:BookmarkFolderSectionFolders]); |
| 494 BookmarkFolderTableViewCell* cell = [self.tableView |
| 495 dequeueReusableCellWithIdentifier:[BookmarkFolderTableViewCell |
| 496 folderCellReuseIdentifier]]; |
| 497 if (!cell) { |
| 498 cell = [BookmarkFolderTableViewCell folderCell]; |
| 499 } |
| 500 const BookmarkNode* folder = self.folders[row]; |
| 501 NSString* title = bookmark_utils_ios::TitleForBookmarkNode(folder); |
| 502 cell.textLabel.text = title; |
| 503 cell.accessibilityIdentifier = title; |
| 504 cell.accessibilityLabel = title; |
| 505 cell.checked = (self.selectedFolder == folder); |
| 506 |
| 507 // Indentation level. |
| 508 NSInteger level = 0; |
| 509 const BookmarkNode* node = folder; |
| 510 while (node && !(self.bookmarkModel->is_root_node(node))) { |
| 511 ++level; |
| 512 node = node->parent(); |
| 513 } |
| 514 // The root node is not shown as a folder, so top level folders have a |
| 515 // level strictly positive. |
| 516 DCHECK(level > 0); |
| 517 cell.indentationLevel = level - 1; |
| 518 |
| 519 return cell; |
| 520 } |
| 521 |
| 522 - (void)reloadFolders { |
| 523 _folders = bookmark_utils_ios::VisibleNonDescendantNodes(self.editedNodes, |
| 524 self.bookmarkModel); |
| 525 [self.tableView reloadData]; |
| 526 } |
| 527 |
| 528 - (void)pushFolderAddViewController { |
| 529 DCHECK(self.allowsNewFolders); |
| 530 BookmarkFolderEditorViewController* folderCreator = |
| 531 [BookmarkFolderEditorViewController |
| 532 folderCreatorWithBookmarkModel:self.bookmarkModel |
| 533 parentFolder:self.selectedFolder]; |
| 534 folderCreator.delegate = self; |
| 535 [self.navigationController pushViewController:folderCreator animated:YES]; |
| 536 self.folderAddController = folderCreator; |
| 537 } |
| 538 |
| 539 - (void)delayedNotifyDelegateOfSelection { |
| 540 self.view.userInteractionEnabled = NO; |
| 541 base::WeakNSObject<BookmarkFolderViewController> weakSelf(self); |
| 542 dispatch_after( |
| 543 dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), |
| 544 dispatch_get_main_queue(), ^{ |
| 545 base::scoped_nsobject<BookmarkFolderViewController> strongSelf( |
| 546 [weakSelf retain]); |
| 547 // Early return if the controller has been deallocated. |
| 548 if (!strongSelf) |
| 549 return; |
| 550 strongSelf.get().view.userInteractionEnabled = YES; |
| 551 [strongSelf done:nil]; |
| 552 }); |
| 553 } |
| 554 |
| 555 @end |
OLD | NEW |