blob: 2377926f6d694323eba76061ce58bab9e8b54b5e [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/autofill/manual_fill/manual_fill_password_cell.h"
#include "base/metrics/user_metrics.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/credential.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_cell_utils.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_content_delegate.h"
#import "ios/chrome/browser/ui/autofill/manual_fill/uicolor_manualfill.h"
#import "ios/chrome/browser/ui/list_model/list_model.h"
#import "ios/chrome/common/ui_util/constraints_ui_util.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface ManualFillCredentialItem ()
// The credential for this item.
@property(nonatomic, strong, readonly) ManualFillCredential* credential;
// The cell won't show a title (site name) label if it is connected to the
// previous password item.
@property(nonatomic, assign) BOOL isConnectedToPreviousItem;
// The separator line won't show if it is connected to the next password item.
@property(nonatomic, assign) BOOL isConnectedToNextItem;
// The delegate for this item.
@property(nonatomic, weak, readonly) id<ManualFillContentDelegate> delegate;
@end
@implementation ManualFillCredentialItem
@synthesize delegate = _delegate;
@synthesize credential = _credential;
- (instancetype)initWithCredential:(ManualFillCredential*)credential
isConnectedToPreviousItem:(BOOL)isConnectedToPreviousItem
isConnectedToNextItem:(BOOL)isConnectedToNextItem
delegate:(id<ManualFillContentDelegate>)delegate {
self = [super initWithType:kItemTypeEnumZero];
if (self) {
_credential = credential;
_isConnectedToPreviousItem = isConnectedToPreviousItem;
_isConnectedToNextItem = isConnectedToNextItem;
_delegate = delegate;
self.cellClass = [ManualFillPasswordCell class];
}
return self;
}
- (void)configureCell:(ManualFillPasswordCell*)cell
withStyler:(ChromeTableViewStyler*)styler {
[super configureCell:cell withStyler:styler];
[cell setUpWithCredential:self.credential
isConnectedToPreviousCell:self.isConnectedToPreviousItem
isConnectedToNextCell:self.isConnectedToNextItem
delegate:self.delegate];
}
@end
namespace {
// The multiplier for the base system spacing at the top margin for connected
// cells.
static const CGFloat TopSystemSpacingMultiplierForConnectedCell = 1.28;
// When no extra multiplier is required.
static const CGFloat NoMultiplier = 1.0;
} // namespace
@interface ManualFillPasswordCell ()
// The credential this cell is showing.
@property(nonatomic, strong) ManualFillCredential* manualFillCredential;
// The vertical constraints for all the lines.
@property(nonatomic, strong) NSArray<NSLayoutConstraint*>* verticalConstraints;
// The label with the site name and host.
@property(nonatomic, strong) UILabel* siteNameLabel;
// A button showing the username, or "No Username".
@property(nonatomic, strong) UIButton* usernameButton;
// A button showing "••••••••" to resemble a password.
@property(nonatomic, strong) UIButton* passwordButton;
// Separator line between cells, if needed.
@property(nonatomic, strong) UIView* grayLine;
// The delegate in charge of processing the user actions in this cell.
@property(nonatomic, weak) id<ManualFillContentDelegate> delegate;
@end
@implementation ManualFillPasswordCell
#pragma mark - Public
- (void)prepareForReuse {
[super prepareForReuse];
[NSLayoutConstraint deactivateConstraints:self.verticalConstraints];
self.verticalConstraints = @[];
self.siteNameLabel.text = @"";
[self.usernameButton setTitle:@"" forState:UIControlStateNormal];
self.usernameButton.enabled = YES;
[self.usernameButton setTitleColor:UIColor.cr_manualFillTintColor
forState:UIControlStateNormal];
[self.passwordButton setTitle:@"" forState:UIControlStateNormal];
self.passwordButton.accessibilityLabel = nil;
self.passwordButton.hidden = NO;
self.manualFillCredential = nil;
self.grayLine.hidden = NO;
}
- (void)setUpWithCredential:(ManualFillCredential*)credential
isConnectedToPreviousCell:(BOOL)isConnectedToPreviousCell
isConnectedToNextCell:(BOOL)isConnectedToNextCell
delegate:(id<ManualFillContentDelegate>)delegate {
if (self.contentView.subviews.count == 0) {
[self createViewHierarchy];
}
self.delegate = delegate;
self.manualFillCredential = credential;
NSMutableArray<UIView*>* verticalLeadViews = [[NSMutableArray alloc] init];
if (isConnectedToPreviousCell) {
self.siteNameLabel.hidden = YES;
} else {
NSMutableAttributedString* attributedString =
[[NSMutableAttributedString alloc]
initWithString:credential.siteName ? credential.siteName : @""
attributes:@{
NSForegroundColorAttributeName : UIColor.blackColor,
NSFontAttributeName :
[UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]
}];
if (credential.host && credential.host.length &&
![credential.host isEqualToString:credential.siteName]) {
NSString* hostString =
[NSString stringWithFormat:@" –– %@", credential.host];
NSDictionary* attributes = @{
NSForegroundColorAttributeName : UIColor.lightGrayColor,
NSFontAttributeName :
[UIFont preferredFontForTextStyle:UIFontTextStyleBody]
};
NSAttributedString* hostAttributedString =
[[NSAttributedString alloc] initWithString:hostString
attributes:attributes];
[attributedString appendAttributedString:hostAttributedString];
}
self.siteNameLabel.attributedText = attributedString;
[verticalLeadViews addObject:self.siteNameLabel];
self.siteNameLabel.hidden = NO;
}
if (credential.username.length) {
[self.usernameButton setTitle:credential.username
forState:UIControlStateNormal];
} else {
NSString* titleString =
l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NO_USERNAME);
[self.usernameButton setTitle:titleString forState:UIControlStateNormal];
[self.usernameButton setTitleColor:UIColor.lightGrayColor
forState:UIControlStateNormal];
self.usernameButton.enabled = NO;
}
[verticalLeadViews addObject:self.usernameButton];
if (credential.password.length) {
[self.passwordButton setTitle:@"••••••••" forState:UIControlStateNormal];
self.passwordButton.accessibilityLabel =
l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_HIDDEN_LABEL);
[verticalLeadViews addObject:self.passwordButton];
self.passwordButton.hidden = NO;
} else {
self.passwordButton.hidden = YES;
}
if (isConnectedToNextCell) {
self.grayLine.hidden = YES;
}
CGFloat topSystemSpacingMultiplier =
isConnectedToPreviousCell ? TopSystemSpacingMultiplierForConnectedCell
: TopSystemSpacingMultiplier;
CGFloat bottomSystemSpacingMultiplier =
isConnectedToNextCell ? NoMultiplier : BottomSystemSpacingMultiplier;
self.verticalConstraints =
VerticalConstraintsSpacingForViewsInContainerWithMultipliers(
verticalLeadViews, self.contentView, topSystemSpacingMultiplier,
MiddleSystemSpacingMultiplier, bottomSystemSpacingMultiplier);
}
#pragma mark - Private
// Creates and sets up the view hierarchy.
- (void)createViewHierarchy {
self.selectionStyle = UITableViewCellSelectionStyleNone;
UIView* guide = self.contentView;
self.grayLine = CreateGraySeparatorForContainer(guide);
self.siteNameLabel = CreateLabel();
self.siteNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.siteNameLabel.adjustsFontForContentSizeCategory = YES;
[self.contentView addSubview:self.siteNameLabel];
HorizontalConstraintsForViewsOnGuideWithShift(@[ self.siteNameLabel ], guide,
ButtonHorizontalMargin);
self.usernameButton = CreateButtonWithSelectorAndTarget(
@selector(userDidTapUsernameButton:), self);
[self.contentView addSubview:self.usernameButton];
HorizontalConstraintsForViewsOnGuideWithShift(@[ self.usernameButton ], guide,
0);
self.passwordButton = CreateButtonWithSelectorAndTarget(
@selector(userDidTapPasswordButton:), self);
[self.contentView addSubview:self.passwordButton];
HorizontalConstraintsForViewsOnGuideWithShift(@[ self.passwordButton ], guide,
0);
}
- (void)userDidTapUsernameButton:(UIButton*)button {
base::RecordAction(
base::UserMetricsAction("ManualFallback_Password_SelectUsername"));
[self.delegate userDidPickContent:self.manualFillCredential.username
passwordField:NO
requiresHTTPS:NO];
}
- (void)userDidTapPasswordButton:(UIButton*)button {
if (![self.delegate canUserInjectInPasswordField:YES requiresHTTPS:YES]) {
return;
}
base::RecordAction(
base::UserMetricsAction("ManualFallback_Password_SelectPassword"));
[self.delegate userDidPickContent:self.manualFillCredential.password
passwordField:YES
requiresHTTPS:YES];
}
@end