| 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
|
|
|