Chromium Code Reviews| Index: ios/chrome/browser/ui/authentication/signin_promo_view.mm |
| diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view.mm b/ios/chrome/browser/ui/authentication/signin_promo_view.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..21ae88a03310096f4ba993ae5d47d5074d5235c6 |
| --- /dev/null |
| +++ b/ios/chrome/browser/ui/authentication/signin_promo_view.mm |
| @@ -0,0 +1,243 @@ |
| +// Copyright 2017 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/authentication/signin_promo_view.h" |
| + |
| +#include "base/logging.h" |
| +#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" |
| +#import "ios/chrome/browser/ui/uikit_ui_util.h" |
| +#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h" |
| +#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" |
| + |
| +#if !defined(__has_feature) || !__has_feature(objc_arc) |
| +#error "This file requires ARC support." |
| +#endif |
| + |
| +namespace { |
| +// Horizontal padding for label and buttons. |
| +const CGFloat kHorizontalPadding = 40; |
| +// Vertical padding for the image and the label. |
| +const CGFloat kVerticalPadding = 12; |
| +// Vertical padding for buttons. |
| +const CGFloat kButtonVerticalPadding = 6; |
| +// Image size for warm state. |
| +const CGFloat kProfileImageFixedSize = 48; |
| +// Image size for cold state. |
| +const CGFloat kChromeImageFixedSize = 24; |
| +// Button height. |
| +const CGFloat kButtonHeight = 36; |
| +} |
| + |
| +@implementation SigninPromoView { |
| + NSArray<NSLayoutConstraint*>* _coldStateConstraints; |
| + NSArray<NSLayoutConstraint*>* _warmStateConstraints; |
| +} |
| + |
| +@synthesize mode = _mode; |
| +@synthesize imageView = _imageView; |
| +@synthesize textLabel = _textLabel; |
| +@synthesize primaryButton = _primaryButton; |
| +@synthesize secondaryButton = _secondaryButton; |
| + |
| +- (instancetype)initWithFrame:(CGRect)frame { |
| + self = [super initWithFrame:frame]; |
| + if (self) { |
| + self.translatesAutoresizingMaskIntoConstraints = NO; |
| + self.isAccessibilityElement = YES; |
| + |
| + // Adding subviews. |
| + self.clipsToBounds = YES; |
| + _imageView = [[UIImageView alloc] init]; |
| + _imageView.translatesAutoresizingMaskIntoConstraints = NO; |
| + [self addSubview:_imageView]; |
| + |
| + _textLabel = [[UILabel alloc] init]; |
| + _textLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| + [self addSubview:_textLabel]; |
| + |
| + _primaryButton = [[MDCFlatButton alloc] init]; |
| + _primaryButton.translatesAutoresizingMaskIntoConstraints = NO; |
| + _primaryButton.accessibilityIdentifier = @"signin_promo_primary_button"; |
| + [self addSubview:_primaryButton]; |
| + |
| + _secondaryButton = [[MDCFlatButton alloc] init]; |
| + _secondaryButton.translatesAutoresizingMaskIntoConstraints = NO; |
| + _secondaryButton.accessibilityIdentifier = @"signin_promo_secondary_button"; |
| + [self addSubview:_secondaryButton]; |
| + |
| + // Adding style. |
| + _imageView.contentMode = UIViewContentModeCenter; |
| + _imageView.layer.masksToBounds = YES; |
| + _imageView.contentMode = UIViewContentModeScaleAspectFit; |
| + |
| + _textLabel.font = [MDCTypography buttonFont]; |
| + _textLabel.textColor = [[MDCPalette greyPalette] tint900]; |
| + _textLabel.numberOfLines = 0; |
| + _textLabel.textAlignment = NSTextAlignmentCenter; |
| + |
| + [_primaryButton setBackgroundColor:[[MDCPalette cr_bluePalette] tint500] |
| + forState:UIControlStateNormal]; |
| + _primaryButton.customTitleColor = [UIColor whiteColor]; |
| + _primaryButton.inkColor = [UIColor colorWithWhite:1 alpha:0.2]; |
| + |
| + _secondaryButton.customTitleColor = [[MDCPalette cr_bluePalette] tint500]; |
| + _secondaryButton.uppercaseTitle = NO; |
| + |
| + // Adding constraints. |
| + NSDictionary* metrics = @{ |
| + @"kButtonHeight" : @(kButtonHeight), |
| + @"kButtonVerticalPadding" : @(kButtonVerticalPadding), |
| + @"kButtonVerticalPaddingx2" : @(kButtonVerticalPadding * 2), |
| + @"kChromeImageFixedSize" : @(kChromeImageFixedSize), |
| + @"kHorizontalPadding" : @(kHorizontalPadding), |
| + @"kVerticalPadding" : @(kVerticalPadding), |
| + @"kVerticalPaddingx2" : @(kVerticalPadding * 2), |
| + @"kVerticalPaddingkButtonVerticalPadding" : |
| + @(kVerticalPadding + kButtonVerticalPadding), |
| + }; |
| + NSDictionary* views = @{ |
| + @"imageView" : _imageView, |
| + @"primaryButton" : _primaryButton, |
| + @"secondaryButton" : _secondaryButton, |
| + @"textLabel" : _textLabel, |
| + }; |
| + |
| + // Constraints shared between modes. |
| + NSString* formatString = @"V:|-kVerticalPaddingx2-[imageView]-" |
| + "kVerticalPadding-[textLabel]-" |
| + "kVerticalPaddingkButtonVerticalPadding-[" |
| + "primaryButton(kButtonHeight)]"; |
| + NSArray* visualConstraints = @[ |
| + formatString, |
| + @"H:|-kHorizontalPadding-[primaryButton]-kHorizontalPadding-|" |
| + ]; |
| + ApplyVisualConstraintsWithMetricsAndOptions( |
| + visualConstraints, views, metrics, NSLayoutFormatAlignAllCenterX); |
| + |
| + // Constraints for cold state mode. |
| + NSMutableArray* constraints = [NSMutableArray array]; |
|
msarda
2017/03/27 09:34:16
Optional nit: I think that using a local variable
jlebel
2017/03/27 21:34:42
My issue about using _coldStateConstraints and _wa
msarda
2017/03/28 08:12:51
Acknowledged.
|
| + formatString = |
|
msarda
2017/03/27 09:34:16
Personal pref: I do not like reusing a previously
jlebel
2017/03/27 21:34:42
Done.
|
| + @"V:[primaryButton]-kVerticalPaddingkButtonVerticalPadding-|"; |
| + [constraints |
| + addObjectsFromArray:[NSLayoutConstraint |
| + constraintsWithVisualFormat:formatString |
| + options:0 |
| + metrics:metrics |
| + views:views]]; |
| + // TODO(crbug.com/2749703003): Remove this rule once chrome image is added. |
|
msarda
2017/03/27 09:34:16
Unexpected character:
jlebel
2017/03/27 21:34:43
Done.
|
| + formatString = @"V:[imageView(kChromeImageFixedSize)]"; |
|
msarda
2017/03/27 09:34:16
Same here: imageViewVerticalSizeConstraint
jlebel
2017/03/27 21:34:43
Done.
|
| + [constraints |
| + addObjectsFromArray:[NSLayoutConstraint |
| + constraintsWithVisualFormat:formatString |
| + options:0 |
| + metrics:metrics |
| + views:views]]; |
| + _coldStateConstraints = [constraints copy]; |
| + |
| + // Constraints for warm state mode. |
| + constraints = [NSMutableArray array]; |
| + formatString = @"V:[primaryButton]-kButtonVerticalPaddingx2-[" |
|
msarda
2017/03/27 09:34:16
s/buttonsVerticalConstraint
jlebel
2017/03/27 21:34:43
Done.
|
| + "secondaryButton(kButtonHeight)]-" |
| + "kVerticalPaddingkButtonVerticalPadding-|"; |
| + [constraints |
| + addObjectsFromArray:[NSLayoutConstraint |
| + constraintsWithVisualFormat:formatString |
| + options:0 |
| + metrics:metrics |
| + views:views]]; |
| + formatString = |
|
msarda
2017/03/27 09:34:16
Same here: secondaryButtonHorizontalConstraint
jlebel
2017/03/27 21:34:42
Done.
|
| + @"H:|-kHorizontalPadding-[secondaryButton]-kHorizontalPadding-|"; |
| + [constraints |
| + addObjectsFromArray:[NSLayoutConstraint |
| + constraintsWithVisualFormat:formatString |
| + options:0 |
| + metrics:metrics |
| + views:views]]; |
| + _warmStateConstraints = [constraints copy]; |
| + |
| + _mode = SigninPromoViewColdStateMode; |
| + [self activateColdMode]; |
| + } |
| + return self; |
| +} |
| + |
| +- (void)setMode:(SigninPromoViewMode)mode { |
| + if (mode == _mode) { |
| + return; |
| + } |
| + _mode = mode; |
| + switch (_mode) { |
| + case SigninPromoViewColdStateMode: |
| + [self activateColdMode]; |
| + return; |
| + case SigninPromoViewWarmStateMode: |
| + [self activateWarmMode]; |
| + return; |
| + } |
| + NOTREACHED(); |
| +} |
| + |
| +- (void)activateColdMode { |
| + // TODO(crbug.com/2749703003) Needs to set the chrome/chromium icon in |
|
lpromero
2017/03/27 13:14:46
Not a crbug. Here and in several places.
lpromero
2017/03/27 13:14:46
Chrome/Chromium
jlebel
2017/03/27 21:34:43
Done.
jlebel
2017/03/27 21:34:43
Done.
|
| + // |imageView|. |
| + DCHECK(_mode == SigninPromoViewColdStateMode); |
|
msarda
2017/03/27 09:34:16
Prefer DCHECK_EQSigninPromoViewColdStateMode, _mod
jlebel
2017/03/27 21:34:43
Done.
|
| + [NSLayoutConstraint deactivateConstraints:_warmStateConstraints]; |
| + [NSLayoutConstraint activateConstraints:_coldStateConstraints]; |
| + _secondaryButton.hidden = YES; |
| +} |
| + |
| +- (void)activateWarmMode { |
| + DCHECK(_mode == SigninPromoViewWarmStateMode); |
|
msarda
2017/03/27 09:34:16
DCHECK_EQ
jlebel
2017/03/27 21:34:42
Done.
|
| + [NSLayoutConstraint deactivateConstraints:_coldStateConstraints]; |
| + [NSLayoutConstraint activateConstraints:_warmStateConstraints]; |
| + _secondaryButton.hidden = NO; |
| +} |
| + |
| +- (void)setProfileImage:(UIImage*)image { |
|
msarda
2017/03/27 09:34:16
I think this method should never be called in the
lpromero
2017/03/27 13:14:46
If you DCHECK, you need to remove the early return
jlebel
2017/03/27 21:34:43
The if() makes more sense to me. But I can change
msarda
2017/03/28 08:12:51
DCHECK_EQ is better than the if IMHO, for the foll
lpromero
2017/03/28 09:43:15
What I mean is that if you DCHECK, the Chromium st
|
| + if (SigninPromoViewColdStateMode == _mode) { |
| + return; |
| + } |
| + _imageView.image = CircularImageFromImage(image, kProfileImageFixedSize); |
| +} |
| + |
| +- (void)accessibilityPrimaryAction:(id)unused { |
| + [_primaryButton sendActionsForControlEvents:UIControlEventTouchUpInside]; |
| +} |
| + |
| +- (void)accessibilitySecondaryAction:(id)unused { |
| + [_secondaryButton sendActionsForControlEvents:UIControlEventTouchUpInside]; |
| +} |
| + |
| +- (CGFloat)horizontalPadding { |
| + return kHorizontalPadding; |
| +} |
| + |
| +#pragma mark - NSObject(Accessibility) |
| + |
| +- (NSArray<UIAccessibilityCustomAction*>*)accessibilityCustomActions { |
| + NSString* primaryActionName = |
| + [_primaryButton titleForState:UIControlStateNormal]; |
| + UIAccessibilityCustomAction* primaryCustomAction = |
| + [[UIAccessibilityCustomAction alloc] |
| + initWithName:primaryActionName |
| + target:self |
| + selector:@selector(accessibilityPrimaryAction:)]; |
| + if (_mode == SigninPromoViewColdStateMode) { |
| + return @[ primaryCustomAction ]; |
| + } |
| + NSString* secondaryActionName = |
| + [_secondaryButton titleForState:UIControlStateNormal]; |
| + UIAccessibilityCustomAction* secondaryCustomAction = |
| + [[UIAccessibilityCustomAction alloc] |
| + initWithName:secondaryActionName |
| + target:self |
| + selector:@selector(accessibilitySecondaryAction:)]; |
| + return @[ primaryCustomAction, secondaryCustomAction ]; |
| +} |
| + |
| +- (NSString*)accessibilityLabel { |
| + return _textLabel.text; |
| +} |
| + |
| +@end |