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 @@ ...@@ -7,17 +7,48 @@
#import <UIKit/UIKit.h> #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 // Creates a blank button in fallback style, for the given |action| and
// |target|. // |target|.
UIButton* CreateButtonWithSelectorAndTarget(SEL action, id target); UIButton* CreateButtonWithSelectorAndTarget(SEL action, id target);
// Sets vertical constraints on firstBaselineAnchor for the button or label rows // Sets vertical constraints on firstBaselineAnchor for the button or label rows
// in |views| inside |container| starting at its topAnchor. Returns the applied // 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<NSLayoutConstraint*>* VerticalConstraintsSpacingForViewsInContainer(
NSArray<UIView*>* views, NSArray<UIView*>* views,
UIView* container); 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, // 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| // parallel to the given |guide| view, and applying the given constant |shift|
// to the whole row. Returns the applied constraints to allow caller to // to the whole row. Returns the applied constraints to allow caller to
......
...@@ -16,25 +16,6 @@ ...@@ -16,25 +16,6 @@
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #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* CreateButtonWithSelectorAndTarget(SEL action, id target) {
UIButton* button = [ManualFillCellButton buttonWithType:UIButtonTypeCustom]; UIButton* button = [ManualFillCellButton buttonWithType:UIButtonTypeCustom];
[button setTitleColor:UIColor.cr_manualFillTintColor [button setTitleColor:UIColor.cr_manualFillTintColor
...@@ -57,21 +38,33 @@ UIButton* CreateButtonWithSelectorAndTarget(SEL action, id target) { ...@@ -57,21 +38,33 @@ UIButton* CreateButtonWithSelectorAndTarget(SEL action, id target) {
NSArray<NSLayoutConstraint*>* VerticalConstraintsSpacingForViewsInContainer( NSArray<NSLayoutConstraint*>* VerticalConstraintsSpacingForViewsInContainer(
NSArray<UIView*>* views, NSArray<UIView*>* views,
UIView* container) { 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]; NSMutableArray* verticalConstraints = [[NSMutableArray alloc] init];
// Multipliers of these constraints are calculated based on a 24 base // Multipliers of these constraints are calculated based on a 24 base
// system spacing. // system spacing.
NSLayoutYAxisAnchor* previousAnchor = container.topAnchor; NSLayoutYAxisAnchor* previousAnchor = container.topAnchor;
CGFloat multiplier = TopSystemSpacingMultiplier; CGFloat multiplier = topSystemSpacingMultiplier;
for (UIView* view in views) { for (UIView* view in views) {
[verticalConstraints [verticalConstraints
addObject:[view.firstBaselineAnchor addObject:[view.firstBaselineAnchor
constraintEqualToSystemSpacingBelowAnchor:previousAnchor constraintEqualToSystemSpacingBelowAnchor:previousAnchor
multiplier:multiplier]]; multiplier:multiplier]];
multiplier = MiddleSystemSpacingMultiplier; multiplier = middleSystemSpacingMultiplier;
previousAnchor = view.lastBaselineAnchor; previousAnchor = view.lastBaselineAnchor;
} }
multiplier = BottomSystemSpacingMultiplier; multiplier = bottomSystemSpacingMultiplier;
[verticalConstraints [verticalConstraints
addObject:[container.bottomAnchor addObject:[container.bottomAnchor
constraintEqualToSystemSpacingBelowAnchor:previousAnchor constraintEqualToSystemSpacingBelowAnchor:previousAnchor
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
@interface ManualFillCredentialItem : TableViewItem @interface ManualFillCredentialItem : TableViewItem
- (instancetype)initWithCredential:(ManualFillCredential*)credential - (instancetype)initWithCredential:(ManualFillCredential*)credential
isConnectedToPreviousItem:(BOOL)isConnectedToPreviousItem
isConnectedToNextItem:(BOOL)isConnectedToNextItem
delegate:(id<ManualFillContentDelegate>)delegate delegate:(id<ManualFillContentDelegate>)delegate
NS_DESIGNATED_INITIALIZER; NS_DESIGNATED_INITIALIZER;
...@@ -30,6 +32,8 @@ ...@@ -30,6 +32,8 @@
// Updates the cell with the |credential|. If the user iteracts with it, the // Updates the cell with the |credential|. If the user iteracts with it, the
// |delegate| will be notified. // |delegate| will be notified.
- (void)setUpWithCredential:(ManualFillCredential*)credential - (void)setUpWithCredential:(ManualFillCredential*)credential
isConnectedToPreviousCell:(BOOL)isConnectedToPreviousCell
isConnectedToNextCell:(BOOL)isConnectedToNextCell
delegate:(id<ManualFillContentDelegate>)delegate; delegate:(id<ManualFillContentDelegate>)delegate;
@end @end
......
...@@ -19,10 +19,20 @@ ...@@ -19,10 +19,20 @@
#endif #endif
@interface ManualFillCredentialItem () @interface ManualFillCredentialItem ()
// The credential for this item. // The credential for this item.
@property(nonatomic, strong, readonly) ManualFillCredential* credential; @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. // The delegate for this item.
@property(nonatomic, weak, readonly) id<ManualFillContentDelegate> delegate; @property(nonatomic, weak, readonly) id<ManualFillContentDelegate> delegate;
@end @end
@implementation ManualFillCredentialItem @implementation ManualFillCredentialItem
...@@ -30,10 +40,14 @@ ...@@ -30,10 +40,14 @@
@synthesize credential = _credential; @synthesize credential = _credential;
- (instancetype)initWithCredential:(ManualFillCredential*)credential - (instancetype)initWithCredential:(ManualFillCredential*)credential
isConnectedToPreviousItem:(BOOL)isConnectedToPreviousItem
isConnectedToNextItem:(BOOL)isConnectedToNextItem
delegate:(id<ManualFillContentDelegate>)delegate { delegate:(id<ManualFillContentDelegate>)delegate {
self = [super initWithType:kItemTypeEnumZero]; self = [super initWithType:kItemTypeEnumZero];
if (self) { if (self) {
_credential = credential; _credential = credential;
_isConnectedToPreviousItem = isConnectedToPreviousItem;
_isConnectedToNextItem = isConnectedToNextItem;
_delegate = delegate; _delegate = delegate;
self.cellClass = [ManualFillPasswordCell class]; self.cellClass = [ManualFillPasswordCell class];
} }
...@@ -43,37 +57,55 @@ ...@@ -43,37 +57,55 @@
- (void)configureCell:(ManualFillPasswordCell*)cell - (void)configureCell:(ManualFillPasswordCell*)cell
withStyler:(ChromeTableViewStyler*)styler { withStyler:(ChromeTableViewStyler*)styler {
[super configureCell:cell withStyler: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 @end
namespace { namespace {
// Left and right margins of the cell content. // Left and right margins of the cell content.
static const CGFloat SideMargins = 16; 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 } // namespace
@interface ManualFillPasswordCell () @interface ManualFillPasswordCell ()
// The credential this cell is showing. // The credential this cell is showing.
@property(nonatomic, strong) ManualFillCredential* manualFillCredential; @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. // The label with the site name and host.
@property(nonatomic, strong) UILabel* siteNameLabel; @property(nonatomic, strong) UILabel* siteNameLabel;
// A button showing the username, or "No Username". // A button showing the username, or "No Username".
@property(nonatomic, strong) UIButton* usernameButton; @property(nonatomic, strong) UIButton* usernameButton;
// A button showing "••••••••" to resemble a password. // A button showing "••••••••" to resemble a password.
@property(nonatomic, strong) UIButton* passwordButton; @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. // The delegate in charge of processing the user actions in this cell.
@property(nonatomic, weak) id<ManualFillContentDelegate> delegate; @property(nonatomic, weak) id<ManualFillContentDelegate> delegate;
@end @end
@implementation ManualFillPasswordCell @implementation ManualFillPasswordCell
@synthesize manualFillCredential = _manualFillCredential;
@synthesize siteNameLabel = _siteNameLabel;
@synthesize usernameButton = _usernameButton;
@synthesize passwordButton = _passwordButton;
@synthesize delegate = _delegate;
#pragma mark - Public #pragma mark - Public
- (void)prepareForReuse { - (void)prepareForReuse {
...@@ -86,12 +118,20 @@ static const CGFloat SideMargins = 16; ...@@ -86,12 +118,20 @@ static const CGFloat SideMargins = 16;
} }
- (void)setUpWithCredential:(ManualFillCredential*)credential - (void)setUpWithCredential:(ManualFillCredential*)credential
isConnectedToPreviousCell:(BOOL)isConnectedToPreviousCell
isConnectedToNextCell:(BOOL)isConnectedToNextCell
delegate:(id<ManualFillContentDelegate>)delegate { delegate:(id<ManualFillContentDelegate>)delegate {
if (self.contentView.subviews.count == 0) { if (self.contentView.subviews.count == 0) {
[self createViewHierarchy]; [self createViewHierarchy];
} }
self.delegate = delegate; self.delegate = delegate;
self.manualFillCredential = credential; self.manualFillCredential = credential;
NSMutableArray<UIView*>* verticalLeadViews = [[NSMutableArray alloc] init];
if (isConnectedToPreviousCell) {
self.siteNameLabel.hidden = YES;
} else {
NSMutableAttributedString* attributedString = NSMutableAttributedString* attributedString =
[[NSMutableAttributedString alloc] [[NSMutableAttributedString alloc]
initWithString:credential.siteName ? credential.siteName : @"" initWithString:credential.siteName ? credential.siteName : @""
...@@ -114,8 +154,11 @@ static const CGFloat SideMargins = 16; ...@@ -114,8 +154,11 @@ static const CGFloat SideMargins = 16;
attributes:attributes]; attributes:attributes];
[attributedString appendAttributedString:hostAttributedString]; [attributedString appendAttributedString:hostAttributedString];
} }
self.siteNameLabel.attributedText = attributedString; self.siteNameLabel.attributedText = attributedString;
[verticalLeadViews addObject:self.siteNameLabel];
self.siteNameLabel.hidden = NO;
}
if (credential.username.length) { if (credential.username.length) {
[self.usernameButton setTitle:credential.username [self.usernameButton setTitle:credential.username
forState:UIControlStateNormal]; forState:UIControlStateNormal];
...@@ -123,12 +166,37 @@ static const CGFloat SideMargins = 16; ...@@ -123,12 +166,37 @@ static const CGFloat SideMargins = 16;
NSString* titleString = NSString* titleString =
l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NO_USERNAME); l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NO_USERNAME);
[self.usernameButton setTitle:titleString forState:UIControlStateNormal]; [self.usernameButton setTitle:titleString forState:UIControlStateNormal];
[self.usernameButton setTitleColor:UIColor.lightGrayColor
forState:UIControlStateNormal];
self.usernameButton.enabled = NO; self.usernameButton.enabled = NO;
} }
[verticalLeadViews addObject:self.usernameButton];
if (credential.password.length) { if (credential.password.length) {
[self.passwordButton setTitle:@"••••••••" forState:UIControlStateNormal]; [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 #pragma mark - Private
...@@ -137,10 +205,10 @@ static const CGFloat SideMargins = 16; ...@@ -137,10 +205,10 @@ static const CGFloat SideMargins = 16;
- (void)createViewHierarchy { - (void)createViewHierarchy {
self.selectionStyle = UITableViewCellSelectionStyleNone; self.selectionStyle = UITableViewCellSelectionStyleNone;
UIView* grayLine = [[UIView alloc] init]; self.grayLine = [[UIView alloc] init];
grayLine.backgroundColor = UIColor.cr_manualFillGrayLineColor; self.grayLine.backgroundColor = UIColor.cr_manualFillGrayLineColor;
grayLine.translatesAutoresizingMaskIntoConstraints = NO; self.grayLine.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:grayLine]; [self.contentView addSubview:self.grayLine];
UIView* guide = self.contentView; UIView* guide = self.contentView;
...@@ -163,22 +231,18 @@ static const CGFloat SideMargins = 16; ...@@ -163,22 +231,18 @@ static const CGFloat SideMargins = 16;
HorizontalConstraintsForViewsOnGuideWithShift(@[ self.passwordButton ], guide, HorizontalConstraintsForViewsOnGuideWithShift(@[ self.passwordButton ], guide,
0); 0);
VerticalConstraintsSpacingForViewsInContainer(
@[ self.siteNameLabel, self.usernameButton, self.passwordButton ],
self.contentView);
id<LayoutGuideProvider> safeArea = self.contentView.safeAreaLayoutGuide; id<LayoutGuideProvider> safeArea = self.contentView.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
// Common vertical constraints. // Common vertical constraints.
[grayLine.bottomAnchor [self.grayLine.bottomAnchor
constraintEqualToAnchor:self.contentView.bottomAnchor], constraintEqualToAnchor:self.contentView.bottomAnchor],
[grayLine.heightAnchor constraintEqualToConstant:1], [self.grayLine.heightAnchor constraintEqualToConstant:1],
// Horizontal constraints. // Horizontal constraints.
[grayLine.leadingAnchor constraintEqualToAnchor:safeArea.leadingAnchor [self.grayLine.leadingAnchor constraintEqualToAnchor:safeArea.leadingAnchor
constant:SideMargins], constant:SideMargins],
[safeArea.trailingAnchor constraintEqualToAnchor:grayLine.trailingAnchor [safeArea.trailingAnchor
constraintEqualToAnchor:self.grayLine.trailingAnchor
constant:SideMargins], constant:SideMargins],
]]; ]];
} }
......
...@@ -39,6 +39,19 @@ NSString* const OtherPasswordsAccessibilityIdentifier = ...@@ -39,6 +39,19 @@ NSString* const OtherPasswordsAccessibilityIdentifier =
} // namespace manual_fill } // 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, @interface ManualFillPasswordMediator ()<ManualFillContentDelegate,
PasswordFetcherDelegate> PasswordFetcherDelegate>
// The |WebStateList| containing the active web state. Used to filter the list // The |WebStateList| containing the active web state. Used to filter the list
...@@ -167,8 +180,16 @@ NSString* const OtherPasswordsAccessibilityIdentifier = ...@@ -167,8 +180,16 @@ NSString* const OtherPasswordsAccessibilityIdentifier =
(NSArray<ManualFillCredential*>*)credentials { (NSArray<ManualFillCredential*>*)credentials {
NSMutableArray* items = NSMutableArray* items =
[[NSMutableArray alloc] initWithCapacity:credentials.count]; [[NSMutableArray alloc] initWithCapacity:credentials.count];
for (ManualFillCredential* credential in credentials) { for (int i = 0; i < (int)credentials.count; i++) {
auto item = [[ManualFillCredentialItem alloc] initWithCredential:credential 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]; delegate:self];
[items addObject:item]; [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