| Index: ios/chrome/browser/ui/history/history_entry_inserter.mm
|
| diff --git a/ios/chrome/browser/ui/history/history_entry_inserter.mm b/ios/chrome/browser/ui/history/history_entry_inserter.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f442455d57322239b7cb46fbaabd2762a1aa8425
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/history/history_entry_inserter.mm
|
| @@ -0,0 +1,165 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// 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/ios/weak_nsobject.h"
|
| +#include "base/mac/foundation_util.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| +#include "base/strings/sys_string_conversions.h"
|
| +#include "base/time/time.h"
|
| +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
|
| +#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
|
| +#import "ios/chrome/browser/ui/history/history_entry_item.h"
|
| +#include "ios/chrome/browser/ui/history/history_util.h"
|
| +#include "url/gurl.h"
|
| +
|
| +@interface HistoryEntryInserter () {
|
| + // Delegate for the HistoryEntryInserter.
|
| + base::WeakNSProtocol<id<HistoryEntryInserterDelegate>> _delegate;
|
| + // CollectionViewModel in which to insert history entries.
|
| + base::scoped_nsobject<CollectionViewModel> _collectionViewModel;
|
| + // 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.
|
| + base::scoped_nsobject<NSMutableOrderedSet> _dates;
|
| + // Mapping from dates to section identifiers.
|
| + base::scoped_nsobject<NSMutableDictionary> _sectionIdentifiers;
|
| +}
|
| +
|
| +@end
|
| +
|
| +@implementation HistoryEntryInserter
|
| +
|
| +- (instancetype)initWithModel:(CollectionViewModel*)collectionViewModel {
|
| + if ((self = [super init])) {
|
| + _collectionViewModel.reset([collectionViewModel retain]);
|
| + _firstSectionIndex = [collectionViewModel numberOfSections];
|
| + _dates.reset([[NSMutableOrderedSet alloc] init]);
|
| + _sectionIdentifiers.reset([[NSMutableDictionary dictionary] retain]);
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (id<HistoryEntryInserterDelegate>)delegate {
|
| + return _delegate;
|
| +}
|
| +
|
| +- (void)setDelegate:(id<HistoryEntryInserterDelegate>)delegate {
|
| + _delegate.reset(delegate);
|
| +}
|
| +
|
| +- (void)insertHistoryEntryItem:(HistoryEntryItem*)item {
|
| + NSInteger sectionIdentifier =
|
| + [self sectionIdentifierForTimestamp:item.timestamp];
|
| +
|
| + NSComparator objectComparator = ^(id obj1, id obj2) {
|
| + HistoryEntryItem* firstObject =
|
| + base::mac::ObjCCastStrict<HistoryEntryItem>(obj1);
|
| + HistoryEntryItem* secondObject =
|
| + base::mac::ObjCCastStrict<HistoryEntryItem>(obj2);
|
| + if ([firstObject isEqualToHistoryEntryItem: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 =
|
| + [_collectionViewModel 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];
|
| + [_collectionViewModel insertItem:item
|
| + inSectionWithIdentifier:sectionIdentifier
|
| + atIndex:index];
|
| + NSIndexPath* indexPath = [NSIndexPath
|
| + indexPathForItem:index
|
| + inSection:[_collectionViewModel
|
| + sectionForSectionIdentifier:sectionIdentifier]];
|
| + [self.delegate historyEntryInserter:self
|
| + didInsertItemAtIndexPath:indexPath];
|
| + }
|
| +}
|
| +
|
| +- (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;
|
| + CollectionViewTextItem* header = [[[CollectionViewTextItem alloc]
|
| + initWithType:kItemTypeEnumZero] autorelease];
|
| + header.text =
|
| + base::SysUTF16ToNSString(history::GetRelativeDateLocalized(timestamp));
|
| + [_collectionViewModel insertSectionWithIdentifier:sectionIdentifier
|
| + atIndex:insertionIndex];
|
| + [_collectionViewModel setHeader:header
|
| + forSectionWithIdentifier:sectionIdentifier];
|
| + [self.delegate historyEntryInserter:self
|
| + didInsertSectionAtIndex:insertionIndex];
|
| + return sectionIdentifier;
|
| +}
|
| +
|
| +- (void)removeSection:(NSInteger)sectionIndex {
|
| + NSUInteger sectionIdentifier =
|
| + [_collectionViewModel sectionIdentifierForSection:sectionIndex];
|
| +
|
| + // Sections should not be removed unless there are no items in that section.
|
| + DCHECK(![[_collectionViewModel itemsInSectionWithIdentifier:sectionIdentifier]
|
| + count]);
|
| + [_collectionViewModel 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
|
|
|