[go: nahoru, domu]

blob: 056bcf56b328747192daea8b0409e58f58fa8f0f [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/history/history_entry_inserter.h"
#import "base/apple/foundation_util.h"
#import "base/strings/sys_string_conversions.h"
#import "base/time/time.h"
#import "ios/chrome/browser/shared/ui/list_model/list_model.h"
#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_header_footer_item.h"
#import "ios/chrome/browser/ui/history/history_entry_item_interface.h"
#import "ios/chrome/browser/ui/history/history_util.h"
#import "url/gurl.h"
@interface HistoryEntryInserter () {
// ListModel in which to insert history entries.
ListModel* _listModel;
// The index of the first section to contain history entries.
NSInteger _firstSectionIndex;
// Number of assigned section identifiers.
NSInteger _sectionIdentifierCount;
// Sorted set of dates that have history entries.
NSMutableOrderedSet* _dates;
// Mapping from dates to section identifiers.
NSMutableDictionary* _sectionIdentifiers;
}
@end
@implementation HistoryEntryInserter
@synthesize delegate = _delegate;
- (instancetype)initWithModel:(ListModel*)listModel {
if ((self = [super init])) {
_listModel = listModel;
_firstSectionIndex = [listModel numberOfSections];
_dates = [[NSMutableOrderedSet alloc] init];
_sectionIdentifiers = [NSMutableDictionary dictionary];
}
return self;
}
- (void)insertHistoryEntryItem:(ListItem<HistoryEntryItemInterface>*)item {
NSInteger sectionIdentifier =
[self sectionIdentifierForTimestamp:item.timestamp];
NSComparator objectComparator = ^(id obj1, id obj2) {
ListItem<HistoryEntryItemInterface>* firstObject =
base::apple::ObjCCastStrict<ListItem<HistoryEntryItemInterface>>(obj1);
ListItem<HistoryEntryItemInterface>* secondObject =
base::apple::ObjCCastStrict<ListItem<HistoryEntryItemInterface>>(obj2);
if ([firstObject isEqual:secondObject])
return NSOrderedSame;
// History entries are ordered from most to least recent.
if (firstObject.timestamp > secondObject.timestamp)
return NSOrderedAscending;
if (firstObject.timestamp < secondObject.timestamp)
return NSOrderedDescending;
return firstObject.URL < secondObject.URL ? NSOrderedAscending
: NSOrderedDescending;
};
NSArray* items = [_listModel itemsInSectionWithIdentifier:sectionIdentifier];
NSRange range = NSMakeRange(0, [items count]);
// If the object is not already in the section, insert it.
if ([items indexOfObject:item
inSortedRange:range
options:NSBinarySearchingFirstEqual
usingComparator:objectComparator] == NSNotFound) {
// Insert the object at the appropriate index to keep the section sorted.
NSUInteger index = [items indexOfObject:item
inSortedRange:range
options:NSBinarySearchingInsertionIndex
usingComparator:objectComparator];
// Calculate the new tableView indexPath row before inserting into the
// model. No matter where in the model the item is inserted, a new row will
// be created for the tableView. For this reason, make sure to insert a new
// index into the tableView after the item has been inserted into the model.
NSInteger section =
[_listModel sectionForSectionIdentifier:sectionIdentifier];
NSInteger tableViewRow = [_listModel numberOfItemsInSection:section];
NSIndexPath* tableIndexPath =
[NSIndexPath indexPathForRow:tableViewRow inSection:section];
[_listModel insertItem:item
inSectionWithIdentifier:sectionIdentifier
atIndex:index];
[self.delegate historyEntryInserter:self
didInsertItemAtIndexPath:tableIndexPath];
}
}
- (NSUInteger)sectionIdentifierForTimestamp:(base::Time)timestamp {
base::TimeDelta timeDelta =
timestamp.LocalMidnight() - base::Time::UnixEpoch();
NSDate* date = [NSDate dateWithTimeIntervalSince1970:timeDelta.InSeconds()];
NSInteger sectionIdentifier =
[[_sectionIdentifiers objectForKey:date] integerValue];
// If there is a section identifier for the date, return it.
if (sectionIdentifier) {
return sectionIdentifier;
}
// Get the next section identifier, and add a section for date.
sectionIdentifier =
kSectionIdentifierEnumZero + _firstSectionIndex + _sectionIdentifierCount;
++_sectionIdentifierCount;
[_sectionIdentifiers setObject:@(sectionIdentifier) forKey:date];
NSComparator comparator = ^(id obj1, id obj2) {
// Dates are ordered from most to least recent.
return [obj2 compare:obj1];
};
NSUInteger index = [_dates indexOfObject:date
inSortedRange:NSMakeRange(0, [_dates count])
options:NSBinarySearchingInsertionIndex
usingComparator:comparator];
[_dates insertObject:date atIndex:index];
NSInteger insertionIndex = _firstSectionIndex + index;
[_listModel insertSectionWithIdentifier:sectionIdentifier
atIndex:insertionIndex];
TableViewTextHeaderFooterItem* header =
[[TableViewTextHeaderFooterItem alloc] initWithType:kItemTypeEnumZero];
header.text =
base::SysUTF16ToNSString(history::GetRelativeDateLocalized(timestamp));
[_listModel setHeader:header forSectionWithIdentifier:sectionIdentifier];
[self.delegate historyEntryInserter:self
didInsertSectionAtIndex:insertionIndex];
return sectionIdentifier;
}
- (void)removeSection:(NSInteger)sectionIndex {
NSUInteger sectionIdentifier =
[_listModel sectionIdentifierForSectionIndex:sectionIndex];
// Sections should not be removed unless there are no items in that section.
DCHECK(![[_listModel itemsInSectionWithIdentifier:sectionIdentifier] count]);
[_listModel removeSectionWithIdentifier:sectionIdentifier];
NSEnumerator* dateEnumerator = [_sectionIdentifiers keyEnumerator];
NSDate* date = nil;
while ((date = [dateEnumerator nextObject])) {
if ([[_sectionIdentifiers objectForKey:date] unsignedIntegerValue] ==
sectionIdentifier) {
[_sectionIdentifiers removeObjectForKey:date];
[_dates removeObject:date];
break;
}
}
[self.delegate historyEntryInserter:self
didRemoveSectionAtIndex:sectionIndex];
}
@end