Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(515)

Side by Side Diff: ios/chrome/browser/ui/history/tab_history_view_controller.mm

Issue 2706403009: Revert of Updated tab history classes to use NavigationItemLists. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
15 #include "ios/web/public/favicon_status.h" 16 #include "ios/web/public/favicon_status.h"
16 #include "ios/web/public/navigation_item.h" 17 #include "ios/web/public/navigation_item.h"
17 #include "ui/gfx/image/image.h" 18 #include "ui/gfx/image/image.h"
18 19
19 #if !defined(__has_feature) || !__has_feature(objc_arc) 20 #if !defined(__has_feature) || !__has_feature(objc_arc)
20 #error "This file requires ARC support." 21 #error "This file requires ARC support."
21 #endif 22 #endif
22 23
23 namespace { 24 namespace {
24 25
25 // Visible percentage of the last visible row on the Tools menu if the 26 // Visible percentage of the last visible row on the Tools menu if the
26 // Tools menu is scrollable. 27 // Tools menu is scrollable.
27 const CGFloat kLastRowVisiblePercentage = 0.6; 28 const CGFloat kLastRowVisiblePercentage = 0.6;
28 // Reuse identifier for cells. 29 // Reuse identifier for cells.
29 NSString* const kCellIdentifier = @"TabHistoryCell"; 30 NSString* cellIdentifier = @"TabHistoryCell";
30 NSString* const kFooterIdentifier = @"Footer"; 31 NSString* footerIdentifier = @"Footer";
31 NSString* const kHeaderIdentifier = @"Header"; 32 NSString* headerIdentifier = @"Header";
32 // The collection view's a11y label.
33 NSString* const kCollectionViewLabel = @"Tab History";
34 // Height of rows. 33 // Height of rows.
35 const CGFloat kCellHeight = 48.0; 34 const CGFloat kCellHeight = 48.0;
36 // Fraction height for partially visible row. 35 // Fraction height for partially visible row.
37 const CGFloat kCellHeightLastRow = kCellHeight * kLastRowVisiblePercentage; 36 const CGFloat kCellHeightLastRow = kCellHeight * kLastRowVisiblePercentage;
38 // Width and leading for the header view. 37 // Width and leading for the header view.
39 const CGFloat kHeaderLeadingInset = 0; 38 const CGFloat kHeaderLeadingInset = 0;
40 const CGFloat kHeaderWidth = 48; 39 const CGFloat kHeaderWidth = 48;
41 // Leading and trailing insets for cell items. 40 // Leading and trailing insets for cell items.
42 const CGFloat kCellLeadingInset = kHeaderLeadingInset + kHeaderWidth; 41 const CGFloat kCellLeadingInset = kHeaderLeadingInset + kHeaderWidth;
43 const CGFloat kCellTrailingInset = 16; 42 const CGFloat kCellTrailingInset = 16;
(...skipping 21 matching lines...) Expand all
65 DCHECK(offsets.at([path section]).size()); 64 DCHECK(offsets.at([path section]).size());
66 65
67 return offsets.at([path section]).at(0); 66 return offsets.at([path section]).at(0);
68 } 67 }
69 68
70 // Height for the footer view. 69 // Height for the footer view.
71 NS_INLINE CGFloat FooterHeight() { 70 NS_INLINE CGFloat FooterHeight() {
72 return 1.0 / [[UIScreen mainScreen] scale]; 71 return 1.0 / [[UIScreen mainScreen] scale];
73 } 72 }
74 73
75 // Returns a vector of of NavigationItemLists where the NavigationItems in
76 // |items| are separated by host.
77 NS_INLINE std::vector<web::NavigationItemList> PartitionItemsByHost(
78 const web::NavigationItemList& items) {
79 std::vector<web::NavigationItemList> partitionedItems;
80 // Used to store the previous host when partitioning NavigationItems.
81 std::string previousHost;
82 // The NavigationItemList containing NavigationItems with the same host.
83 web::NavigationItemList itemsWithSameHostname;
84 // Separate the items in |items| by host.
85 for (web::NavigationItem* item : items) {
86 std::string currentHost = item->GetURL().host();
87 if (previousHost.empty())
88 previousHost = currentHost;
89 // TODO: This should use some sort of Top Level Domain matching instead of
90 // explicit host match so that images.googe.com matches shopping.google.com.
91 if (previousHost == currentHost) {
92 itemsWithSameHostname.push_back(item);
93 } else {
94 partitionedItems.push_back(itemsWithSameHostname);
95 itemsWithSameHostname = web::NavigationItemList(1, item);
96 previousHost = currentHost;
97 }
98 }
99 // Add the last list contiaining the same host.
100 if (!itemsWithSameHostname.empty())
101 partitionedItems.push_back(itemsWithSameHostname);
102 return partitionedItems;
103 }
104
105 } // namespace 74 } // namespace
106 75
107 @interface TabHistoryViewControllerLayout : UICollectionViewLayout 76 @interface TabHistoryViewControllerLayout : UICollectionViewLayout
108 @end 77 @end
109 78
110 @implementation TabHistoryViewControllerLayout { 79 @implementation TabHistoryViewControllerLayout {
111 ItemOffsetVector _itemYOffsets; 80 ItemOffsetVector _itemYOffsets;
112 CGFloat _containerCalculatedHeight; 81 CGFloat _containerCalculatedHeight;
113 CGFloat _containerWidth; 82 CGFloat _containerWidth;
114 CGFloat _cellItemWidth; 83 CGFloat _cellItemWidth;
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 [attributes setZIndex:0]; 212 [attributes setZIndex:0];
244 } 213 }
245 214
246 return attributes; 215 return attributes;
247 } 216 }
248 217
249 @end 218 @end
250 219
251 @interface TabHistoryViewController ()<MDCInkTouchControllerDelegate> { 220 @interface TabHistoryViewController ()<MDCInkTouchControllerDelegate> {
252 MDCInkTouchController* _inkTouchController; 221 MDCInkTouchController* _inkTouchController;
253 // A vector of NavigationItemLists where the NavigationItems are separated 222 NSArray* _partitionedEntries;
254 // by hostname. 223 NSArray* _sessionEntries;
255 std::vector<web::NavigationItemList> _partitionedItems;
256 } 224 }
257
258 // Returns the NavigationItem corresponding with |indexPath|.
259 - (const web::NavigationItem*)itemAtIndexPath:(NSIndexPath*)indexPath;
260
261 // Removes all NavigationItem pointers from this class. Tapping a cell that
262 // triggers a navigation may delete NavigationItems, so NavigationItem
263 // references should be reset to avoid use-after-free errors.
264 - (void)clearNavigationItems;
265
266 @end 225 @end
267 226
268 @implementation TabHistoryViewController 227 @implementation TabHistoryViewController
269 228
270 - (instancetype)initWithItems:(const web::NavigationItemList&)items { 229 - (NSArray*)sessionEntries {
271 TabHistoryViewControllerLayout* layout = 230 return _sessionEntries;
272 [[TabHistoryViewControllerLayout alloc] init];
273 if ((self = [super initWithCollectionViewLayout:layout])) {
274 // Populate |_partitionedItems|.
275 _partitionedItems = PartitionItemsByHost(items);
276
277 // Set up the UICollectionView.
278 UICollectionView* collectionView = [self collectionView];
279 collectionView.accessibilityLabel = kCollectionViewLabel;
280 collectionView.backgroundColor = [UIColor whiteColor];
281 [collectionView registerClass:[TabHistoryCell class]
282 forCellWithReuseIdentifier:kCellIdentifier];
283 [collectionView registerClass:[TabHistorySectionHeader class]
284 forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
285 withReuseIdentifier:kHeaderIdentifier];
286 [collectionView registerClass:[TabHistorySectionFooter class]
287 forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
288 withReuseIdentifier:kFooterIdentifier];
289
290 // Set up the ink controller.
291 _inkTouchController =
292 [[MDCInkTouchController alloc] initWithView:collectionView];
293 [_inkTouchController setDelegate:self];
294 [_inkTouchController addInkView];
295 }
296 return self;
297 } 231 }
298 232
299 #pragma mark Public Methods 233 #pragma mark Public Methods
300 234
301 - (CGFloat)optimalHeight:(CGFloat)suggestedHeight { 235 - (CGFloat)optimalHeight:(CGFloat)suggestedHeight {
302 DCHECK(suggestedHeight >= kCellHeight); 236 DCHECK(suggestedHeight >= kCellHeight);
303 CGFloat optimalHeight = 0; 237 CGFloat optimalHeight = 0;
304 238
305 for (web::NavigationItemList& itemsWithSameHost : _partitionedItems) { 239 for (NSArray* sectionArray in _partitionedEntries) {
306 for (size_t count = 0; count < itemsWithSameHost.size(); ++count) { 240 NSUInteger sectionItemCount = [sectionArray count];
241 for (NSUInteger i = 0; i < sectionItemCount; ++i) {
307 CGFloat proposedHeight = optimalHeight + kCellHeight; 242 CGFloat proposedHeight = optimalHeight + kCellHeight;
308 243
309 if (proposedHeight > suggestedHeight) { 244 if (proposedHeight > suggestedHeight) {
310 CGFloat difference = proposedHeight - suggestedHeight; 245 CGFloat difference = proposedHeight - suggestedHeight;
311 if (difference > kCellHeightLastRow) { 246 if (difference > kCellHeightLastRow) {
312 return optimalHeight + kCellHeightLastRow; 247 return optimalHeight + kCellHeightLastRow;
313 } else { 248 } else {
314 return optimalHeight - kCellHeight + kCellHeightLastRow; 249 return optimalHeight - kCellHeight + kCellHeightLastRow;
315 } 250 }
316 } 251 }
317 252
318 optimalHeight = proposedHeight; 253 optimalHeight = proposedHeight;
319 } 254 }
320 255
321 optimalHeight += FooterHeight(); 256 optimalHeight += FooterHeight();
322 } 257 }
323 258
324 // If this point is reached, it means the entire content fits and this last 259 // If this point is reached, it means the entire content fits and this last
325 // section should not include the footer. 260 // section should not include the footer.
326 optimalHeight -= FooterHeight(); 261 optimalHeight -= FooterHeight();
327 262
328 return optimalHeight; 263 return optimalHeight;
329 } 264 }
330 265
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
331 #pragma mark UICollectionViewDelegate 299 #pragma mark UICollectionViewDelegate
332 300
333 - (void)collectionView:(UICollectionView*)collectionView 301 - (void)collectionView:(UICollectionView*)collectionView
334 didSelectItemAtIndexPath:(NSIndexPath*)indexPath { 302 didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
335 TabHistoryCell* cell = base::mac::ObjCCastStrict<TabHistoryCell>( 303 UICollectionViewCell* cell =
336 [collectionView cellForItemAtIndexPath:indexPath]); 304 [collectionView cellForItemAtIndexPath:indexPath];
337 [collectionView chromeExecuteCommand:cell]; 305 [collectionView chromeExecuteCommand:cell];
338 [self clearNavigationItems];
339 } 306 }
340 307
341 #pragma mark UICollectionViewDataSource 308 #pragma mark UICollectionViewDataSource
342 309
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
343 - (NSInteger)collectionView:(UICollectionView*)collectionView 321 - (NSInteger)collectionView:(UICollectionView*)collectionView
344 numberOfItemsInSection:(NSInteger)section { 322 numberOfItemsInSection:(NSInteger)section {
345 size_t sectionIdx = static_cast<size_t>(section); 323 DCHECK(section < (NSInteger)[_partitionedEntries count]);
346 DCHECK_LT(sectionIdx, _partitionedItems.size()); 324 return [[_partitionedEntries objectAtIndex:section] count];
347 return _partitionedItems[sectionIdx].size();
348 } 325 }
349 326
350 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView 327 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
351 cellForItemAtIndexPath:(NSIndexPath*)indexPath { 328 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
352 TabHistoryCell* cell = 329 TabHistoryCell* cell =
353 [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier 330 [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier
354 forIndexPath:indexPath]; 331 forIndexPath:indexPath];
355 cell.item = [self itemAtIndexPath:indexPath]; 332
356 cell.tag = IDC_BACK_FORWARD_IN_TAB_HISTORY; 333 [cell setEntry:[self entryForIndexPath:indexPath]];
334 [cell setTag:IDC_BACK_FORWARD_IN_TAB_HISTORY];
335
357 return cell; 336 return cell;
358 } 337 }
359 338
360 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)view { 339 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)view {
361 return _partitionedItems.size(); 340 return [_partitionedEntries count];
362 } 341 }
363 342
364 - (UICollectionReusableView*)collectionView:(UICollectionView*)view 343 - (UICollectionReusableView*)collectionView:(UICollectionView*)view
365 viewForSupplementaryElementOfKind:(NSString*)kind 344 viewForSupplementaryElementOfKind:(NSString*)kind
366 atIndexPath:(NSIndexPath*)indexPath { 345 atIndexPath:(NSIndexPath*)indexPath {
367 // Return a footer cell if requested.
368 if ([kind isEqualToString:UICollectionElementKindSectionFooter]) { 346 if ([kind isEqualToString:UICollectionElementKindSectionFooter]) {
369 return [view dequeueReusableSupplementaryViewOfKind:kind 347 return [view dequeueReusableSupplementaryViewOfKind:kind
370 withReuseIdentifier:kFooterIdentifier 348 withReuseIdentifier:footerIdentifier
371 forIndexPath:indexPath]; 349 forIndexPath:indexPath];
372 } 350 }
351
373 DCHECK([kind isEqualToString:UICollectionElementKindSectionHeader]); 352 DCHECK([kind isEqualToString:UICollectionElementKindSectionHeader]);
353 CRWSessionEntry* sessionEntry = [self entryForIndexPath:indexPath];
354 web::NavigationItem* navigationItem = [sessionEntry navigationItem];
374 355
375 // Dequeue a header cell and populate its favicon image.
376 TabHistorySectionHeader* header = 356 TabHistorySectionHeader* header =
377 [view dequeueReusableSupplementaryViewOfKind:kind 357 [view dequeueReusableSupplementaryViewOfKind:kind
378 withReuseIdentifier:kHeaderIdentifier 358 withReuseIdentifier:headerIdentifier
379 forIndexPath:indexPath]; 359 forIndexPath:indexPath];
360
380 UIImage* iconImage = nil; 361 UIImage* iconImage = nil;
381 const gfx::Image& image = 362 const gfx::Image& image = navigationItem->GetFavicon().image;
382 [self itemAtIndexPath:indexPath]->GetFavicon().image;
383 if (!image.IsEmpty()) 363 if (!image.IsEmpty())
384 iconImage = image.ToUIImage(); 364 iconImage = image.ToUIImage();
385 else 365 else
386 iconImage = [UIImage imageNamed:@"default_favicon"]; 366 iconImage = [UIImage imageNamed:@"default_favicon"];
367
387 [[header iconView] setImage:iconImage]; 368 [[header iconView] setImage:iconImage];
388 369
389 return header; 370 return header;
390 } 371 }
391 372
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
392 #pragma mark MDCInkTouchControllerDelegate 413 #pragma mark MDCInkTouchControllerDelegate
393 414
394 - (BOOL)inkTouchController:(MDCInkTouchController*)inkTouchController 415 - (BOOL)inkTouchController:(MDCInkTouchController*)inkTouchController
395 shouldProcessInkTouchesAtTouchLocation:(CGPoint)location { 416 shouldProcessInkTouchesAtTouchLocation:(CGPoint)location {
396 NSIndexPath* indexPath = 417 NSIndexPath* indexPath =
397 [self.collectionView indexPathForItemAtPoint:location]; 418 [self.collectionView indexPathForItemAtPoint:location];
398 TabHistoryCell* cell = base::mac::ObjCCastStrict<TabHistoryCell>( 419 TabHistoryCell* cell = base::mac::ObjCCastStrict<TabHistoryCell>(
399 [self.collectionView cellForItemAtIndexPath:indexPath]); 420 [self.collectionView cellForItemAtIndexPath:indexPath]);
400 if (!cell) { 421 if (!cell) {
401 return NO; 422 return NO;
402 } 423 }
403 424
404 // Increase the size of the ink view to cover the collection view from edge 425 // Increase the size of the ink view to cover the collection view from edge
405 // to edge. 426 // to edge.
406 CGRect inkViewFrame = [cell frame]; 427 CGRect inkViewFrame = [cell frame];
407 inkViewFrame.origin.x = 0; 428 inkViewFrame.origin.x = 0;
408 inkViewFrame.size.width = CGRectGetWidth([self.collectionView bounds]); 429 inkViewFrame.size.width = CGRectGetWidth([self.collectionView bounds]);
409 [[inkTouchController defaultInkView] setFrame:inkViewFrame]; 430 [[inkTouchController defaultInkView] setFrame:inkViewFrame];
410 return YES; 431 return YES;
411 } 432 }
412 433
413 #pragma mark -
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
431 @end 434 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/history/tab_history_view_controller.h ('k') | ios/chrome/browser/ui/toolbar/web_toolbar_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698