Index: ios/chrome/browser/ui/history/tab_history_view_controller.mm |
diff --git a/ios/chrome/browser/ui/history/tab_history_view_controller.mm b/ios/chrome/browser/ui/history/tab_history_view_controller.mm |
index 5f84835e3722f9a9a0541c0884779ea516126c50..954ea175ae541159381e16051280b8637e80e1e0 100644 |
--- a/ios/chrome/browser/ui/history/tab_history_view_controller.mm |
+++ b/ios/chrome/browser/ui/history/tab_history_view_controller.mm |
@@ -12,6 +12,7 @@ |
#import "ios/chrome/browser/ui/history/tab_history_cell.h" |
#include "ios/chrome/browser/ui/rtl_geometry.h" |
#import "ios/third_party/material_components_ios/src/components/Ink/src/MaterialInk.h" |
+#import "ios/web/navigation/crw_session_entry.h" |
#include "ios/web/public/favicon_status.h" |
#include "ios/web/public/navigation_item.h" |
#include "ui/gfx/image/image.h" |
@@ -26,11 +27,9 @@ |
// Tools menu is scrollable. |
const CGFloat kLastRowVisiblePercentage = 0.6; |
// Reuse identifier for cells. |
-NSString* const kCellIdentifier = @"TabHistoryCell"; |
-NSString* const kFooterIdentifier = @"Footer"; |
-NSString* const kHeaderIdentifier = @"Header"; |
-// The collection view's a11y label. |
-NSString* const kCollectionViewLabel = @"Tab History"; |
+NSString* cellIdentifier = @"TabHistoryCell"; |
+NSString* footerIdentifier = @"Footer"; |
+NSString* headerIdentifier = @"Header"; |
// Height of rows. |
const CGFloat kCellHeight = 48.0; |
// Fraction height for partially visible row. |
@@ -72,36 +71,6 @@ |
return 1.0 / [[UIScreen mainScreen] scale]; |
} |
-// Returns a vector of of NavigationItemLists where the NavigationItems in |
-// |items| are separated by host. |
-NS_INLINE std::vector<web::NavigationItemList> PartitionItemsByHost( |
- const web::NavigationItemList& items) { |
- std::vector<web::NavigationItemList> partitionedItems; |
- // Used to store the previous host when partitioning NavigationItems. |
- std::string previousHost; |
- // The NavigationItemList containing NavigationItems with the same host. |
- web::NavigationItemList itemsWithSameHostname; |
- // Separate the items in |items| by host. |
- for (web::NavigationItem* item : items) { |
- std::string currentHost = item->GetURL().host(); |
- if (previousHost.empty()) |
- previousHost = currentHost; |
- // TODO: This should use some sort of Top Level Domain matching instead of |
- // explicit host match so that images.googe.com matches shopping.google.com. |
- if (previousHost == currentHost) { |
- itemsWithSameHostname.push_back(item); |
- } else { |
- partitionedItems.push_back(itemsWithSameHostname); |
- itemsWithSameHostname = web::NavigationItemList(1, item); |
- previousHost = currentHost; |
- } |
- } |
- // Add the last list contiaining the same host. |
- if (!itemsWithSameHostname.empty()) |
- partitionedItems.push_back(itemsWithSameHostname); |
- return partitionedItems; |
-} |
- |
} // namespace |
@interface TabHistoryViewControllerLayout : UICollectionViewLayout |
@@ -250,50 +219,15 @@ |
@interface TabHistoryViewController ()<MDCInkTouchControllerDelegate> { |
MDCInkTouchController* _inkTouchController; |
- // A vector of NavigationItemLists where the NavigationItems are separated |
- // by hostname. |
- std::vector<web::NavigationItemList> _partitionedItems; |
-} |
- |
-// Returns the NavigationItem corresponding with |indexPath|. |
-- (const web::NavigationItem*)itemAtIndexPath:(NSIndexPath*)indexPath; |
- |
-// Removes all NavigationItem pointers from this class. Tapping a cell that |
-// triggers a navigation may delete NavigationItems, so NavigationItem |
-// references should be reset to avoid use-after-free errors. |
-- (void)clearNavigationItems; |
- |
+ NSArray* _partitionedEntries; |
+ NSArray* _sessionEntries; |
+} |
@end |
@implementation TabHistoryViewController |
-- (instancetype)initWithItems:(const web::NavigationItemList&)items { |
- TabHistoryViewControllerLayout* layout = |
- [[TabHistoryViewControllerLayout alloc] init]; |
- if ((self = [super initWithCollectionViewLayout:layout])) { |
- // Populate |_partitionedItems|. |
- _partitionedItems = PartitionItemsByHost(items); |
- |
- // Set up the UICollectionView. |
- UICollectionView* collectionView = [self collectionView]; |
- collectionView.accessibilityLabel = kCollectionViewLabel; |
- collectionView.backgroundColor = [UIColor whiteColor]; |
- [collectionView registerClass:[TabHistoryCell class] |
- forCellWithReuseIdentifier:kCellIdentifier]; |
- [collectionView registerClass:[TabHistorySectionHeader class] |
- forSupplementaryViewOfKind:UICollectionElementKindSectionHeader |
- withReuseIdentifier:kHeaderIdentifier]; |
- [collectionView registerClass:[TabHistorySectionFooter class] |
- forSupplementaryViewOfKind:UICollectionElementKindSectionFooter |
- withReuseIdentifier:kFooterIdentifier]; |
- |
- // Set up the ink controller. |
- _inkTouchController = |
- [[MDCInkTouchController alloc] initWithView:collectionView]; |
- [_inkTouchController setDelegate:self]; |
- [_inkTouchController addInkView]; |
- } |
- return self; |
+- (NSArray*)sessionEntries { |
+ return _sessionEntries; |
} |
#pragma mark Public Methods |
@@ -302,8 +236,9 @@ |
DCHECK(suggestedHeight >= kCellHeight); |
CGFloat optimalHeight = 0; |
- for (web::NavigationItemList& itemsWithSameHost : _partitionedItems) { |
- for (size_t count = 0; count < itemsWithSameHost.size(); ++count) { |
+ for (NSArray* sectionArray in _partitionedEntries) { |
+ NSUInteger sectionItemCount = [sectionArray count]; |
+ for (NSUInteger i = 0; i < sectionItemCount; ++i) { |
CGFloat proposedHeight = optimalHeight + kCellHeight; |
if (proposedHeight > suggestedHeight) { |
@@ -328,65 +263,151 @@ |
return optimalHeight; |
} |
+- (instancetype)init { |
+ TabHistoryViewControllerLayout* layout = |
+ [[TabHistoryViewControllerLayout alloc] init]; |
+ |
+ return [self initWithCollectionViewLayout:layout]; |
+} |
+ |
+- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout*)layout { |
+ self = [super initWithCollectionViewLayout:layout]; |
+ if (self) { |
+ UICollectionView* collectionView = [self collectionView]; |
+ [collectionView setBackgroundColor:[UIColor whiteColor]]; |
+ |
+ [collectionView registerClass:[TabHistoryCell class] |
+ forCellWithReuseIdentifier:cellIdentifier]; |
+ |
+ [collectionView registerClass:[TabHistorySectionHeader class] |
+ forSupplementaryViewOfKind:UICollectionElementKindSectionHeader |
+ withReuseIdentifier:headerIdentifier]; |
+ |
+ [collectionView registerClass:[TabHistorySectionFooter class] |
+ forSupplementaryViewOfKind:UICollectionElementKindSectionFooter |
+ withReuseIdentifier:footerIdentifier]; |
+ |
+ _inkTouchController = |
+ [[MDCInkTouchController alloc] initWithView:collectionView]; |
+ [_inkTouchController setDelegate:self]; |
+ [_inkTouchController addInkView]; |
+ } |
+ |
+ return self; |
+} |
+ |
#pragma mark UICollectionViewDelegate |
- (void)collectionView:(UICollectionView*)collectionView |
didSelectItemAtIndexPath:(NSIndexPath*)indexPath { |
- TabHistoryCell* cell = base::mac::ObjCCastStrict<TabHistoryCell>( |
- [collectionView cellForItemAtIndexPath:indexPath]); |
+ UICollectionViewCell* cell = |
+ [collectionView cellForItemAtIndexPath:indexPath]; |
[collectionView chromeExecuteCommand:cell]; |
- [self clearNavigationItems]; |
} |
#pragma mark UICollectionViewDataSource |
+ |
+- (CRWSessionEntry*)entryForIndexPath:(NSIndexPath*)indexPath { |
+ NSInteger section = [indexPath section]; |
+ NSInteger item = [indexPath item]; |
+ |
+ DCHECK(section < (NSInteger)[_partitionedEntries count]); |
+ DCHECK(item < (NSInteger)[[_partitionedEntries objectAtIndex:section] count]); |
+ NSArray* sectionedArray = [_partitionedEntries objectAtIndex:section]; |
+ |
+ return [sectionedArray objectAtIndex:item]; |
+} |
- (NSInteger)collectionView:(UICollectionView*)collectionView |
numberOfItemsInSection:(NSInteger)section { |
- size_t sectionIdx = static_cast<size_t>(section); |
- DCHECK_LT(sectionIdx, _partitionedItems.size()); |
- return _partitionedItems[sectionIdx].size(); |
+ DCHECK(section < (NSInteger)[_partitionedEntries count]); |
+ return [[_partitionedEntries objectAtIndex:section] count]; |
} |
- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView |
cellForItemAtIndexPath:(NSIndexPath*)indexPath { |
TabHistoryCell* cell = |
- [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier |
+ [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier |
forIndexPath:indexPath]; |
- cell.item = [self itemAtIndexPath:indexPath]; |
- cell.tag = IDC_BACK_FORWARD_IN_TAB_HISTORY; |
+ |
+ [cell setEntry:[self entryForIndexPath:indexPath]]; |
+ [cell setTag:IDC_BACK_FORWARD_IN_TAB_HISTORY]; |
+ |
return cell; |
} |
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)view { |
- return _partitionedItems.size(); |
+ return [_partitionedEntries count]; |
} |
- (UICollectionReusableView*)collectionView:(UICollectionView*)view |
viewForSupplementaryElementOfKind:(NSString*)kind |
atIndexPath:(NSIndexPath*)indexPath { |
- // Return a footer cell if requested. |
if ([kind isEqualToString:UICollectionElementKindSectionFooter]) { |
return [view dequeueReusableSupplementaryViewOfKind:kind |
- withReuseIdentifier:kFooterIdentifier |
+ withReuseIdentifier:footerIdentifier |
forIndexPath:indexPath]; |
} |
+ |
DCHECK([kind isEqualToString:UICollectionElementKindSectionHeader]); |
- |
- // Dequeue a header cell and populate its favicon image. |
+ CRWSessionEntry* sessionEntry = [self entryForIndexPath:indexPath]; |
+ web::NavigationItem* navigationItem = [sessionEntry navigationItem]; |
+ |
TabHistorySectionHeader* header = |
[view dequeueReusableSupplementaryViewOfKind:kind |
- withReuseIdentifier:kHeaderIdentifier |
+ withReuseIdentifier:headerIdentifier |
forIndexPath:indexPath]; |
+ |
UIImage* iconImage = nil; |
- const gfx::Image& image = |
- [self itemAtIndexPath:indexPath]->GetFavicon().image; |
+ const gfx::Image& image = navigationItem->GetFavicon().image; |
if (!image.IsEmpty()) |
iconImage = image.ToUIImage(); |
else |
iconImage = [UIImage imageNamed:@"default_favicon"]; |
+ |
[[header iconView] setImage:iconImage]; |
return header; |
+} |
+ |
+- (void)setSessionEntries:(NSArray*)sessionEntries { |
+ _sessionEntries = sessionEntries; |
+ |
+ std::string previousHost; |
+ |
+ NSMutableArray* sectionArray = [NSMutableArray array]; |
+ NSMutableArray* partitionedEntries = [NSMutableArray array]; |
+ |
+ NSInteger numberOfEntries = [_sessionEntries count]; |
+ for (NSInteger index = 0; index < numberOfEntries; ++index) { |
+ CRWSessionEntry* sessionEntry = [_sessionEntries objectAtIndex:index]; |
+ web::NavigationItem* navigationItem = [sessionEntry navigationItem]; |
+ |
+ std::string currentHost; |
+ if (navigationItem) |
+ currentHost = navigationItem->GetURL().host(); |
+ |
+ if (previousHost.empty()) |
+ previousHost = currentHost; |
+ |
+ // TODO: This should use some sort of Top Level Domain matching instead of |
+ // explicit host match so that images.googe.com matches shopping.google.com. |
+ if (previousHost == currentHost) { |
+ [sectionArray addObject:sessionEntry]; |
+ } else { |
+ [partitionedEntries addObject:sectionArray]; |
+ sectionArray = [NSMutableArray arrayWithObject:sessionEntry]; |
+ previousHost = currentHost; |
+ } |
+ } |
+ |
+ if ([sectionArray count]) |
+ [partitionedEntries addObject:sectionArray]; |
+ |
+ if (![partitionedEntries count]) |
+ partitionedEntries = nil; |
+ |
+ _partitionedEntries = partitionedEntries; |
} |
#pragma mark MDCInkTouchControllerDelegate |
@@ -410,22 +431,4 @@ |
return YES; |
} |
-#pragma mark - |
- |
-- (const web::NavigationItem*)itemAtIndexPath:(NSIndexPath*)indexPath { |
- size_t section = static_cast<size_t>([indexPath section]); |
- size_t item = static_cast<size_t>([indexPath item]); |
- DCHECK_LT(section, _partitionedItems.size()); |
- DCHECK_LT(item, _partitionedItems[section].size()); |
- return _partitionedItems[section][item]; |
-} |
- |
-- (void)clearNavigationItems { |
- _partitionedItems.clear(); |
- for (UICollectionViewCell* cell in self.collectionView.visibleCells) { |
- TabHistoryCell* historyCell = base::mac::ObjCCast<TabHistoryCell>(cell); |
- historyCell.item = nullptr; |
- } |
-} |
- |
@end |