OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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/collection_view/collection_view_controller.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/mac/foundation_util.h" |
| 9 #import "base/mac/scoped_nsobject.h" |
| 10 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" |
| 11 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" |
| 12 #import "ios/chrome/browser/ui/material_components/utils.h" |
| 13 #import "ios/third_party/material_components_ios/src/components/AppBar/src/Mater
ialAppBar.h" |
| 14 #import "ios/third_party/material_components_ios/src/components/CollectionCells/
src/MaterialCollectionCells.h" |
| 15 |
| 16 @implementation CollectionViewController { |
| 17 // The implementation of this controller follows the guidelines from |
| 18 // https://github.com/material-components/material-components-ios/tree/develop
/components/AppBar |
| 19 base::scoped_nsobject<MDCAppBar> _appBar; |
| 20 base::scoped_nsobject<CollectionViewModel> _collectionViewModel; |
| 21 } |
| 22 |
| 23 - (instancetype)initWithStyle:(CollectionViewControllerStyle)style { |
| 24 UICollectionViewLayout* layout = |
| 25 [[[MDCCollectionViewFlowLayout alloc] init] autorelease]; |
| 26 self = [super initWithCollectionViewLayout:layout]; |
| 27 if (self) { |
| 28 if (style == CollectionViewControllerStyleAppBar) { |
| 29 _appBar.reset([[MDCAppBar alloc] init]); |
| 30 [self addChildViewController:_appBar.get().headerViewController]; |
| 31 } |
| 32 } |
| 33 return self; |
| 34 } |
| 35 |
| 36 - (void)viewDidLoad { |
| 37 [super viewDidLoad]; |
| 38 |
| 39 // Configure the app bar, if there is one. |
| 40 if (self.appBar) { |
| 41 // Configure the app bar style. |
| 42 ConfigureAppBarWithCardStyle(self.appBar); |
| 43 // Set the header view's tracking scroll view. |
| 44 self.appBar.headerViewController.headerView.trackingScrollView = |
| 45 self.collectionView; |
| 46 // After all other views have been registered. |
| 47 [self.appBar addSubviewsToParent]; |
| 48 } |
| 49 } |
| 50 |
| 51 - (UIViewController*)childViewControllerForStatusBarHidden { |
| 52 return self.appBar.headerViewController; |
| 53 } |
| 54 |
| 55 - (UIViewController*)childViewControllerForStatusBarStyle { |
| 56 return self.appBar.headerViewController; |
| 57 } |
| 58 |
| 59 - (MDCAppBar*)appBar { |
| 60 return _appBar.get(); |
| 61 } |
| 62 |
| 63 - (CollectionViewModel*)collectionViewModel { |
| 64 return _collectionViewModel.get(); |
| 65 } |
| 66 |
| 67 - (void)loadModel { |
| 68 _collectionViewModel.reset([[CollectionViewModel alloc] init]); |
| 69 } |
| 70 |
| 71 - (void)reconfigureCellsForItems:(NSArray*)items |
| 72 inSectionWithIdentifier:(NSInteger)sectionIdentifier { |
| 73 for (CollectionViewItem* item in items) { |
| 74 NSIndexPath* indexPath = |
| 75 [_collectionViewModel indexPathForItem:item |
| 76 inSectionWithIdentifier:sectionIdentifier]; |
| 77 MDCCollectionViewCell* cell = |
| 78 base::mac::ObjCCastStrict<MDCCollectionViewCell>( |
| 79 [self.collectionView cellForItemAtIndexPath:indexPath]); |
| 80 |
| 81 // |cell| may be nil if the row is not currently on screen. |
| 82 if (cell) { |
| 83 [item configureCell:cell]; |
| 84 } |
| 85 } |
| 86 } |
| 87 |
| 88 #pragma mark MDCCollectionViewEditingDelegate |
| 89 |
| 90 - (void)collectionView:(UICollectionView*)collectionView |
| 91 willDeleteItemsAtIndexPaths:(NSArray*)indexPaths { |
| 92 // Check that the parent class doesn't implement this method. Otherwise, it |
| 93 // would need to be called here. |
| 94 DCHECK([self isKindOfClass:[MDCCollectionViewController class]]); |
| 95 DCHECK(![MDCCollectionViewController instancesRespondToSelector:_cmd]); |
| 96 |
| 97 // Sort and enumerate in reverse order to delete the items from the collection |
| 98 // view model. |
| 99 NSArray* sortedIndexPaths = |
| 100 [indexPaths sortedArrayUsingSelector:@selector(compare:)]; |
| 101 for (NSIndexPath* indexPath in [sortedIndexPaths reverseObjectEnumerator]) { |
| 102 NSInteger sectionIdentifier = |
| 103 [_collectionViewModel sectionIdentifierForSection:indexPath.section]; |
| 104 NSInteger itemType = [_collectionViewModel itemTypeForIndexPath:indexPath]; |
| 105 NSUInteger index = |
| 106 [_collectionViewModel indexInItemTypeForIndexPath:indexPath]; |
| 107 [_collectionViewModel removeItemWithType:itemType |
| 108 fromSectionWithIdentifier:sectionIdentifier |
| 109 atIndex:index]; |
| 110 } |
| 111 } |
| 112 |
| 113 - (void)collectionView:(UICollectionView*)collectionView |
| 114 willMoveItemAtIndexPath:(NSIndexPath*)indexPath |
| 115 toIndexPath:(NSIndexPath*)newIndexPath { |
| 116 // Check that the parent class doesn't implement this method. Otherwise, it |
| 117 // would need to be called here. |
| 118 DCHECK([self isKindOfClass:[MDCCollectionViewController class]]); |
| 119 DCHECK(![MDCCollectionViewController instancesRespondToSelector:_cmd]); |
| 120 |
| 121 // Retain the item to be able to move it. |
| 122 base::scoped_nsobject<CollectionViewItem> item( |
| 123 [[self.collectionViewModel itemAtIndexPath:indexPath] retain]); |
| 124 |
| 125 // Item coordinates. |
| 126 NSInteger sectionIdentifier = |
| 127 [self.collectionViewModel sectionIdentifierForSection:indexPath.section]; |
| 128 NSInteger itemType = |
| 129 [self.collectionViewModel itemTypeForIndexPath:indexPath]; |
| 130 NSUInteger indexInItemType = |
| 131 [self.collectionViewModel indexInItemTypeForIndexPath:indexPath]; |
| 132 |
| 133 // Move the item. |
| 134 [self.collectionViewModel removeItemWithType:itemType |
| 135 fromSectionWithIdentifier:sectionIdentifier |
| 136 atIndex:indexInItemType]; |
| 137 NSInteger section = [self.collectionViewModel |
| 138 sectionIdentifierForSection:newIndexPath.section]; |
| 139 [self.collectionViewModel insertItem:item |
| 140 inSectionWithIdentifier:section |
| 141 atIndex:newIndexPath.item]; |
| 142 } |
| 143 |
| 144 #pragma mark UICollectionViewDataSource |
| 145 |
| 146 - (NSInteger)numberOfSectionsInCollectionView: |
| 147 (UICollectionView*)collectionView { |
| 148 return [_collectionViewModel numberOfSections]; |
| 149 } |
| 150 |
| 151 - (NSInteger)collectionView:(UICollectionView*)collectionView |
| 152 numberOfItemsInSection:(NSInteger)section { |
| 153 return [_collectionViewModel numberOfItemsInSection:section]; |
| 154 } |
| 155 |
| 156 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView |
| 157 cellForItemAtIndexPath:(NSIndexPath*)indexPath { |
| 158 CollectionViewItem* item = [_collectionViewModel itemAtIndexPath:indexPath]; |
| 159 Class cellClass = [item cellClass]; |
| 160 NSString* reuseIdentifier = NSStringFromClass(cellClass); |
| 161 [self.collectionView registerClass:cellClass |
| 162 forCellWithReuseIdentifier:reuseIdentifier]; |
| 163 MDCCollectionViewCell* cell = [self.collectionView |
| 164 dequeueReusableCellWithReuseIdentifier:reuseIdentifier |
| 165 forIndexPath:indexPath]; |
| 166 [item configureCell:cell]; |
| 167 return cell; |
| 168 } |
| 169 |
| 170 - (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView |
| 171 viewForSupplementaryElementOfKind:(NSString*)kind |
| 172 atIndexPath:(NSIndexPath*)indexPath { |
| 173 CollectionViewItem* item = nil; |
| 174 UIAccessibilityTraits traits = UIAccessibilityTraitNone; |
| 175 if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { |
| 176 item = [_collectionViewModel headerForSection:indexPath.section]; |
| 177 traits = UIAccessibilityTraitHeader; |
| 178 } else if ([kind isEqualToString:UICollectionElementKindSectionFooter]) { |
| 179 item = [_collectionViewModel footerForSection:indexPath.section]; |
| 180 } else { |
| 181 return [super collectionView:collectionView |
| 182 viewForSupplementaryElementOfKind:kind |
| 183 atIndexPath:indexPath]; |
| 184 } |
| 185 |
| 186 Class cellClass = [item cellClass]; |
| 187 NSString* reuseIdentifier = NSStringFromClass(cellClass); |
| 188 [self.collectionView registerClass:cellClass |
| 189 forSupplementaryViewOfKind:kind |
| 190 withReuseIdentifier:reuseIdentifier]; |
| 191 MDCCollectionViewCell* cell = [self.collectionView |
| 192 dequeueReusableSupplementaryViewOfKind:kind |
| 193 withReuseIdentifier:reuseIdentifier |
| 194 forIndexPath:indexPath]; |
| 195 [item configureCell:cell]; |
| 196 cell.accessibilityTraits |= traits; |
| 197 return cell; |
| 198 }; |
| 199 |
| 200 #pragma mark - UICollectionViewDelegateFlowLayout |
| 201 |
| 202 - (CGSize)collectionView:(UICollectionView*)collectionView |
| 203 layout: |
| 204 (UICollectionViewLayout*)collectionViewLayout |
| 205 referenceSizeForHeaderInSection:(NSInteger)section { |
| 206 CollectionViewItem* item = [_collectionViewModel headerForSection:section]; |
| 207 |
| 208 if (item) { |
| 209 // TODO(crbug.com/635604): Support arbitrary sized headers. |
| 210 return CGSizeMake(0, MDCCellDefaultOneLineHeight); |
| 211 } |
| 212 return CGSizeZero; |
| 213 } |
| 214 |
| 215 - (CGSize)collectionView:(UICollectionView*)collectionView |
| 216 layout: |
| 217 (UICollectionViewLayout*)collectionViewLayout |
| 218 referenceSizeForFooterInSection:(NSInteger)section { |
| 219 CollectionViewItem* item = [_collectionViewModel footerForSection:section]; |
| 220 |
| 221 if (item) { |
| 222 // TODO(crbug.com/635604): Support arbitrary sized footers. |
| 223 return CGSizeMake(0, MDCCellDefaultOneLineHeight); |
| 224 } |
| 225 return CGSizeZero; |
| 226 } |
| 227 |
| 228 #pragma mark UIScrollViewDelegate |
| 229 |
| 230 - (void)scrollViewDidScroll:(UIScrollView*)scrollView { |
| 231 MDCFlexibleHeaderView* headerView = |
| 232 self.appBar.headerViewController.headerView; |
| 233 if (scrollView == headerView.trackingScrollView) { |
| 234 [headerView trackingScrollViewDidScroll]; |
| 235 } |
| 236 } |
| 237 |
| 238 - (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView { |
| 239 MDCFlexibleHeaderView* headerView = |
| 240 self.appBar.headerViewController.headerView; |
| 241 if (scrollView == headerView.trackingScrollView) { |
| 242 [headerView trackingScrollViewDidEndDecelerating]; |
| 243 } |
| 244 } |
| 245 |
| 246 - (void)scrollViewDidEndDragging:(UIScrollView*)scrollView |
| 247 willDecelerate:(BOOL)decelerate { |
| 248 MDCFlexibleHeaderView* headerView = |
| 249 self.appBar.headerViewController.headerView; |
| 250 if (scrollView == headerView.trackingScrollView) { |
| 251 [headerView trackingScrollViewDidEndDraggingWillDecelerate:decelerate]; |
| 252 } |
| 253 } |
| 254 |
| 255 - (void)scrollViewWillEndDragging:(UIScrollView*)scrollView |
| 256 withVelocity:(CGPoint)velocity |
| 257 targetContentOffset:(inout CGPoint*)targetContentOffset { |
| 258 MDCFlexibleHeaderView* headerView = |
| 259 self.appBar.headerViewController.headerView; |
| 260 if (scrollView == headerView.trackingScrollView) { |
| 261 [headerView |
| 262 trackingScrollViewWillEndDraggingWithVelocity:velocity |
| 263 targetContentOffset:targetContentOffset]; |
| 264 } |
| 265 } |
| 266 |
| 267 @end |
OLD | NEW |