| Index: ios/chrome/browser/ui/history/history_entry_item.mm
|
| diff --git a/ios/chrome/browser/ui/history/history_entry_item.mm b/ios/chrome/browser/ui/history/history_entry_item.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..92a69519df1b727303a9fe8e23f19fc3a9a5e822
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/history/history_entry_item.mm
|
| @@ -0,0 +1,315 @@
|
| +// 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_item.h"
|
| +
|
| +#include "base/i18n/time_formatting.h"
|
| +#include "base/ios/weak_nsobject.h"
|
| +#import "base/mac/foundation_util.h"
|
| +#import "base/mac/objc_property_releaser.h"
|
| +#include "base/strings/sys_string_conversions.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "components/history/core/browser/url_row.h"
|
| +#include "components/strings/grit/components_strings.h"
|
| +#include "components/url_formatter/url_formatter.h"
|
| +#include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
|
| +#import "ios/chrome/browser/ui/history/favicon_view.h"
|
| +#import "ios/chrome/browser/ui/history/favicon_view_provider.h"
|
| +#import "ios/chrome/browser/ui/history/history_entry.h"
|
| +#include "ios/chrome/browser/ui/rtl_geometry.h"
|
| +#import "ios/chrome/browser/ui/uikit_ui_util.h"
|
| +#include "ios/chrome/grit/ios_strings.h"
|
| +#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
|
| +#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +
|
| +namespace {
|
| +// Size at which the favicon will be displayed.
|
| +const CGFloat kFaviconSize = 24.0;
|
| +// Minimum size at which to fetch favicons.
|
| +const CGFloat kMinFaviconSize = 16.0;
|
| +// Horizontal spacing between edge of the cell and the cell content.
|
| +const CGFloat kMargin = 16.0;
|
| +// Horizontal spacing between the leading edge of the cell and the text.
|
| +const CGFloat kHeaderMargin = 56.0;
|
| +
|
| +NSString* FormattedTitle(const base::string16& title, const GURL& url) {
|
| + // Use url as title if no title.
|
| + bool using_url_as_the_title = false;
|
| + base::string16 formatted_title(title);
|
| + if (title.empty()) {
|
| + using_url_as_the_title = true;
|
| + formatted_title = url_formatter::FormatUrl(url);
|
| + }
|
| + // Since the title can contain BiDi text, mark the text as either RTL or LTR,
|
| + // depending on the characters in the string. If the URL is used as the title,
|
| + // mark the title as LTR since URLs are always treated as left to right
|
| + // strings.
|
| + if (base::i18n::IsRTL()) {
|
| + if (using_url_as_the_title)
|
| + base::i18n::WrapStringWithLTRFormatting(&formatted_title);
|
| + else
|
| + base::i18n::AdjustStringForLocaleDirection(&formatted_title);
|
| + }
|
| + return base::SysUTF16ToNSString(formatted_title);
|
| +}
|
| +} // namespace
|
| +
|
| +#pragma mark - HistoryEntryItem
|
| +
|
| +@interface HistoryEntryItem ()<FaviconViewProviderDelegate> {
|
| + // Property releaser for HistoryEntryItem.
|
| + base::mac::ObjCPropertyReleaser _propertyReleaser_HistoryEntryItem;
|
| + // Delegate for HistoryEntryItem.
|
| + base::WeakNSProtocol<id<HistoryEntryItemDelegate>> _delegate;
|
| +}
|
| +
|
| +// FaviconViewProvider to fetch the favicon and format the favicon view.
|
| +@property(nonatomic, retain) FaviconViewProvider* faviconViewProvider;
|
| +
|
| +// Custom accessibility actions for the history entry view.
|
| +- (NSArray*)accessibilityActions;
|
| +// Custom accessibility action to delete the history entry.
|
| +- (BOOL)deleteHistoryEntry;
|
| +// Custom accessibility action to open the history entry's URL in a new tab.
|
| +- (BOOL)openInNewTab;
|
| +// Custom accessibility action to open the history entry's URL in a new
|
| +// incognito tab.
|
| +- (BOOL)openInNewIncognitoTab;
|
| +// Custom accessibility action to copy the history entry's URL to the clipboard.
|
| +- (BOOL)copyURL;
|
| +@end
|
| +
|
| +@implementation HistoryEntryItem
|
| +
|
| +@synthesize faviconViewProvider = _faviconViewProvider;
|
| +@synthesize text = _text;
|
| +@synthesize detailText = _detailText;
|
| +@synthesize timeText = _timeText;
|
| +@synthesize URL = _URL;
|
| +@synthesize timestamp = _timestamp;
|
| +
|
| +- (instancetype)initWithType:(NSInteger)type
|
| + historyEntry:(const history::HistoryEntry&)entry
|
| + browserState:(ios::ChromeBrowserState*)browserState
|
| + delegate:(id<HistoryEntryItemDelegate>)delegate {
|
| + self = [super initWithType:type];
|
| + if (self) {
|
| + _propertyReleaser_HistoryEntryItem.Init(self, [HistoryEntryItem class]);
|
| + self.cellClass = [HistoryEntryCell class];
|
| + favicon::LargeIconService* largeIconService =
|
| + IOSChromeLargeIconServiceFactory::GetForBrowserState(browserState);
|
| + _faviconViewProvider =
|
| + [[FaviconViewProvider alloc] initWithURL:entry.url
|
| + faviconSize:kFaviconSize
|
| + minFaviconSize:kMinFaviconSize
|
| + largeIconService:largeIconService
|
| + delegate:self];
|
| + _text = [FormattedTitle(entry.title, entry.url) copy];
|
| + _detailText = [base::SysUTF8ToNSString(entry.url.spec()) copy];
|
| + _timeText =
|
| + [base::SysUTF16ToNSString(base::TimeFormatTimeOfDay(entry.time)) copy];
|
| + _URL = GURL(entry.url);
|
| + _timestamp = entry.time;
|
| + _delegate.reset(delegate);
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (instancetype)initWithType:(NSInteger)type {
|
| + NOTREACHED();
|
| + return nil;
|
| +}
|
| +
|
| +- (BOOL)isEqualToHistoryEntryItem:(HistoryEntryItem*)item {
|
| + return item && item.URL == _URL && item.timestamp == _timestamp;
|
| +}
|
| +
|
| +- (BOOL)isEqual:(id)object {
|
| + if (self == object)
|
| + return YES;
|
| +
|
| + if (![object isMemberOfClass:[HistoryEntryItem class]])
|
| + return NO;
|
| +
|
| + return [self isEqualToHistoryEntryItem:object];
|
| +}
|
| +
|
| +- (NSUInteger)hash {
|
| + return [base::SysUTF8ToNSString(self.URL.spec()) hash] ^
|
| + self.timestamp.ToInternalValue();
|
| +}
|
| +
|
| +- (NSArray*)accessibilityActions {
|
| + UIAccessibilityCustomAction* deleteAction =
|
| + [[[UIAccessibilityCustomAction alloc]
|
| + initWithName:l10n_util::GetNSString(
|
| + IDS_HISTORY_ENTRY_ACCESSIBILITY_DELETE)
|
| + target:self
|
| + selector:@selector(deleteHistoryEntry)] autorelease];
|
| + UIAccessibilityCustomAction* openInNewTabAction =
|
| + [[[UIAccessibilityCustomAction alloc]
|
| + initWithName:l10n_util::GetNSString(
|
| + IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)
|
| + target:self
|
| + selector:@selector(openInNewTab)] autorelease];
|
| + UIAccessibilityCustomAction* openInNewIncognitoTabAction =
|
| + [[[UIAccessibilityCustomAction alloc]
|
| + initWithName:l10n_util::GetNSString(
|
| + IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)
|
| + target:self
|
| + selector:@selector(openInNewIncognitoTab)] autorelease];
|
| + UIAccessibilityCustomAction* copyURLAction =
|
| + [[[UIAccessibilityCustomAction alloc]
|
| + initWithName:l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_COPY)
|
| + target:self
|
| + selector:@selector(copyURL)] autorelease];
|
| + return @[
|
| + deleteAction, openInNewTabAction, openInNewIncognitoTabAction, copyURLAction
|
| + ];
|
| +}
|
| +
|
| +- (BOOL)deleteHistoryEntry {
|
| + [_delegate historyEntryItemDidRequestDelete:self];
|
| + return YES;
|
| +}
|
| +
|
| +- (BOOL)openInNewTab {
|
| + [_delegate historyEntryItemDidRequestOpenInNewTab:self];
|
| + return YES;
|
| +}
|
| +
|
| +- (BOOL)openInNewIncognitoTab {
|
| + [_delegate historyEntryItemDidRequestOpenInNewIncognitoTab:self];
|
| + return YES;
|
| +}
|
| +
|
| +- (BOOL)copyURL {
|
| + [_delegate historyEntryItemDidRequestCopy:self];
|
| + return YES;
|
| +}
|
| +
|
| +- (void)configureCell:(HistoryEntryCell*)cell {
|
| + [super configureCell:cell];
|
| +
|
| + // Set favicon view and constraints.
|
| + FaviconView* faviconView = self.faviconViewProvider.faviconView;
|
| + [cell.faviconViewContainer addSubview:faviconView];
|
| + [faviconView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
| + AddSameSizeConstraint(faviconView, cell.faviconViewContainer);
|
| + AddSameCenterConstraints(faviconView, cell.faviconViewContainer);
|
| +
|
| + cell.textLabel.text = self.text;
|
| + cell.detailTextLabel.text = self.detailText;
|
| + cell.timeLabel.text = self.timeText;
|
| + cell.isAccessibilityElement = YES;
|
| + cell.accessibilityCustomActions = self.accessibilityActions;
|
| + cell.accessibilityLabel =
|
| + l10n_util::GetNSStringF(IDS_HISTORY_ENTRY_ACCESSIBILITY_LABEL,
|
| + base::SysNSStringToUTF16(self.text),
|
| + base::SysNSStringToUTF16(self.detailText),
|
| + base::SysNSStringToUTF16(self.timeText));
|
| +}
|
| +
|
| +- (void)faviconViewProviderFaviconDidLoad:(FaviconViewProvider*)provider {
|
| + [_delegate historyEntryItemShouldUpdateView:self];
|
| +}
|
| +
|
| +@end
|
| +
|
| +#pragma mark - HistoryEntryCell
|
| +
|
| +@interface HistoryEntryCell () {
|
| + // Property releaser for HistoryEntryCell.
|
| + base::mac::ObjCPropertyReleaser _propertyReleaser_HistoryEntryCell;
|
| +}
|
| +
|
| +// Redeclare as readwrite to allow property releaser to handle these properties.
|
| +@property(nonatomic, readwrite, retain) UILabel* textLabel;
|
| +@property(nonatomic, readwrite, retain) UILabel* detailTextLabel;
|
| +@property(nonatomic, readwrite, retain) UILabel* timeLabel;
|
| +@end
|
| +
|
| +@implementation HistoryEntryCell
|
| +
|
| +@synthesize faviconViewContainer = _faviconViewContainer;
|
| +@synthesize textLabel = _textLabel;
|
| +@synthesize detailTextLabel = _detailTextLabel;
|
| +@synthesize timeLabel = _timeLabel;
|
| +
|
| +- (id)initWithFrame:(CGRect)frame {
|
| + self = [super initWithFrame:frame];
|
| + if (self) {
|
| + _propertyReleaser_HistoryEntryCell.Init(self, [HistoryEntryCell class]);
|
| +
|
| + _faviconViewContainer = [[UIView alloc] initWithFrame:CGRectZero];
|
| +
|
| + _textLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
| + [_textLabel
|
| + setFont:[[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:16]];
|
| + [_textLabel setTextColor:[[MDCPalette greyPalette] tint900]];
|
| +
|
| + _detailTextLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
| + [_detailTextLabel
|
| + setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14]];
|
| + [_detailTextLabel setTextColor:[[MDCPalette greyPalette] tint600]];
|
| +
|
| + _timeLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
| + [_timeLabel
|
| + setFont:[[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14]];
|
| + [_timeLabel setTextColor:[[MDCPalette greyPalette] tint600]];
|
| + _timeLabel.textAlignment =
|
| + UseRTLLayout() ? NSTextAlignmentLeft : NSTextAlignmentRight;
|
| +
|
| + UIView* contentView = self.contentView;
|
| + [contentView addSubview:_faviconViewContainer];
|
| + [contentView addSubview:_textLabel];
|
| + [contentView addSubview:_detailTextLabel];
|
| + [contentView addSubview:_timeLabel];
|
| +
|
| + [_faviconViewContainer setTranslatesAutoresizingMaskIntoConstraints:NO];
|
| + [_textLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
|
| + [_detailTextLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
|
| + [_timeLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
|
| +
|
| + [_faviconViewContainer.widthAnchor constraintEqualToConstant:kFaviconSize];
|
| +
|
| + NSDictionary* views = @{
|
| + @"title" : _textLabel,
|
| + @"URL" : _detailTextLabel,
|
| + @"time" : _timeLabel,
|
| + @"favicon" : _faviconViewContainer,
|
| + };
|
| + NSDictionary* metrics = @{
|
| + @"margin" : @(kMargin),
|
| + @"spacing" : @(kHeaderMargin - (kMargin + kFaviconSize)),
|
| + };
|
| + NSArray* constraints = @[
|
| + @"H:|-margin-[favicon]-spacing-[title]-[time]-margin-|",
|
| + @"H:|-margin-[favicon]-spacing-[URL]-margin-|",
|
| + @"V:|-margin-[title][URL]-margin-|",
|
| + ];
|
| + ApplyVisualConstraintsWithMetrics(constraints, views, metrics);
|
| + AddSameCenterYConstraint(_textLabel, _timeLabel);
|
| + AddSameCenterYConstraint(_faviconViewContainer, _textLabel);
|
| +
|
| + [_timeLabel
|
| + setContentCompressionResistancePriority:UILayoutPriorityRequired
|
| + forAxis:
|
| + UILayoutConstraintAxisHorizontal];
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (void)prepareForReuse {
|
| + [super prepareForReuse];
|
| + _textLabel.text = nil;
|
| + _detailTextLabel.text = nil;
|
| + _timeLabel.text = nil;
|
| + for (UIView* subview in _faviconViewContainer.subviews) {
|
| + [subview removeFromSuperview];
|
| + }
|
| +}
|
| +
|
| +@end
|
|
|