Commit b8f08357 authored by David Jean's avatar David Jean Committed by Commit Bot

[ios] combine password cells for manual fallback

Also gray out "No Username" label.

Bug: 905663
Change-Id: Iabbbf1ce7d20f62e72896ad08b5a239d0fbd14dc
Reviewed-on: https://chromium-review.googlesource.com/c/1350616
Commit-Queue: David Jean <djean@chromium.org>
Reviewed-by: default avatarJavier Ernesto Flores Robles <javierrobles@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611091}
parent d70ca123
......@@ -7,17 +7,48 @@
#import <UIKit/UIKit.h>
namespace {
// The multiplier for the base system spacing at the top margin.
static const CGFloat TopSystemSpacingMultiplier = 1.58;
// The multiplier for the base system spacing between elements (vertical).
static const CGFloat MiddleSystemSpacingMultiplier = 1.83;
// The multiplier for the base system spacing at the bottom margin.
static const CGFloat BottomSystemSpacingMultiplier = 2.26;
// Top and bottom margins for buttons.
static const CGFloat ButtonVerticalMargin = 12;
// Left and right margins of the cell content and buttons.
static const CGFloat ButtonHorizontalMargin = 16;
} // namespace
// Creates a blank button in fallback style, for the given |action| and
// |target|.
UIButton* CreateButtonWithSelectorAndTarget(SEL action, id target);
// Sets vertical constraints on firstBaselineAnchor for the button or label rows
// in |views| inside |container| starting at its topAnchor. Returns the applied
// constrainst to allow caller to deactivate them later.
// constrainst to allow caller to deactivate them later. Defaults multipliers
// are applied.
NSArray<NSLayoutConstraint*>* VerticalConstraintsSpacingForViewsInContainer(
NSArray<UIView*>* views,
UIView* container);
// Sets vertical constraints on firstBaselineAnchor for the button or label rows
// in |views| inside |container| starting at its topAnchor. Returns the applied
// constrainst to allow caller to deactivate them later.
NSArray<NSLayoutConstraint*>*
VerticalConstraintsSpacingForViewsInContainerWithMultipliers(
NSArray<UIView*>* views,
UIView* container,
CGFloat topSystemSpacingMultiplier,
CGFloat middleSystemSpacingMultiplier,
CGFloat BottomSystemSpacingMultiplier);
// Sets constraints for the given |views|, so as to lay them out horizontally,
// parallel to the given |guide| view, and applying the given constant |shift|
// to the whole row. Returns the applied constraints to allow caller to
......
......@@ -16,25 +16,6 @@
#error "This file requires ARC support."
#endif
namespace {
// The multiplier for the base system spacing at the top margin.
static const CGFloat TopSystemSpacingMultiplier = 1.58;
// The multiplier for the base system spacing between elements (vertical).
static const CGFloat MiddleSystemSpacingMultiplier = 1.83;
// The multiplier for the base system spacing at the bottom margin.
static const CGFloat BottomSystemSpacingMultiplier = 2.26;
// Top and bottom margins for buttons.
static const CGFloat ButtonVerticalMargin = 12;
// Left and right margins of the cell content and buttons.
static const CGFloat ButtonHorizontalMargin = 16;
} // namespace
UIButton* CreateButtonWithSelectorAndTarget(SEL action, id target) {
UIButton* button = [ManualFillCellButton buttonWithType:UIButtonTypeCustom];
[button setTitleColor:UIColor.cr_manualFillTintColor
......@@ -57,21 +38,33 @@ UIButton* CreateButtonWithSelectorAndTarget(SEL action, id target) {
NSArray<NSLayoutConstraint*>* VerticalConstraintsSpacingForViewsInContainer(
NSArray<UIView*>* views,
UIView* container) {
return VerticalConstraintsSpacingForViewsInContainerWithMultipliers(
views, container, TopSystemSpacingMultiplier,
MiddleSystemSpacingMultiplier, BottomSystemSpacingMultiplier);
}
NSArray<NSLayoutConstraint*>*
VerticalConstraintsSpacingForViewsInContainerWithMultipliers(
NSArray<UIView*>* views,
UIView* container,
CGFloat topSystemSpacingMultiplier,
CGFloat middleSystemSpacingMultiplier,
CGFloat bottomSystemSpacingMultiplier) {
NSMutableArray* verticalConstraints = [[NSMutableArray alloc] init];
// Multipliers of these constraints are calculated based on a 24 base
// system spacing.
NSLayoutYAxisAnchor* previousAnchor = container.topAnchor;
CGFloat multiplier = TopSystemSpacingMultiplier;
CGFloat multiplier = topSystemSpacingMultiplier;
for (UIView* view in views) {
[verticalConstraints
addObject:[view.firstBaselineAnchor
constraintEqualToSystemSpacingBelowAnchor:previousAnchor
multiplier:multiplier]];
multiplier = MiddleSystemSpacingMultiplier;
multiplier = middleSystemSpacingMultiplier;
previousAnchor = view.lastBaselineAnchor;
}
multiplier = BottomSystemSpacingMultiplier;
multiplier = bottomSystemSpacingMultiplier;
[verticalConstraints
addObject:[container.bottomAnchor
constraintEqualToSystemSpacingBelowAnchor:previousAnchor
......
......@@ -16,6 +16,8 @@
@interface ManualFillCredentialItem : TableViewItem
- (instancetype)initWithCredential:(ManualFillCredential*)credential
isConnectedToPreviousItem:(BOOL)isConnectedToPreviousItem
isConnectedToNextItem:(BOOL)isConnectedToNextItem
delegate:(id<ManualFillContentDelegate>)delegate
NS_DESIGNATED_INITIALIZER;
......@@ -30,6 +32,8 @@
// Updates the cell with the |credential|. If the user iteracts with it, the
// |delegate| will be notified.
- (void)setUpWithCredential:(ManualFillCredential*)credential
isConnectedToPreviousCell:(BOOL)isConnectedToPreviousCell
isConnectedToNextCell:(BOOL)isConnectedToNextCell
delegate:(id<ManualFillContentDelegate>)delegate;
@end
......
......@@ -19,10 +19,20 @@
#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
......@@ -30,10 +40,14 @@
@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];
}
......@@ -43,37 +57,55 @@
- (void)configureCell:(ManualFillPasswordCell*)cell
withStyler:(ChromeTableViewStyler*)styler {
[super configureCell:cell withStyler:styler];
[cell setUpWithCredential:self.credential delegate:self.delegate];
[cell setUpWithCredential:self.credential
isConnectedToPreviousCell:self.isConnectedToPreviousItem
isConnectedToNextCell:self.isConnectedToNextItem
delegate:self.delegate];
}
@end
namespace {
// Left and right margins of the cell content.
static const CGFloat SideMargins = 16;
// 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
@synthesize manualFillCredential = _manualFillCredential;
@synthesize siteNameLabel = _siteNameLabel;
@synthesize usernameButton = _usernameButton;
@synthesize passwordButton = _passwordButton;
@synthesize delegate = _delegate;
#pragma mark - Public
- (void)prepareForReuse {
......@@ -86,12 +118,20 @@ static const CGFloat SideMargins = 16;
}
- (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 : @""
......@@ -114,8 +154,11 @@ static const CGFloat SideMargins = 16;
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];
......@@ -123,12 +166,37 @@ static const CGFloat SideMargins = 16;
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];
[verticalLeadViews addObject:self.passwordButton];
self.passwordButton.hidden = NO;
} else {
self.passwordButton.hidden = YES;
}
if (!isConnectedToNextCell) {
[verticalLeadViews addObject:self.grayLine];
self.grayLine.hidden = NO;
} else {
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
......@@ -137,10 +205,10 @@ static const CGFloat SideMargins = 16;
- (void)createViewHierarchy {
self.selectionStyle = UITableViewCellSelectionStyleNone;
UIView* grayLine = [[UIView alloc] init];
grayLine.backgroundColor = UIColor.cr_manualFillGrayLineColor;
grayLine.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:grayLine];
self.grayLine = [[UIView alloc] init];
self.grayLine.backgroundColor = UIColor.cr_manualFillGrayLineColor;
self.grayLine.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:self.grayLine];
UIView* guide = self.contentView;
......@@ -163,22 +231,18 @@ static const CGFloat SideMargins = 16;
HorizontalConstraintsForViewsOnGuideWithShift(@[ self.passwordButton ], guide,
0);
VerticalConstraintsSpacingForViewsInContainer(
@[ self.siteNameLabel, self.usernameButton, self.passwordButton ],
self.contentView);
id<LayoutGuideProvider> safeArea = self.contentView.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
// Common vertical constraints.
[grayLine.bottomAnchor
[self.grayLine.bottomAnchor
constraintEqualToAnchor:self.contentView.bottomAnchor],
[grayLine.heightAnchor constraintEqualToConstant:1],
[self.grayLine.heightAnchor constraintEqualToConstant:1],
// Horizontal constraints.
[grayLine.leadingAnchor constraintEqualToAnchor:safeArea.leadingAnchor
[self.grayLine.leadingAnchor constraintEqualToAnchor:safeArea.leadingAnchor
constant:SideMargins],
[safeArea.trailingAnchor constraintEqualToAnchor:grayLine.trailingAnchor
[safeArea.trailingAnchor
constraintEqualToAnchor:self.grayLine.trailingAnchor
constant:SideMargins],
]];
}
......
......@@ -39,6 +39,19 @@ NSString* const OtherPasswordsAccessibilityIdentifier =
} // namespace manual_fill
// Checks if two credential are connected. They are considered connected if they
// have same host.
BOOL AreCredentialsAtIndexesConnected(
NSArray<ManualFillCredential*>* credentials,
int firstIndex,
int secondIndex) {
if (firstIndex < 0 || firstIndex >= (int)credentials.count ||
secondIndex < 0 || secondIndex >= (int)credentials.count)
return NO;
return [credentials[firstIndex].host
isEqualToString:credentials[secondIndex].host];
}
@interface ManualFillPasswordMediator ()<ManualFillContentDelegate,
PasswordFetcherDelegate>
// The |WebStateList| containing the active web state. Used to filter the list
......@@ -167,8 +180,16 @@ NSString* const OtherPasswordsAccessibilityIdentifier =
(NSArray<ManualFillCredential*>*)credentials {
NSMutableArray* items =
[[NSMutableArray alloc] initWithCapacity:credentials.count];
for (ManualFillCredential* credential in credentials) {
auto item = [[ManualFillCredentialItem alloc] initWithCredential:credential
for (int i = 0; i < (int)credentials.count; i++) {
BOOL isConnectedToPreviousItem =
AreCredentialsAtIndexesConnected(credentials, i, i - 1);
BOOL isConnectedToNextItem =
AreCredentialsAtIndexesConnected(credentials, i, i + 1);
ManualFillCredential* credential = credentials[i];
auto item = [[ManualFillCredentialItem alloc]
initWithCredential:credential
isConnectedToPreviousItem:isConnectedToPreviousItem
isConnectedToNextItem:isConnectedToNextItem
delegate:self];
[items addObject:item];
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment