Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/browser/ui/history/tab_history_view_controller.h" | 5 #import "ios/chrome/browser/ui/history/tab_history_view_controller.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/mac/foundation_util.h" | 8 #include "base/mac/foundation_util.h" |
| 9 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
| 10 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" | 10 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" |
| 11 #include "ios/chrome/browser/ui/commands/ios_command_ids.h" | 11 #include "ios/chrome/browser/ui/commands/ios_command_ids.h" |
| 12 #import "ios/chrome/browser/ui/history/tab_history_cell.h" | 12 #import "ios/chrome/browser/ui/history/tab_history_cell.h" |
| 13 #include "ios/chrome/browser/ui/rtl_geometry.h" | 13 #include "ios/chrome/browser/ui/rtl_geometry.h" |
| 14 #import "ios/third_party/material_components_ios/src/components/Ink/src/Material Ink.h" | 14 #import "ios/third_party/material_components_ios/src/components/Ink/src/Material Ink.h" |
| 15 #import "ios/web/navigation/crw_session_entry.h" | |
| 16 #include "ios/web/public/favicon_status.h" | 15 #include "ios/web/public/favicon_status.h" |
| 17 #include "ios/web/public/navigation_item.h" | 16 #include "ios/web/public/navigation_item.h" |
| 18 #include "ui/gfx/image/image.h" | 17 #include "ui/gfx/image/image.h" |
| 19 | 18 |
| 20 #if !defined(__has_feature) || !__has_feature(objc_arc) | 19 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 21 #error "This file requires ARC support." | 20 #error "This file requires ARC support." |
| 22 #endif | 21 #endif |
| 23 | 22 |
| 24 namespace { | 23 namespace { |
| 25 | 24 |
| 26 // Visible percentage of the last visible row on the Tools menu if the | 25 // Visible percentage of the last visible row on the Tools menu if the |
| 27 // Tools menu is scrollable. | 26 // Tools menu is scrollable. |
| 28 const CGFloat kLastRowVisiblePercentage = 0.6; | 27 const CGFloat kLastRowVisiblePercentage = 0.6; |
| 29 // Reuse identifier for cells. | 28 // Reuse identifier for cells. |
| 30 NSString* cellIdentifier = @"TabHistoryCell"; | 29 NSString* const kCellIdentifier = @"TabHistoryCell"; |
| 31 NSString* footerIdentifier = @"Footer"; | 30 NSString* const kFooterIdentifier = @"Footer"; |
| 32 NSString* headerIdentifier = @"Header"; | 31 NSString* const kHeaderIdentifier = @"Header"; |
| 32 // The collection view's a11y label. | |
| 33 NSString* const kCollectionViewLabel = @"Tab History"; | |
| 33 // Height of rows. | 34 // Height of rows. |
| 34 const CGFloat kCellHeight = 48.0; | 35 const CGFloat kCellHeight = 48.0; |
| 35 // Fraction height for partially visible row. | 36 // Fraction height for partially visible row. |
| 36 const CGFloat kCellHeightLastRow = kCellHeight * kLastRowVisiblePercentage; | 37 const CGFloat kCellHeightLastRow = kCellHeight * kLastRowVisiblePercentage; |
| 37 // Width and leading for the header view. | 38 // Width and leading for the header view. |
| 38 const CGFloat kHeaderLeadingInset = 0; | 39 const CGFloat kHeaderLeadingInset = 0; |
| 39 const CGFloat kHeaderWidth = 48; | 40 const CGFloat kHeaderWidth = 48; |
| 40 // Leading and trailing insets for cell items. | 41 // Leading and trailing insets for cell items. |
| 41 const CGFloat kCellLeadingInset = kHeaderLeadingInset + kHeaderWidth; | 42 const CGFloat kCellLeadingInset = kHeaderLeadingInset + kHeaderWidth; |
| 42 const CGFloat kCellTrailingInset = 16; | 43 const CGFloat kCellTrailingInset = 16; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 212 [attributes setZIndex:0]; | 213 [attributes setZIndex:0]; |
| 213 } | 214 } |
| 214 | 215 |
| 215 return attributes; | 216 return attributes; |
| 216 } | 217 } |
| 217 | 218 |
| 218 @end | 219 @end |
| 219 | 220 |
| 220 @interface TabHistoryViewController ()<MDCInkTouchControllerDelegate> { | 221 @interface TabHistoryViewController ()<MDCInkTouchControllerDelegate> { |
| 221 MDCInkTouchController* _inkTouchController; | 222 MDCInkTouchController* _inkTouchController; |
| 222 NSArray* _partitionedEntries; | 223 // A vector of NavigationItemLists where the NavigationItems are separated |
| 223 NSArray* _sessionEntries; | 224 // by hostname. |
| 225 std::vector<web::NavigationItemList> _partitionedItems; | |
| 224 } | 226 } |
| 227 | |
| 228 // Populates |_partitionedItems| with the NavigationItems in |items| partitioned | |
| 229 // by their hosts. | |
| 230 - (void)partitionItemsByHost:(const web::NavigationItemList&)items; | |
| 231 | |
| 232 // Returns the NavigationItem corresponding with |indexPath|. | |
| 233 - (const web::NavigationItem*)itemAtIndexPath:(NSIndexPath*)indexPath; | |
| 234 | |
| 235 // Removes all NavigationItem pointers from this class. Tapping a cell that | |
| 236 // triggers a navigation may delete NavigationItems, so NavigationItem | |
| 237 // references should be reset to avoid use-after-free errors. | |
| 238 - (void)clearNavigationItems; | |
| 239 | |
| 225 @end | 240 @end |
| 226 | 241 |
| 227 @implementation TabHistoryViewController | 242 @implementation TabHistoryViewController |
| 228 | 243 |
| 229 - (NSArray*)sessionEntries { | 244 - (instancetype)initWithItems:(const web::NavigationItemList&)items { |
| 230 return _sessionEntries; | 245 TabHistoryViewControllerLayout* layout = |
|
Eugene But (OOO till 7-30)
2017/02/14 23:08:08
Do you want to move this inside |if ((self =| bloc
kkhorimoto
2017/02/14 23:23:51
It's passed to |initWithCollectionViewLayout|.
| |
| 246 [[TabHistoryViewControllerLayout alloc] init]; | |
| 247 if ((self = [super initWithCollectionViewLayout:layout])) { | |
| 248 // Populate |_partitionedItems|. | |
| 249 [self partitionItemsByHost:items]; | |
|
Eugene But (OOO till 7-30)
2017/02/14 23:08:08
We should not call instance methods inside init. T
kkhorimoto
2017/02/14 23:23:51
Changed to C function.
| |
| 250 | |
| 251 // Set up the UICollectionView. | |
| 252 UICollectionView* collectionView = [self collectionView]; | |
| 253 collectionView.accessibilityLabel = kCollectionViewLabel; | |
| 254 collectionView.backgroundColor = [UIColor whiteColor]; | |
| 255 [collectionView registerClass:[TabHistoryCell class] | |
| 256 forCellWithReuseIdentifier:kCellIdentifier]; | |
| 257 [collectionView registerClass:[TabHistorySectionHeader class] | |
| 258 forSupplementaryViewOfKind:UICollectionElementKindSectionHeader | |
| 259 withReuseIdentifier:kHeaderIdentifier]; | |
| 260 [collectionView registerClass:[TabHistorySectionFooter class] | |
| 261 forSupplementaryViewOfKind:UICollectionElementKindSectionFooter | |
| 262 withReuseIdentifier:kFooterIdentifier]; | |
| 263 | |
| 264 // Set up the ink controller. | |
| 265 _inkTouchController = | |
| 266 [[MDCInkTouchController alloc] initWithView:collectionView]; | |
| 267 [_inkTouchController setDelegate:self]; | |
| 268 [_inkTouchController addInkView]; | |
| 269 } | |
| 270 return self; | |
| 231 } | 271 } |
| 232 | 272 |
| 233 #pragma mark Public Methods | 273 #pragma mark Public Methods |
| 234 | 274 |
| 235 - (CGFloat)optimalHeight:(CGFloat)suggestedHeight { | 275 - (CGFloat)optimalHeight:(CGFloat)suggestedHeight { |
| 236 DCHECK(suggestedHeight >= kCellHeight); | 276 DCHECK(suggestedHeight >= kCellHeight); |
| 237 CGFloat optimalHeight = 0; | 277 CGFloat optimalHeight = 0; |
| 238 | 278 |
| 239 for (NSArray* sectionArray in _partitionedEntries) { | 279 for (web::NavigationItemList& itemsWithSameHost : _partitionedItems) { |
| 240 NSUInteger sectionItemCount = [sectionArray count]; | 280 for (size_t count = 0; count < itemsWithSameHost.size(); ++count) { |
| 241 for (NSUInteger i = 0; i < sectionItemCount; ++i) { | |
| 242 CGFloat proposedHeight = optimalHeight + kCellHeight; | 281 CGFloat proposedHeight = optimalHeight + kCellHeight; |
| 243 | 282 |
| 244 if (proposedHeight > suggestedHeight) { | 283 if (proposedHeight > suggestedHeight) { |
| 245 CGFloat difference = proposedHeight - suggestedHeight; | 284 CGFloat difference = proposedHeight - suggestedHeight; |
| 246 if (difference > kCellHeightLastRow) { | 285 if (difference > kCellHeightLastRow) { |
| 247 return optimalHeight + kCellHeightLastRow; | 286 return optimalHeight + kCellHeightLastRow; |
| 248 } else { | 287 } else { |
| 249 return optimalHeight - kCellHeight + kCellHeightLastRow; | 288 return optimalHeight - kCellHeight + kCellHeightLastRow; |
| 250 } | 289 } |
| 251 } | 290 } |
| 252 | 291 |
| 253 optimalHeight = proposedHeight; | 292 optimalHeight = proposedHeight; |
| 254 } | 293 } |
| 255 | 294 |
| 256 optimalHeight += FooterHeight(); | 295 optimalHeight += FooterHeight(); |
| 257 } | 296 } |
| 258 | 297 |
| 259 // If this point is reached, it means the entire content fits and this last | 298 // If this point is reached, it means the entire content fits and this last |
| 260 // section should not include the footer. | 299 // section should not include the footer. |
| 261 optimalHeight -= FooterHeight(); | 300 optimalHeight -= FooterHeight(); |
| 262 | 301 |
| 263 return optimalHeight; | 302 return optimalHeight; |
| 264 } | 303 } |
| 265 | 304 |
| 266 - (instancetype)init { | |
| 267 TabHistoryViewControllerLayout* layout = | |
| 268 [[TabHistoryViewControllerLayout alloc] init]; | |
| 269 | |
| 270 return [self initWithCollectionViewLayout:layout]; | |
| 271 } | |
| 272 | |
| 273 - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout*)layout { | |
| 274 self = [super initWithCollectionViewLayout:layout]; | |
| 275 if (self) { | |
| 276 UICollectionView* collectionView = [self collectionView]; | |
| 277 [collectionView setBackgroundColor:[UIColor whiteColor]]; | |
| 278 | |
| 279 [collectionView registerClass:[TabHistoryCell class] | |
| 280 forCellWithReuseIdentifier:cellIdentifier]; | |
| 281 | |
| 282 [collectionView registerClass:[TabHistorySectionHeader class] | |
| 283 forSupplementaryViewOfKind:UICollectionElementKindSectionHeader | |
| 284 withReuseIdentifier:headerIdentifier]; | |
| 285 | |
| 286 [collectionView registerClass:[TabHistorySectionFooter class] | |
| 287 forSupplementaryViewOfKind:UICollectionElementKindSectionFooter | |
| 288 withReuseIdentifier:footerIdentifier]; | |
| 289 | |
| 290 _inkTouchController = | |
| 291 [[MDCInkTouchController alloc] initWithView:collectionView]; | |
| 292 [_inkTouchController setDelegate:self]; | |
| 293 [_inkTouchController addInkView]; | |
| 294 } | |
| 295 | |
| 296 return self; | |
| 297 } | |
| 298 | |
| 299 #pragma mark UICollectionViewDelegate | 305 #pragma mark UICollectionViewDelegate |
| 300 | 306 |
| 301 - (void)collectionView:(UICollectionView*)collectionView | 307 - (void)collectionView:(UICollectionView*)collectionView |
| 302 didSelectItemAtIndexPath:(NSIndexPath*)indexPath { | 308 didSelectItemAtIndexPath:(NSIndexPath*)indexPath { |
| 303 UICollectionViewCell* cell = | 309 TabHistoryCell* cell = base::mac::ObjCCastStrict<TabHistoryCell>( |
| 304 [collectionView cellForItemAtIndexPath:indexPath]; | 310 [collectionView cellForItemAtIndexPath:indexPath]); |
| 305 [collectionView chromeExecuteCommand:cell]; | 311 [collectionView chromeExecuteCommand:cell]; |
| 312 [self clearNavigationItems]; | |
| 306 } | 313 } |
| 307 | 314 |
| 308 #pragma mark UICollectionViewDataSource | 315 #pragma mark UICollectionViewDataSource |
| 309 | 316 |
| 310 - (CRWSessionEntry*)entryForIndexPath:(NSIndexPath*)indexPath { | |
| 311 NSInteger section = [indexPath section]; | |
| 312 NSInteger item = [indexPath item]; | |
| 313 | |
| 314 DCHECK(section < (NSInteger)[_partitionedEntries count]); | |
| 315 DCHECK(item < (NSInteger)[[_partitionedEntries objectAtIndex:section] count]); | |
| 316 NSArray* sectionedArray = [_partitionedEntries objectAtIndex:section]; | |
| 317 | |
| 318 return [sectionedArray objectAtIndex:item]; | |
| 319 } | |
| 320 | |
| 321 - (NSInteger)collectionView:(UICollectionView*)collectionView | 317 - (NSInteger)collectionView:(UICollectionView*)collectionView |
| 322 numberOfItemsInSection:(NSInteger)section { | 318 numberOfItemsInSection:(NSInteger)section { |
| 323 DCHECK(section < (NSInteger)[_partitionedEntries count]); | 319 size_t sectionIdx = static_cast<size_t>(section); |
|
Eugene But (OOO till 7-30)
2017/02/14 23:08:08
s/sectionIdx/sectionIndex
Objective-C Style Guid
| |
| 324 return [[_partitionedEntries objectAtIndex:section] count]; | 320 DCHECK_LT(sectionIdx, _partitionedItems.size()); |
| 321 return _partitionedItems[sectionIdx].size(); | |
| 325 } | 322 } |
| 326 | 323 |
| 327 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView | 324 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView |
| 328 cellForItemAtIndexPath:(NSIndexPath*)indexPath { | 325 cellForItemAtIndexPath:(NSIndexPath*)indexPath { |
| 329 TabHistoryCell* cell = | 326 TabHistoryCell* cell = |
| 330 [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier | 327 [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier |
| 331 forIndexPath:indexPath]; | 328 forIndexPath:indexPath]; |
| 332 | 329 cell.item = [self itemAtIndexPath:indexPath]; |
| 333 [cell setEntry:[self entryForIndexPath:indexPath]]; | 330 cell.tag = IDC_BACK_FORWARD_IN_TAB_HISTORY; |
| 334 [cell setTag:IDC_BACK_FORWARD_IN_TAB_HISTORY]; | |
| 335 | |
| 336 return cell; | 331 return cell; |
| 337 } | 332 } |
| 338 | 333 |
| 339 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)view { | 334 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)view { |
| 340 return [_partitionedEntries count]; | 335 return _partitionedItems.size(); |
| 341 } | 336 } |
| 342 | 337 |
| 343 - (UICollectionReusableView*)collectionView:(UICollectionView*)view | 338 - (UICollectionReusableView*)collectionView:(UICollectionView*)view |
| 344 viewForSupplementaryElementOfKind:(NSString*)kind | 339 viewForSupplementaryElementOfKind:(NSString*)kind |
| 345 atIndexPath:(NSIndexPath*)indexPath { | 340 atIndexPath:(NSIndexPath*)indexPath { |
| 341 // Return a footer cell if requested. | |
| 346 if ([kind isEqualToString:UICollectionElementKindSectionFooter]) { | 342 if ([kind isEqualToString:UICollectionElementKindSectionFooter]) { |
| 347 return [view dequeueReusableSupplementaryViewOfKind:kind | 343 return [view dequeueReusableSupplementaryViewOfKind:kind |
| 348 withReuseIdentifier:footerIdentifier | 344 withReuseIdentifier:kFooterIdentifier |
| 349 forIndexPath:indexPath]; | 345 forIndexPath:indexPath]; |
| 350 } | 346 } |
| 347 DCHECK([kind isEqualToString:UICollectionElementKindSectionHeader]); | |
| 351 | 348 |
| 352 DCHECK([kind isEqualToString:UICollectionElementKindSectionHeader]); | 349 // Dequeue a header cell and populate its favicon image. |
| 353 CRWSessionEntry* sessionEntry = [self entryForIndexPath:indexPath]; | |
| 354 web::NavigationItem* navigationItem = [sessionEntry navigationItem]; | |
| 355 | |
| 356 TabHistorySectionHeader* header = | 350 TabHistorySectionHeader* header = |
| 357 [view dequeueReusableSupplementaryViewOfKind:kind | 351 [view dequeueReusableSupplementaryViewOfKind:kind |
| 358 withReuseIdentifier:headerIdentifier | 352 withReuseIdentifier:kHeaderIdentifier |
| 359 forIndexPath:indexPath]; | 353 forIndexPath:indexPath]; |
| 360 | |
| 361 UIImage* iconImage = nil; | 354 UIImage* iconImage = nil; |
| 362 const gfx::Image& image = navigationItem->GetFavicon().image; | 355 const gfx::Image& image = |
| 356 [self itemAtIndexPath:indexPath]->GetFavicon().image; | |
| 363 if (!image.IsEmpty()) | 357 if (!image.IsEmpty()) |
| 364 iconImage = image.ToUIImage(); | 358 iconImage = image.ToUIImage(); |
| 365 else | 359 else |
| 366 iconImage = [UIImage imageNamed:@"default_favicon"]; | 360 iconImage = [UIImage imageNamed:@"default_favicon"]; |
| 367 | |
| 368 [[header iconView] setImage:iconImage]; | 361 [[header iconView] setImage:iconImage]; |
| 369 | 362 |
| 370 return header; | 363 return header; |
| 371 } | 364 } |
| 372 | 365 |
| 373 - (void)setSessionEntries:(NSArray*)sessionEntries { | |
| 374 _sessionEntries = sessionEntries; | |
| 375 | |
| 376 std::string previousHost; | |
| 377 | |
| 378 NSMutableArray* sectionArray = [NSMutableArray array]; | |
| 379 NSMutableArray* partitionedEntries = [NSMutableArray array]; | |
| 380 | |
| 381 NSInteger numberOfEntries = [_sessionEntries count]; | |
| 382 for (NSInteger index = 0; index < numberOfEntries; ++index) { | |
| 383 CRWSessionEntry* sessionEntry = [_sessionEntries objectAtIndex:index]; | |
| 384 web::NavigationItem* navigationItem = [sessionEntry navigationItem]; | |
| 385 | |
| 386 std::string currentHost; | |
| 387 if (navigationItem) | |
| 388 currentHost = navigationItem->GetURL().host(); | |
| 389 | |
| 390 if (previousHost.empty()) | |
| 391 previousHost = currentHost; | |
| 392 | |
| 393 // TODO: This should use some sort of Top Level Domain matching instead of | |
| 394 // explicit host match so that images.googe.com matches shopping.google.com. | |
| 395 if (previousHost == currentHost) { | |
| 396 [sectionArray addObject:sessionEntry]; | |
| 397 } else { | |
| 398 [partitionedEntries addObject:sectionArray]; | |
| 399 sectionArray = [NSMutableArray arrayWithObject:sessionEntry]; | |
| 400 previousHost = currentHost; | |
| 401 } | |
| 402 } | |
| 403 | |
| 404 if ([sectionArray count]) | |
| 405 [partitionedEntries addObject:sectionArray]; | |
| 406 | |
| 407 if (![partitionedEntries count]) | |
| 408 partitionedEntries = nil; | |
| 409 | |
| 410 _partitionedEntries = partitionedEntries; | |
| 411 } | |
| 412 | |
| 413 #pragma mark MDCInkTouchControllerDelegate | 366 #pragma mark MDCInkTouchControllerDelegate |
| 414 | 367 |
| 415 - (BOOL)inkTouchController:(MDCInkTouchController*)inkTouchController | 368 - (BOOL)inkTouchController:(MDCInkTouchController*)inkTouchController |
| 416 shouldProcessInkTouchesAtTouchLocation:(CGPoint)location { | 369 shouldProcessInkTouchesAtTouchLocation:(CGPoint)location { |
| 417 NSIndexPath* indexPath = | 370 NSIndexPath* indexPath = |
| 418 [self.collectionView indexPathForItemAtPoint:location]; | 371 [self.collectionView indexPathForItemAtPoint:location]; |
| 419 TabHistoryCell* cell = base::mac::ObjCCastStrict<TabHistoryCell>( | 372 TabHistoryCell* cell = base::mac::ObjCCastStrict<TabHistoryCell>( |
| 420 [self.collectionView cellForItemAtIndexPath:indexPath]); | 373 [self.collectionView cellForItemAtIndexPath:indexPath]); |
| 421 if (!cell) { | 374 if (!cell) { |
| 422 return NO; | 375 return NO; |
| 423 } | 376 } |
| 424 | 377 |
| 425 // Increase the size of the ink view to cover the collection view from edge | 378 // Increase the size of the ink view to cover the collection view from edge |
| 426 // to edge. | 379 // to edge. |
| 427 CGRect inkViewFrame = [cell frame]; | 380 CGRect inkViewFrame = [cell frame]; |
| 428 inkViewFrame.origin.x = 0; | 381 inkViewFrame.origin.x = 0; |
| 429 inkViewFrame.size.width = CGRectGetWidth([self.collectionView bounds]); | 382 inkViewFrame.size.width = CGRectGetWidth([self.collectionView bounds]); |
| 430 [[inkTouchController defaultInkView] setFrame:inkViewFrame]; | 383 [[inkTouchController defaultInkView] setFrame:inkViewFrame]; |
| 431 return YES; | 384 return YES; |
| 432 } | 385 } |
| 433 | 386 |
| 387 #pragma mark - | |
| 388 | |
| 389 - (void)partitionItemsByHost:(const web::NavigationItemList&)items { | |
| 390 _partitionedItems.clear(); | |
| 391 // Used to store the previous host when partitioning NavigationItems. | |
| 392 std::string previousHost; | |
| 393 // The NavigationItemList containing NavigationItems with the same host. | |
| 394 web::NavigationItemList itemsWithSameHostname; | |
| 395 // Separate the items in |items| by host. | |
| 396 for (web::NavigationItem* item : items) { | |
| 397 std::string currentHost = item->GetURL().host(); | |
| 398 if (previousHost.empty()) | |
| 399 previousHost = currentHost; | |
| 400 // TODO: This should use some sort of Top Level Domain matching instead of | |
| 401 // explicit host match so that images.googe.com matches shopping.google.com. | |
| 402 if (previousHost == currentHost) { | |
| 403 itemsWithSameHostname.push_back(item); | |
| 404 } else { | |
| 405 _partitionedItems.push_back(itemsWithSameHostname); | |
| 406 itemsWithSameHostname.clear(); | |
| 407 previousHost = currentHost; | |
| 408 } | |
| 409 } | |
| 410 // Add the last list contiaining the same host. | |
| 411 if (!itemsWithSameHostname.empty()) | |
| 412 _partitionedItems.push_back(itemsWithSameHostname); | |
| 413 } | |
| 414 | |
| 415 - (const web::NavigationItem*)itemAtIndexPath:(NSIndexPath*)indexPath { | |
| 416 size_t section = static_cast<size_t>([indexPath section]); | |
| 417 size_t item = static_cast<size_t>([indexPath item]); | |
| 418 DCHECK_LT(section, _partitionedItems.size()); | |
| 419 DCHECK_LT(item, _partitionedItems[section].size()); | |
| 420 return _partitionedItems[section][item]; | |
| 421 } | |
| 422 | |
| 423 - (void)clearNavigationItems { | |
| 424 _partitionedItems.clear(); | |
| 425 for (UICollectionViewCell* cell in self.collectionView.visibleCells) { | |
| 426 TabHistoryCell* historyCell = base::mac::ObjCCast<TabHistoryCell>(cell); | |
| 427 historyCell.item = nullptr; | |
| 428 } | |
| 429 } | |
| 430 | |
| 434 @end | 431 @end |
| OLD | NEW |