blob: 00d82a5145bdd28acb26f2939af3dc145d230ac8 [file] [log] [blame]
// Copyright 2018 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/table_view/cells/table_view_url_item.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_url_cell_favicon_badge_view.h"
#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
#include "ios/chrome/browser/ui/util/ui_util.h"
#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
#import "ios/chrome/common/favicon/favicon_view.h"
#import "ios/chrome/common/ui_util/constraints_ui_util.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// The width and height of the favicon ImageView.
const CGFloat kFaviconWidth = 16;
// The width and height of the favicon container view.
const CGFloat kFaviconContainerWidth = 28;
// Default delimiter to use between the hostname and the supplemental URL text
// if text is specified but not the delimiter.
const char kDefaultSupplementalURLTextDelimiter[] = "•";
}
#pragma mark - TableViewURLCellFaviconBadgeView
#pragma mark - TableViewURLItem
@implementation TableViewURLItem
@synthesize title = _title;
@synthesize URL = _URL;
@synthesize supplementalURLText = _supplementalURLText;
@synthesize supplementalURLTextDelimiter = _supplementalURLTextDelimiter;
@synthesize badgeImage = _badgeImage;
@synthesize metadata = _metadata;
- (instancetype)initWithType:(NSInteger)type {
self = [super initWithType:type];
if (self) {
self.cellClass = [TableViewURLCell class];
}
return self;
}
- (void)configureCell:(UITableViewCell*)tableCell
withStyler:(ChromeTableViewStyler*)styler {
[super configureCell:tableCell withStyler:styler];
TableViewURLCell* cell =
base::mac::ObjCCastStrict<TableViewURLCell>(tableCell);
cell.titleLabel.text = [self titleLabelText];
cell.URLLabel.text = [self URLLabelText];
cell.faviconBadgeView.image = self.badgeImage;
cell.metadataLabel.text = self.metadata;
cell.cellUniqueIdentifier = self.uniqueIdentifier;
cell.accessibilityTraits |= UIAccessibilityTraitButton;
// If the background color specified by the styler is opaque, use it as the
// subview backround colors as well.
UIColor* backgroundColor = styler.tableViewBackgroundColor;
if (AreCGFloatsEqual(CGColorGetAlpha(backgroundColor.CGColor), 1.0)) {
cell.faviconContainerView.backgroundColor = styler.tableViewBackgroundColor;
cell.titleLabel.backgroundColor = styler.tableViewBackgroundColor;
cell.URLLabel.backgroundColor = styler.tableViewBackgroundColor;
cell.metadataLabel.backgroundColor = styler.tableViewBackgroundColor;
}
if (styler.cellTitleColor)
cell.titleLabel.textColor = styler.cellTitleColor;
[cell configureUILayout];
}
- (NSString*)uniqueIdentifier {
return base::SysUTF8ToNSString(self.URL.host());
}
#pragma mark Private
// Returns the text to use when configuring a TableViewURLCell's title label.
- (NSString*)titleLabelText {
if (self.title.length) {
return self.title;
} else if (base::SysUTF8ToNSString(self.URL.host()).length) {
return base::SysUTF8ToNSString(self.URL.host());
} else {
// Backup in case host returns nothing (e.g. about:blank).
return base::SysUTF8ToNSString(self.URL.spec());
}
}
// Returns the text to use when configuring a TableViewURLCell's URL label.
- (NSString*)URLLabelText {
// If there's no title text, the URL is used as the cell title. Add the
// supplemental text to the URL label below if it exists.
if (!self.title.length)
return self.supplementalURLText;
// Append the hostname with the supplemental text.
NSString* hostname = base::SysUTF8ToNSString(self.URL.host());
if (self.supplementalURLText.length) {
NSString* delimeter =
self.supplementalURLTextDelimiter.length
? self.supplementalURLTextDelimiter
: base::SysUTF8ToNSString(kDefaultSupplementalURLTextDelimiter);
return [NSString stringWithFormat:@"%@ %@ %@", hostname, delimeter,
self.supplementalURLText];
} else {
return hostname;
}
}
@end
#pragma mark - TableViewURLCell
@interface TableViewURLCell ()
// If the cell's accessibility label has not been manually set via
// |-setAccessibilityLabel:|, this property will be YES, and
// |-accessibilityLabel| will return a lazily created label based on the
// text values of the UILabel subviews.
@property(nonatomic, assign) BOOL shouldGenerateAccessibilityLabel;
// Horizontal StackView that holds url, title, and metadata labels.
@property(nonatomic, strong) UIStackView* horizontalStack;
@end
@implementation TableViewURLCell
@synthesize faviconView = _faviconView;
@synthesize faviconContainerView = _faviconContainerView;
@synthesize faviconBadgeView = _faviconBadgeView;
@synthesize horizontalStack = _horizontalStack;
@synthesize cellUniqueIdentifier = _cellUniqueIdentifier;
@synthesize shouldGenerateAccessibilityLabel =
_shouldGenerateAccessibilityLabel;
@synthesize metadataLabel = _metadataLabel;
@synthesize titleLabel = _titleLabel;
@synthesize URLLabel = _URLLabel;
- (instancetype)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString*)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
_faviconContainerView = [[UIImageView alloc]
initWithImage:[UIImage
imageNamed:@"table_view_cell_favicon_background"]];
_faviconView = [[FaviconView alloc] init];
_faviconView.contentMode = UIViewContentModeScaleAspectFit;
_faviconView.clipsToBounds = YES;
[_faviconContainerView addSubview:_faviconView];
_faviconBadgeView = [[TableViewURLCellFaviconBadgeView alloc] init];
_titleLabel = [[UILabel alloc] init];
_URLLabel = [[UILabel alloc] init];
_metadataLabel = [[UILabel alloc] init];
// Set font sizes using dynamic type.
_titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
_titleLabel.adjustsFontForContentSizeCategory = YES;
_URLLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
_URLLabel.adjustsFontForContentSizeCategory = YES;
_URLLabel.textColor =
UIColorFromRGB(kTableViewSecondaryLabelLightGrayTextColor);
_URLLabel.hidden = YES;
_metadataLabel.font =
[UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
_metadataLabel.textColor =
UIColorFromRGB(kTableViewSecondaryLabelLightGrayTextColor);
_metadataLabel.adjustsFontForContentSizeCategory = YES;
_metadataLabel.hidden = YES;
// Use stack views to layout the subviews except for the favicon.
UIStackView* verticalStack = [[UIStackView alloc]
initWithArrangedSubviews:@[ _titleLabel, _URLLabel ]];
verticalStack.axis = UILayoutConstraintAxisVertical;
[_metadataLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh
forAxis:UILayoutConstraintAxisHorizontal];
[_metadataLabel
setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh
forAxis:
UILayoutConstraintAxisHorizontal];
// Horizontal stack view holds vertical stack view and metadata label.
self.horizontalStack = [[UIStackView alloc]
initWithArrangedSubviews:@[ verticalStack, _metadataLabel ]];
self.horizontalStack.axis = UILayoutConstraintAxisHorizontal;
self.horizontalStack.spacing = kTableViewSubViewHorizontalSpacing;
self.horizontalStack.distribution = UIStackViewDistributionFill;
self.horizontalStack.alignment = UIStackViewAlignmentFill;
UIView* contentView = self.contentView;
_faviconView.translatesAutoresizingMaskIntoConstraints = NO;
_faviconContainerView.translatesAutoresizingMaskIntoConstraints = NO;
_faviconBadgeView.translatesAutoresizingMaskIntoConstraints = NO;
self.horizontalStack.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:_faviconContainerView];
[contentView addSubview:_faviconBadgeView];
[contentView addSubview:self.horizontalStack];
[NSLayoutConstraint activateConstraints:@[
// The favicon view is a fixed size, is pinned to the leading edge of the
// content view, and is centered vertically.
[_faviconView.heightAnchor constraintEqualToConstant:kFaviconWidth],
[_faviconView.widthAnchor constraintEqualToConstant:kFaviconWidth],
[_faviconView.centerYAnchor
constraintEqualToAnchor:_faviconContainerView.centerYAnchor],
[_faviconView.centerXAnchor
constraintEqualToAnchor:_faviconContainerView.centerXAnchor],
[_faviconContainerView.heightAnchor
constraintEqualToConstant:kFaviconContainerWidth],
[_faviconContainerView.widthAnchor
constraintEqualToConstant:kFaviconContainerWidth],
[_faviconContainerView.leadingAnchor
constraintEqualToAnchor:self.contentView.leadingAnchor
constant:kTableViewHorizontalSpacing],
[_faviconContainerView.centerYAnchor
constraintEqualToAnchor:self.contentView.centerYAnchor],
// The favicon badge view is aligned with the top-trailing corner of the
// favicon container.
[_faviconBadgeView.centerXAnchor
constraintEqualToAnchor:_faviconContainerView.trailingAnchor],
[_faviconBadgeView.centerYAnchor
constraintEqualToAnchor:_faviconContainerView.topAnchor],
// The stack view fills the remaining space, has an intrinsic height, and
// is centered vertically.
[self.horizontalStack.leadingAnchor
constraintEqualToAnchor:_faviconContainerView.trailingAnchor
constant:kTableViewSubViewHorizontalSpacing],
[self.horizontalStack.trailingAnchor
constraintEqualToAnchor:self.contentView.trailingAnchor
constant:-kTableViewHorizontalSpacing],
[self.horizontalStack.topAnchor
constraintEqualToAnchor:self.contentView.topAnchor
constant:kTableViewVerticalSpacing],
[self.horizontalStack.bottomAnchor
constraintEqualToAnchor:self.contentView.bottomAnchor
constant:-kTableViewVerticalSpacing]
]];
}
return self;
}
// Hide or show the metadata and URL labels depending on the presence of text.
// Align the horizontal stack properly depending on if the metadata label will
// be present or not.
- (void)configureUILayout {
if ([self.metadataLabel.text length]) {
self.metadataLabel.hidden = NO;
// Align metadataLabel to first line of content in vertical stack.
self.horizontalStack.alignment = UIStackViewAlignmentFirstBaseline;
} else {
self.metadataLabel.hidden = YES;
self.horizontalStack.alignment = UIStackViewAlignmentFill;
}
if ([self.URLLabel.text length]) {
self.URLLabel.hidden = NO;
} else {
self.URLLabel.hidden = YES;
}
}
- (void)prepareForReuse {
[super prepareForReuse];
[self.faviconView configureWithAttributes:nil];
self.faviconBadgeView.image = nil;
self.horizontalStack.alignment = UIStackViewAlignmentFill;
self.metadataLabel.hidden = YES;
self.URLLabel.hidden = YES;
}
- (void)setAccessibilityLabel:(NSString*)accessibilityLabel {
self.shouldGenerateAccessibilityLabel = !accessibilityLabel.length;
[super setAccessibilityLabel:accessibilityLabel];
}
- (NSString*)accessibilityLabel {
if (self.shouldGenerateAccessibilityLabel) {
NSString* accessibilityLabel = self.titleLabel.text;
if (self.URLLabel.text.length > 0) {
accessibilityLabel = [NSString
stringWithFormat:@"%@, %@", accessibilityLabel, self.URLLabel.text];
}
if (self.metadataLabel.text.length > 0) {
accessibilityLabel =
[NSString stringWithFormat:@"%@, %@", accessibilityLabel,
self.metadataLabel.text];
}
return accessibilityLabel;
} else {
return [super accessibilityLabel];
}
}
- (NSString*)accessibilityIdentifier {
return self.titleLabel.text;
}
- (BOOL)isAccessibilityElement {
return YES;
}
@end