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..14d58a1ed9ae6d3b0d457195574a46b0b1042a29 |
--- /dev/null |
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view.mm |
@@ -0,0 +1,280 @@ |
+// 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" |
+#include "ios/chrome/grit/ios_strings.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 start. |
+const CGFloat kProfileImageFixedSize = 48; |
+// Image size for cold start. |
+const CGFloat kChromeImageFixedSize = 24; |
msarda
2017/03/22 12:18:39
I expect the profile image and the chrome image sh
lpromero
2017/03/24 10:36:20
That would be simpler for us. Try to push back to
jlebel
2017/03/24 20:59:08
I don't understand my code already handles the 2 s
|
+// Button height. |
+const CGFloat kButtonHeight = 36; |
+} |
+ |
+@implementation SigninPromoView { |
+ SigninPromoViewMode _mode; |
lpromero
2017/03/24 10:36:20
These 5 ivars are not needed, as they are generate
jlebel
2017/03/24 20:59:09
Done.
|
+ UIImageView* _imageView; |
+ UILabel* _textLabel; |
+ MDCFlatButton* _primaryButton; |
+ MDCFlatButton* _secondaryButton; |
+ |
+ NSArray<NSLayoutConstraint*>* _coldStartConstraints; |
msarda
2017/03/22 12:18:39
s/_coldStartConstraints/_secondaryButtonVisibleCon
lpromero
2017/03/24 10:36:20
Actually, I like the abstraction the names give.
jlebel
2017/03/24 20:59:09
Acknowledged.
|
+ NSArray<NSLayoutConstraint*>* _warmStartConstraints; |
msarda
2017/03/22 12:18:39
s/_coldStartConstraints/_secondaryButtonHiddenCons
jlebel
2017/03/24 20:59:09
Acknowledged.
|
+} |
+ |
+@synthesize mode = _mode; |
+@synthesize imageView = _imageView; |
+@synthesize textLabel = _textLabel; |
+@synthesize primaryButton = _primaryButton; |
+@synthesize secondaryButton = _secondaryButton; |
+ |
+- (instancetype)initWithCoder:(NSCoder*)aDecoder { |
lpromero
2017/03/24 10:36:20
No need for this (see similar comment above or bel
jlebel
2017/03/24 20:59:09
Done.
|
+ NOTREACHED(); |
+ return nil; |
+} |
+ |
+- (instancetype)initWithFrame:(CGRect)frame { |
+ self = [super initWithFrame:frame]; |
+ if (self) { |
+ self.translatesAutoresizingMaskIntoConstraints = NO; |
+ self.isAccessibilityElement = YES; |
+ [self addSubviews]; |
+ [self setDefaultViewStyling]; |
+ [self setViewConstraints]; |
msarda
2017/03/22 12:18:39
Consider calling [self setMode:SigninPromoViewCold
lpromero
2017/03/24 10:36:20
Ha! Mihai, you advised against calling methods in
jlebel
2017/03/24 20:59:09
I can't call -[SigninPromoView setMode:] in the in
|
+ _mode = SigninPromoViewColdStartMode; |
+ [self activateColdMode]; |
+ } |
+ return self; |
+} |
+ |
+- (void)addSubviews { |
+ 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]; |
+} |
+ |
+- (void)setDefaultViewStyling { |
+ _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; |
+} |
+ |
+- (void)setViewConstraints { |
+ NSDictionary* metrics = @{ |
+ @"kButtonHeight" : @(kButtonHeight), |
+ @"kButtonVerticalPadding" : @(kButtonVerticalPadding), |
+ @"kButtonVerticalPaddingx2" : @(kButtonVerticalPadding * 2), |
+ @"kChromeImageFixedSize" : @(kChromeImageFixedSize), |
+ @"kHorizontalPadding" : @(kHorizontalPadding), |
+ @"kProfileImageFixedSize" : @(kProfileImageFixedSize), |
+ @"kVerticalPadding" : @(kVerticalPadding), |
+ @"kVerticalPaddingx2" : @(kVerticalPadding * 2), |
+ @"kVerticalPaddingkButtonVerticalPadding" : |
+ @(kVerticalPadding + kButtonVerticalPadding), |
+ }; |
+ NSDictionary* views = @{ |
+ @"imageView" : _imageView, |
+ @"primaryButton" : _primaryButton, |
+ @"secondaryButton" : _secondaryButton, |
+ @"textLabel" : _textLabel, |
+ }; |
+ |
+ // Constraints in shared between modes. |
msarda
2017/03/22 12:18:39
Constraints shared between modes.
jlebel
2017/03/24 20:59:09
Done.
|
+ NSString* formatString = |
+ @"V:|-kVerticalPaddingx2-[imageView]-kVerticalPadding-[textLabel]-" |
+ @"kVerticalPaddingkButtonVerticalPadding-[primaryButton(kButtonHeight)]"; |
msarda
2017/03/22 12:18:39
Personal pref: Consider removing the @ on this sec
lpromero
2017/03/24 10:36:20
Agreed, I thought it was a second string.
jlebel
2017/03/24 20:59:09
Done.
|
+ [NSLayoutConstraint |
+ activateConstraints: |
+ [NSLayoutConstraint |
+ constraintsWithVisualFormat:formatString |
+ options:NSLayoutFormatAlignAllCenterX |
+ metrics:metrics |
+ views:views]]; |
+ |
+ formatString = @"H:|-kHorizontalPadding-[primaryButton]-kHorizontalPadding-|"; |
msarda
2017/03/22 12:18:39
You can put all these visual constraints in a sing
jlebel
2017/03/24 20:59:08
Done.
|
+ [NSLayoutConstraint |
msarda
2017/03/22 12:18:39
I think this code would be so much simpler to read
jlebel
2017/03/24 20:59:09
I will do that in another patch.
msarda
2017/03/27 09:34:16
I have a strong preference for this as I think it
|
+ activateConstraints:[NSLayoutConstraint |
+ constraintsWithVisualFormat:formatString |
+ options:0 |
+ metrics:metrics |
+ views:views]]; |
+ |
+ // Constraints for cold start mode. |
+ NSMutableArray* constraints = [NSMutableArray array]; |
+ formatString = @"V:[primaryButton]-kVerticalPaddingkButtonVerticalPadding-|"; |
+ [constraints addObjectsFromArray:[NSLayoutConstraint |
+ constraintsWithVisualFormat:formatString |
+ options:0 |
+ metrics:metrics |
+ views:views]]; |
+ formatString = @"H:[imageView(kChromeImageFixedSize)]"; |
+ [constraints addObjectsFromArray:[NSLayoutConstraint |
+ constraintsWithVisualFormat:formatString |
+ options:0 |
+ metrics:metrics |
+ views:views]]; |
+ formatString = @"V:[imageView(kChromeImageFixedSize)]"; |
+ [constraints addObjectsFromArray:[NSLayoutConstraint |
+ constraintsWithVisualFormat:formatString |
+ options:0 |
+ metrics:metrics |
+ views:views]]; |
+ _coldStartConstraints = [constraints copy]; |
+ |
+ // Constraints for warm start mode. |
+ constraints = [NSMutableArray array]; |
+ formatString = @"V:[primaryButton]-kButtonVerticalPaddingx2-[secondaryButton(" |
+ @"kButtonHeight)]-kVerticalPaddingkButtonVerticalPadding-|"; |
+ [constraints addObjectsFromArray:[NSLayoutConstraint |
+ constraintsWithVisualFormat:formatString |
+ options:0 |
+ metrics:metrics |
+ views:views]]; |
+ formatString = |
+ @"H:|-kHorizontalPadding-[secondaryButton]-kHorizontalPadding-|"; |
+ [constraints addObjectsFromArray: |
+ [NSLayoutConstraint |
+ constraintsWithVisualFormat:formatString |
+ options:NSLayoutFormatAlignAllCenterX |
lpromero
2017/03/24 10:36:20
Isn't tis option already done with line 138?
jlebel
2017/03/24 20:59:09
I didn't know it applied to the secondary button e
lpromero
2017/03/27 13:14:46
Oh good catch. Line 138 might not set this then.
|
+ metrics:metrics |
+ views:views]]; |
+ formatString = @"H:[imageView(kProfileImageFixedSize)]"; |
+ [constraints addObjectsFromArray:[NSLayoutConstraint |
+ constraintsWithVisualFormat:formatString |
+ options:0 |
+ metrics:metrics |
+ views:views]]; |
+ formatString = @"V:[imageView(kProfileImageFixedSize)]"; |
+ [constraints addObjectsFromArray:[NSLayoutConstraint |
+ constraintsWithVisualFormat:formatString |
+ options:0 |
+ metrics:metrics |
+ views:views]]; |
+ _warmStartConstraints = [constraints copy]; |
+ _mode = SigninPromoViewWarmStartMode; |
msarda
2017/03/22 12:18:39
I think this line needs to be removed.
jlebel
2017/03/24 20:59:09
Done.
|
+} |
+ |
+- (void)setMode:(SigninPromoViewMode)mode { |
+ if (mode == _mode) { |
+ return; |
+ } |
+ _mode = mode; |
+ switch (_mode) { |
+ case SigninPromoViewColdStartMode: |
+ [self activateColdMode]; |
+ return; |
+ case SigninPromoViewWarmStartMode: |
+ [self activateWarmMode]; |
+ return; |
+ } |
+ NOTREACHED(); |
+} |
+ |
+- (void)activateColdMode { |
msarda
2017/03/22 12:18:39
DCHECK(_mode, COLD);
jlebel
2017/03/24 20:59:09
Done.
|
+ // TODO(jlebel) Needs to set the chrome/chromium icon in |imageView|. |
msarda
2017/03/22 12:18:39
Please remove this TODO as it is the job of the co
jlebel
2017/03/24 20:59:09
I'm going to follow Louis suggestion and keep it t
|
+ [NSLayoutConstraint deactivateConstraints:_warmStartConstraints]; |
+ [NSLayoutConstraint activateConstraints:_coldStartConstraints]; |
+ _secondaryButton.hidden = YES; |
+} |
+ |
+- (void)activateWarmMode { |
msarda
2017/03/22 12:18:39
DCHECK(_mode, WARM);
jlebel
2017/03/24 20:59:09
Done.
|
+ [NSLayoutConstraint deactivateConstraints:_coldStartConstraints]; |
+ [NSLayoutConstraint activateConstraints:_warmStartConstraints]; |
+ _secondaryButton.hidden = NO; |
+} |
+ |
+- (void)setProfileImage:(UIImage*)image { |
lpromero
2017/03/24 10:36:20
Can you add a comment in the header that this is a
jlebel
2017/03/24 20:59:09
Should I rephrase:
"Should be called only with the
|
+ if (SigninPromoViewColdStartMode == _mode) { |
+ return; |
+ } |
+ _imageView.image = CircularImageFromImage(image, kProfileImageFixedSize); |
+} |
+ |
+- (void)accessibilityPrimaryAction:(id)unused { |
+ [_primaryButton sendActionsForControlEvents:UIControlEventTouchUpInside]; |
+} |
+ |
+- (void)accessibilitySecondaryAction:(id)unused { |
+ [_secondaryButton sendActionsForControlEvents:UIControlEventTouchUpInside]; |
+} |
+ |
+- (CGFloat)horizontalPadding { |
lpromero
2017/03/24 10:36:20
Doesn't seem used.
jlebel
2017/03/24 20:59:09
It is used. It is explained in the header why this
lpromero
2017/03/27 13:14:46
Sounds good.
|
+ 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 == SigninPromoViewColdStartMode) { |
+ 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 |