| 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_collection_view.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/strings/sys_string_conversions.h" | |
| 9 #include "components/bookmarks/browser/bookmark_model.h" | |
| 10 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h" | |
| 11 #include "ios/chrome/browser/experimental_flags.h" | |
| 12 #import "ios/chrome/browser/ui/authentication/signin_promo_view.h" | |
| 13 #import "ios/chrome/browser/ui/authentication/signin_promo_view_configurator.h" | |
| 14 #import "ios/chrome/browser/ui/authentication/signin_promo_view_consumer.h" | |
| 15 #import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h" | |
| 16 #import "ios/chrome/browser/ui/bookmarks/bookmark_collection_cells.h" | |
| 17 #import "ios/chrome/browser/ui/bookmarks/bookmark_promo_cell.h" | |
| 18 #import "ios/chrome/browser/ui/bookmarks/bookmark_signin_promo_cell.h" | |
| 19 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" | |
| 20 | |
| 21 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
| 22 #error "This file requires ARC support." | |
| 23 #endif | |
| 24 | |
| 25 using bookmarks::BookmarkNode; | |
| 26 | |
| 27 namespace { | |
| 28 // Computes the cell size based on width. | |
| 29 CGSize PreferredCellSizeForWidth(UICollectionViewCell* cell, CGFloat width) { | |
| 30 CGRect cellFrame = cell.frame; | |
| 31 cellFrame.size.width = width; | |
| 32 cellFrame.size.height = CGFLOAT_MAX; | |
| 33 cell.frame = cellFrame; | |
| 34 [cell setNeedsLayout]; | |
| 35 [cell layoutIfNeeded]; | |
| 36 CGSize result = | |
| 37 [cell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize | |
| 38 withHorizontalFittingPriority:UILayoutPriorityRequired | |
| 39 verticalFittingPriority:UILayoutPriorityDefaultLow]; | |
| 40 cellFrame.size = result; | |
| 41 cell.frame = cellFrame; | |
| 42 return result; | |
| 43 } | |
| 44 } | |
| 45 | |
| 46 @interface BookmarkFolderCollectionView ()<BookmarkPromoCellDelegate, | |
| 47 SigninPromoViewConsumer> { | |
| 48 // A vector of folders to display in the collection view. | |
| 49 std::vector<const BookmarkNode*> _subFolders; | |
| 50 // A vector of bookmark urls to display in the collection view. | |
| 51 std::vector<const BookmarkNode*> _subItems; | |
| 52 | |
| 53 // True if the promo is visible. | |
| 54 BOOL _promoVisible; | |
| 55 | |
| 56 // Mediator, helper for the sign-in promo view. | |
| 57 SigninPromoViewMediator* _signinPromoViewMediator; | |
| 58 } | |
| 59 @property(nonatomic, assign) const bookmarks::BookmarkNode* folder; | |
| 60 | |
| 61 // Section indices. | |
| 62 @property(nonatomic, readonly, assign) NSInteger promoSection; | |
| 63 @property(nonatomic, readonly, assign) NSInteger folderSection; | |
| 64 @property(nonatomic, readonly, assign) NSInteger itemsSection; | |
| 65 @property(nonatomic, readonly, assign) NSInteger sectionCount; | |
| 66 | |
| 67 @end | |
| 68 | |
| 69 @implementation BookmarkFolderCollectionView | |
| 70 @synthesize delegate = _delegate; | |
| 71 @synthesize folder = _folder; | |
| 72 | |
| 73 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState | |
| 74 frame:(CGRect)frame { | |
| 75 self = [super initWithBrowserState:browserState frame:frame]; | |
| 76 if (self) { | |
| 77 [self updateCollectionView]; | |
| 78 } | |
| 79 return self; | |
| 80 } | |
| 81 | |
| 82 - (void)setDelegate:(id<BookmarkFolderCollectionViewDelegate>)delegate { | |
| 83 _delegate = delegate; | |
| 84 [self promoStateChangedAnimated:NO]; | |
| 85 } | |
| 86 | |
| 87 - (NSInteger)promoSection { | |
| 88 return [self shouldShowPromoCell] ? 0 : -1; | |
| 89 } | |
| 90 | |
| 91 - (NSInteger)folderSection { | |
| 92 return [self shouldShowPromoCell] ? 1 : 0; | |
| 93 } | |
| 94 | |
| 95 - (NSInteger)itemsSection { | |
| 96 return [self shouldShowPromoCell] ? 2 : 1; | |
| 97 } | |
| 98 | |
| 99 - (NSInteger)sectionCount { | |
| 100 return [self shouldShowPromoCell] ? 3 : 2; | |
| 101 } | |
| 102 | |
| 103 - (void)updateCollectionView { | |
| 104 if (!self.bookmarkModel->loaded()) | |
| 105 return; | |
| 106 | |
| 107 // Regenerate the list of all bookmarks. | |
| 108 _subFolders = std::vector<const BookmarkNode*>(); | |
| 109 _subItems = std::vector<const BookmarkNode*>(); | |
| 110 | |
| 111 if (self.folder) { | |
| 112 int childCount = self.folder->child_count(); | |
| 113 for (int i = 0; i < childCount; ++i) { | |
| 114 const BookmarkNode* node = self.folder->GetChild(i); | |
| 115 if (node->is_folder()) | |
| 116 _subFolders.push_back(node); | |
| 117 else | |
| 118 _subItems.push_back(node); | |
| 119 } | |
| 120 | |
| 121 bookmark_utils_ios::SortFolders(&_subFolders); | |
| 122 } | |
| 123 | |
| 124 [self cancelAllFaviconLoads]; | |
| 125 [self.collectionView reloadData]; | |
| 126 } | |
| 127 | |
| 128 #pragma mark - BookmarkModelBridgeObserver Callbacks | |
| 129 | |
| 130 - (void)bookmarkModelLoaded { | |
| 131 [self updateCollectionView]; | |
| 132 } | |
| 133 | |
| 134 - (void)bookmarkNodeChanged:(const BookmarkNode*)bookmarkNode { | |
| 135 // The base folder changed. Do nothing. | |
| 136 if (bookmarkNode == self.folder) | |
| 137 return; | |
| 138 | |
| 139 // A specific cell changed. Reload that cell. | |
| 140 NSIndexPath* indexPath = [self indexPathForNode:bookmarkNode]; | |
| 141 | |
| 142 if (indexPath) { | |
| 143 // TODO(crbug.com/603661): Ideally, we would only reload the relevant index | |
| 144 // path. However, calling reloadItemsAtIndexPaths:(0,0) immediately after | |
| 145 // reloadData results in a exception: NSInternalInconsistencyException | |
| 146 // 'request for index path for global index 2147483645 ...' | |
| 147 // One solution would be to keep track of whether we've just called | |
| 148 // reloadData, but that requires experimentation to determine how long we | |
| 149 // have to wait before we can safely call reloadItemsAtIndexPaths. | |
| 150 [self updateCollectionView]; | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 - (void)bookmarkNodeFaviconChanged: | |
| 155 (const bookmarks::BookmarkNode*)bookmarkNode { | |
| 156 // Only urls have favicons. | |
| 157 DCHECK(bookmarkNode->is_url()); | |
| 158 | |
| 159 // Update image of corresponding cell. | |
| 160 NSIndexPath* indexPath = [self indexPathForNode:bookmarkNode]; | |
| 161 | |
| 162 if (!indexPath) | |
| 163 return; | |
| 164 | |
| 165 // Check that this cell is visible. | |
| 166 NSArray* visiblePaths = [self.collectionView indexPathsForVisibleItems]; | |
| 167 if (![visiblePaths containsObject:indexPath]) | |
| 168 return; | |
| 169 | |
| 170 [self loadFaviconAtIndexPath:indexPath]; | |
| 171 } | |
| 172 | |
| 173 - (NSIndexPath*)indexPathForNode:(const bookmarks::BookmarkNode*)bookmarkNode { | |
| 174 NSIndexPath* indexPath = nil; | |
| 175 if (bookmarkNode->is_folder()) { | |
| 176 std::vector<const BookmarkNode*>::iterator it = | |
| 177 std::find(_subFolders.begin(), _subFolders.end(), bookmarkNode); | |
| 178 if (it != _subFolders.end()) { | |
| 179 ptrdiff_t index = std::distance(_subFolders.begin(), it); | |
| 180 indexPath = | |
| 181 [NSIndexPath indexPathForRow:index inSection:self.folderSection]; | |
| 182 } | |
| 183 } else if (bookmarkNode->is_url()) { | |
| 184 std::vector<const BookmarkNode*>::iterator it = | |
| 185 std::find(_subItems.begin(), _subItems.end(), bookmarkNode); | |
| 186 if (it != _subItems.end()) { | |
| 187 ptrdiff_t index = std::distance(_subItems.begin(), it); | |
| 188 indexPath = | |
| 189 [NSIndexPath indexPathForRow:index inSection:self.itemsSection]; | |
| 190 } | |
| 191 } | |
| 192 return indexPath; | |
| 193 } | |
| 194 | |
| 195 - (void)bookmarkNodeDeleted:(const BookmarkNode*)node | |
| 196 fromFolder:(const BookmarkNode*)folder { | |
| 197 if (self.folder == node) { | |
| 198 self.folder = nil; | |
| 199 [self updateCollectionView]; | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 - (void)bookmarkNodeChildrenChanged:(const BookmarkNode*)bookmarkNode { | |
| 204 // The base folder's children changed. Reload everything. | |
| 205 if (bookmarkNode == self.folder) { | |
| 206 [self updateCollectionView]; | |
| 207 return; | |
| 208 } | |
| 209 | |
| 210 // A subfolder's children changed. Reload that cell. | |
| 211 std::vector<const BookmarkNode*>::iterator it = | |
| 212 std::find(_subFolders.begin(), _subFolders.end(), bookmarkNode); | |
| 213 if (it != _subFolders.end()) { | |
| 214 // TODO(crbug.com/603661): Ideally, we would only reload the relevant index | |
| 215 // path. However, calling reloadItemsAtIndexPaths:(0,0) immediately after | |
| 216 // reloadData results in a exception: NSInternalInconsistencyException | |
| 217 // 'request for index path for global index 2147483645 ...' | |
| 218 // One solution would be to keep track of whether we've just called | |
| 219 // reloadData, but that requires experimentation to determine how long we | |
| 220 // have to wait before we can safely call reloadItemsAtIndexPaths. | |
| 221 [self updateCollectionView]; | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 - (void)bookmarkNode:(const BookmarkNode*)bookmarkNode | |
| 226 movedFromParent:(const BookmarkNode*)oldParent | |
| 227 toParent:(const BookmarkNode*)newParent { | |
| 228 if (oldParent == self.folder || newParent == self.folder) { | |
| 229 // A folder was added or removed from the base folder. | |
| 230 [self updateCollectionView]; | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 - (void)bookmarkModelRemovedAllNodes { | |
| 235 self.folder = nil; | |
| 236 [self updateCollectionView]; | |
| 237 } | |
| 238 | |
| 239 #pragma mark - Parent class overrides that affect functionality | |
| 240 | |
| 241 - (void)collectionView:(UICollectionView*)collectionView | |
| 242 willDisplayCell:(UICollectionViewCell*)cell | |
| 243 forItemAtIndexPath:(NSIndexPath*)indexPath { | |
| 244 if (indexPath.section == self.itemsSection) { | |
| 245 [self loadFaviconAtIndexPath:indexPath]; | |
| 246 } | |
| 247 } | |
| 248 | |
| 249 - (void)didAddCellForEditingAtIndexPath:(NSIndexPath*)indexPath { | |
| 250 const BookmarkNode* node = [self nodeAtIndexPath:indexPath]; | |
| 251 UICollectionViewCell* cell = | |
| 252 [self.collectionView cellForItemAtIndexPath:indexPath]; | |
| 253 [self.delegate bookmarkCollectionView:self cell:cell addNodeForEditing:node]; | |
| 254 } | |
| 255 | |
| 256 - (void)didRemoveCellForEditingAtIndexPath:(NSIndexPath*)indexPath { | |
| 257 const BookmarkNode* node = [self nodeAtIndexPath:indexPath]; | |
| 258 UICollectionViewCell* cell = | |
| 259 [self.collectionView cellForItemAtIndexPath:indexPath]; | |
| 260 [self.delegate bookmarkCollectionView:self | |
| 261 cell:cell | |
| 262 removeNodeForEditing:node]; | |
| 263 } | |
| 264 | |
| 265 - (void)didTapCellAtIndexPath:(NSIndexPath*)indexPath { | |
| 266 if (indexPath.section == self.promoSection) { | |
| 267 // User tapped inside promo cell but not on one of the buttons. Ignore it. | |
| 268 return; | |
| 269 } | |
| 270 | |
| 271 const BookmarkNode* node = [self nodeAtIndexPath:indexPath]; | |
| 272 DCHECK(node); | |
| 273 | |
| 274 if (indexPath.section == self.folderSection) { | |
| 275 [self.delegate bookmarkFolderCollectionView:self | |
| 276 selectedFolderForNavigation:node]; | |
| 277 } else { | |
| 278 RecordBookmarkLaunch(BOOKMARK_LAUNCH_LOCATION_FOLDER); | |
| 279 [self.delegate bookmarkCollectionView:self | |
| 280 selectedUrlForNavigation:node->url()]; | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 - (void)didTapMenuButtonAtIndexPath:(NSIndexPath*)indexPath | |
| 285 onView:(UIView*)view | |
| 286 forCell:(BookmarkItemCell*)cell { | |
| 287 [self.delegate bookmarkCollectionView:self | |
| 288 wantsMenuForBookmark:[self nodeAtIndexPath:indexPath] | |
| 289 onView:view | |
| 290 forCell:cell]; | |
| 291 } | |
| 292 | |
| 293 - (bookmark_cell::ButtonType)buttonTypeForCellAtIndexPath: | |
| 294 (NSIndexPath*)indexPath { | |
| 295 return self.editing ? bookmark_cell::ButtonNone : bookmark_cell::ButtonMenu; | |
| 296 } | |
| 297 | |
| 298 - (BOOL)allowLongPressForCellAtIndexPath:(NSIndexPath*)indexPath { | |
| 299 return !self.editing; | |
| 300 } | |
| 301 | |
| 302 - (void)didLongPressCell:(UICollectionViewCell*)cell | |
| 303 atIndexPath:(NSIndexPath*)indexPath { | |
| 304 if (indexPath.section == self.promoSection) { | |
| 305 // User long-pressed inside promo cell. Ignore it. | |
| 306 return; | |
| 307 } | |
| 308 | |
| 309 [self.delegate bookmarkCollectionView:self | |
| 310 didLongPressCell:cell | |
| 311 forBookmark:[self nodeAtIndexPath:indexPath]]; | |
| 312 } | |
| 313 | |
| 314 - (BOOL)shouldSelectCellAtIndexPath:(NSIndexPath*)indexPath { | |
| 315 return YES; | |
| 316 } | |
| 317 | |
| 318 - (BOOL)cellIsSelectedForEditingAtIndexPath:(NSIndexPath*)indexPath { | |
| 319 const BookmarkNode* node = [self nodeAtIndexPath:indexPath]; | |
| 320 const std::set<const BookmarkNode*>& editingNodes = | |
| 321 [self.delegate nodesBeingEdited]; | |
| 322 return editingNodes.find(node) != editingNodes.end(); | |
| 323 } | |
| 324 | |
| 325 - (const BookmarkNode*)nodeAtIndexPath:(NSIndexPath*)indexPath { | |
| 326 if (indexPath.section == self.folderSection) | |
| 327 return _subFolders[indexPath.row]; | |
| 328 if (indexPath.section == self.itemsSection) | |
| 329 return _subItems[indexPath.row]; | |
| 330 | |
| 331 NOTREACHED(); | |
| 332 return nullptr; | |
| 333 } | |
| 334 | |
| 335 - (void)resetFolder:(const BookmarkNode*)folder { | |
| 336 DCHECK(folder->is_folder()); | |
| 337 self.folder = folder; | |
| 338 [self updateCollectionView]; | |
| 339 } | |
| 340 | |
| 341 - (CGFloat)interitemSpacingForSectionAtIndex:(NSInteger)section { | |
| 342 CGFloat interitemSpacing = 0; | |
| 343 SEL minimumInteritemSpacingSelector = @selector(collectionView: | |
| 344 layout: | |
| 345 minimumInteritemSpacingForSectionAtIndex:); | |
| 346 if ([self.collectionView.delegate | |
| 347 respondsToSelector:minimumInteritemSpacingSelector]) { | |
| 348 id collectionViewDelegate = static_cast<id>(self.collectionView.delegate); | |
| 349 interitemSpacing = | |
| 350 [collectionViewDelegate collectionView:self.collectionView | |
| 351 layout:self.collectionView | |
| 352 .collectionViewLayout | |
| 353 minimumInteritemSpacingForSectionAtIndex:section]; | |
| 354 } else if ([self.collectionView.collectionViewLayout | |
| 355 isKindOfClass:[UICollectionViewFlowLayout class]]) { | |
| 356 UICollectionViewFlowLayout* flowLayout = | |
| 357 static_cast<UICollectionViewFlowLayout*>( | |
| 358 self.collectionView.collectionViewLayout); | |
| 359 interitemSpacing = flowLayout.minimumInteritemSpacing; | |
| 360 } | |
| 361 return interitemSpacing; | |
| 362 } | |
| 363 | |
| 364 // Parent class override. | |
| 365 - (UIEdgeInsets)insetForSectionAtIndex:(NSInteger)section { | |
| 366 UIEdgeInsets insets = [super insetForSectionAtIndex:section]; | |
| 367 if (section == self.folderSection) | |
| 368 insets.bottom = [self interitemSpacingForSectionAtIndex:section] / 2.; | |
| 369 else if (section == self.itemsSection) | |
| 370 insets.top = [self interitemSpacingForSectionAtIndex:section] / 2.; | |
| 371 else if (section == self.promoSection) | |
| 372 (void)0; // No insets to update. | |
| 373 else | |
| 374 NOTREACHED(); | |
| 375 return insets; | |
| 376 } | |
| 377 | |
| 378 // Parent class override. | |
| 379 - (CGSize)cellSizeForIndexPath:(NSIndexPath*)indexPath { | |
| 380 if ([self isPromoSection:indexPath.section]) { | |
| 381 UICollectionViewCell* cell = | |
| 382 [self.collectionView cellForItemAtIndexPath:indexPath]; | |
| 383 if (!cell) { | |
| 384 // -[UICollectionView | |
| 385 // dequeueReusableCellWithReuseIdentifier:forIndexPath:] cannot be used | |
| 386 // here since this method is called by -[id<UICollectionViewDelegate> | |
| 387 // collectionView:layout:sizeForItemAtIndexPath:]. This would generate | |
| 388 // crash: SIGFPE, EXC_I386_DIV. | |
| 389 if (experimental_flags::IsSigninPromoEnabled()) { | |
| 390 DCHECK(_signinPromoViewMediator); | |
| 391 BookmarkSigninPromoCell* signinPromoCell = | |
| 392 [[BookmarkSigninPromoCell alloc] | |
| 393 initWithFrame:CGRectMake(0, 0, 1000, 1000)]; | |
| 394 [[_signinPromoViewMediator createConfigurator] | |
| 395 configureSigninPromoView:signinPromoCell.signinPromoView]; | |
| 396 cell = signinPromoCell; | |
| 397 } else { | |
| 398 cell = [[BookmarkPromoCell alloc] init]; | |
| 399 } | |
| 400 } | |
| 401 return PreferredCellSizeForWidth(cell, CGRectGetWidth(self.bounds)); | |
| 402 } | |
| 403 return [super cellSizeForIndexPath:indexPath]; | |
| 404 } | |
| 405 | |
| 406 // Parent class override. | |
| 407 - (UICollectionViewCell*)cellAtIndexPath:(NSIndexPath*)indexPath { | |
| 408 if (indexPath.section == self.promoSection) { | |
| 409 if (experimental_flags::IsSigninPromoEnabled()) { | |
| 410 BookmarkSigninPromoCell* signinPromoCell = [self.collectionView | |
| 411 dequeueReusableCellWithReuseIdentifier:[BookmarkSigninPromoCell | |
| 412 reuseIdentifier] | |
| 413 forIndexPath:indexPath]; | |
| 414 signinPromoCell.signinPromoView.delegate = _signinPromoViewMediator; | |
| 415 [[_signinPromoViewMediator createConfigurator] | |
| 416 configureSigninPromoView:signinPromoCell.signinPromoView]; | |
| 417 __weak BookmarkFolderCollectionView* weakSelf = self; | |
| 418 signinPromoCell.closeButtonAction = ^() { | |
| 419 [weakSelf.delegate bookmarkCollectionViewDismissPromo:self]; | |
| 420 }; | |
| 421 return signinPromoCell; | |
| 422 } else { | |
| 423 BookmarkPromoCell* promoCell = [self.collectionView | |
| 424 dequeueReusableCellWithReuseIdentifier:[BookmarkPromoCell | |
| 425 reuseIdentifier] | |
| 426 forIndexPath:indexPath]; | |
| 427 promoCell.delegate = self; | |
| 428 return promoCell; | |
| 429 } | |
| 430 } | |
| 431 const BookmarkNode* node = [self nodeAtIndexPath:indexPath]; | |
| 432 | |
| 433 if (indexPath.section == self.folderSection) | |
| 434 return [self cellForFolder:node indexPath:indexPath]; | |
| 435 | |
| 436 BookmarkItemCell* cell = [self cellForBookmark:node indexPath:indexPath]; | |
| 437 return cell; | |
| 438 } | |
| 439 | |
| 440 - (BOOL)needsSectionHeaderForSection:(NSInteger)section { | |
| 441 // Only show header when there is at least one element in the previous | |
| 442 // section. | |
| 443 if (section == 0) | |
| 444 return NO; | |
| 445 | |
| 446 if ([self numberOfItemsInSection:(section - 1)] == 0) | |
| 447 return NO; | |
| 448 | |
| 449 return YES; | |
| 450 } | |
| 451 | |
| 452 // Parent class override. | |
| 453 - (CGSize)headerSizeForSection:(NSInteger)section { | |
| 454 if ([self needsSectionHeaderForSection:section]) | |
| 455 return CGSizeMake(self.bounds.size.width, | |
| 456 [BookmarkHeaderSeparatorView preferredHeight]); | |
| 457 | |
| 458 return CGSizeZero; | |
| 459 } | |
| 460 | |
| 461 // Parent class override. | |
| 462 - (UICollectionReusableView*)headerAtIndexPath:(NSIndexPath*)indexPath { | |
| 463 if (![self needsSectionHeaderForSection:indexPath.section]) | |
| 464 return nil; | |
| 465 | |
| 466 BookmarkHeaderSeparatorView* view = [self.collectionView | |
| 467 dequeueReusableSupplementaryViewOfKind: | |
| 468 UICollectionElementKindSectionHeader | |
| 469 withReuseIdentifier:[BookmarkHeaderSeparatorView | |
| 470 reuseIdentifier] | |
| 471 forIndexPath:indexPath]; | |
| 472 view.backgroundColor = [UIColor colorWithWhite:1 alpha:1]; | |
| 473 return view; | |
| 474 } | |
| 475 | |
| 476 - (NSInteger)numberOfItemsInSection:(NSInteger)section { | |
| 477 if (section == self.folderSection) | |
| 478 return _subFolders.size(); | |
| 479 if (section == self.itemsSection) | |
| 480 return _subItems.size(); | |
| 481 if (section == self.promoSection) | |
| 482 return 1; | |
| 483 | |
| 484 NOTREACHED(); | |
| 485 return -1; | |
| 486 } | |
| 487 | |
| 488 - (NSInteger)numberOfSections { | |
| 489 return self.sectionCount; | |
| 490 } | |
| 491 | |
| 492 - (void)collectionViewScrolled { | |
| 493 [self.delegate bookmarkCollectionViewDidScroll:self]; | |
| 494 } | |
| 495 | |
| 496 - (void)setEditing:(BOOL)editing animated:(BOOL)animated { | |
| 497 [super setEditing:editing animated:animated]; | |
| 498 [self promoStateChangedAnimated:animated]; | |
| 499 } | |
| 500 | |
| 501 - (void)promoStateChangedAnimated:(BOOL)animate { | |
| 502 BOOL newPromoState = | |
| 503 !self.editing && self.folder && | |
| 504 self.folder->type() == BookmarkNode::MOBILE && | |
| 505 [self.delegate bookmarkCollectionViewShouldShowPromoCell:self]; | |
| 506 if (newPromoState != _promoVisible) { | |
| 507 // This is awful, but until the old code to do the refresh when switching | |
| 508 // in and out of edit mode is fixed, this is probably the cleanest thing to | |
| 509 // do. | |
| 510 _promoVisible = newPromoState; | |
| 511 if (experimental_flags::IsSigninPromoEnabled()) { | |
| 512 if (!_promoVisible) { | |
| 513 _signinPromoViewMediator.consumer = nil; | |
| 514 _signinPromoViewMediator = nil; | |
| 515 } else { | |
| 516 _signinPromoViewMediator = [[SigninPromoViewMediator alloc] init]; | |
| 517 _signinPromoViewMediator.consumer = self; | |
| 518 _signinPromoViewMediator.accessPoint = | |
| 519 signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER; | |
| 520 } | |
| 521 } | |
| 522 [self.collectionView reloadData]; | |
| 523 } | |
| 524 } | |
| 525 | |
| 526 #pragma mark - BookmarkPromoCellDelegate | |
| 527 | |
| 528 - (void)bookmarkPromoCellDidTapSignIn:(BookmarkPromoCell*)bookmarkPromoCell { | |
| 529 [self.delegate bookmarkCollectionViewShowSignIn:self]; | |
| 530 } | |
| 531 | |
| 532 - (void)bookmarkPromoCellDidTapDismiss:(BookmarkPromoCell*)bookmarkPromoCell { | |
| 533 [self.delegate bookmarkCollectionViewDismissPromo:self]; | |
| 534 } | |
| 535 | |
| 536 #pragma mark - Promo Cell | |
| 537 | |
| 538 - (BOOL)shouldShowPromoCell { | |
| 539 return _promoVisible; | |
| 540 } | |
| 541 | |
| 542 #pragma mark - SigninPromoViewConsumer | |
| 543 | |
| 544 - (void)configureSigninPromoWithConfigurator: | |
| 545 (SigninPromoViewConfigurator*)configurator | |
| 546 identityChanged:(BOOL)identityChanged { | |
| 547 DCHECK(_signinPromoViewMediator); | |
| 548 NSIndexPath* indexPath = | |
| 549 [NSIndexPath indexPathForRow:0 inSection:self.promoSection]; | |
| 550 BookmarkSigninPromoCell* signinPromoCell = | |
| 551 static_cast<BookmarkSigninPromoCell*>( | |
| 552 [self.collectionView cellForItemAtIndexPath:indexPath]); | |
| 553 if (!signinPromoCell) | |
| 554 return; | |
| 555 // Should always reconfigure the cell size even if it has to be reloaded. | |
| 556 // -[BookmarkFolderCollectionView cellSizeForIndexPath:] uses the current | |
| 557 // cell to compute its height. | |
| 558 [configurator configureSigninPromoView:signinPromoCell.signinPromoView]; | |
| 559 if (identityChanged) { | |
| 560 // The section should be reload to update the cell height. | |
| 561 NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:self.promoSection]; | |
| 562 [self.collectionView reloadSections:indexSet]; | |
| 563 } | |
| 564 } | |
| 565 | |
| 566 @end | |
| OLD | NEW |