Commit 37d6dae3 authored by Jérôme Lebel's avatar Jérôme Lebel Committed by Commit Bot

[iOS] Creating IdentityView

This patch extracts code to display an avatar with an email and an
optional name from IdentityPickerView into IdentityView.

This code can be share between IdentityPickerView and the identity
chooser dialog in this mock:
https://gallery.googleplex.com/projects/MCHbtQVoQ2HCZQNtxfU4ytJv/files/MCHtA7U1iMGr62Mmhjs3q0iDhQHgIuNdWV0

Bug: 827072
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: Ib7df934aa678c35b42b8a37c71dfac6fd52ca5c4
Reviewed-on: https://chromium-review.googlesource.com/1044373
Commit-Queue: Jérôme Lebel <jlebel@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#557219}
parent 11ef1ec8
...@@ -218,11 +218,22 @@ class ChromeSigninViewControllerTest ...@@ -218,11 +218,22 @@ class ChromeSigninViewControllerTest
NSString* view_name = NSStringFromClass([view class]); NSString* view_name = NSStringFromClass([view class]);
// Views that don't display strings. // Views that don't display strings.
NSArray* other_views = @[ NSArray* other_views = @[
@"AccountControlCell", @"CollectionViewFooterCell", @"UIButtonLabel", @"AccountControlCell",
@"UICollectionView", @"UICollectionViewControllerWrapperView", @"CollectionViewFooterCell",
@"UIImageView", @"UIView", @"MDCActivityIndicator", @"MDCButtonBar", @"IdentityPickerView",
@"MDCFlexibleHeaderView", @"MDCHeaderStackView", @"MDCInkView", @"IdentityView",
@"MDCNavigationBar", @"UIScrollView", @"IdentityPickerView" @"UIButtonLabel",
@"MDCActivityIndicator",
@"MDCButtonBar",
@"MDCFlexibleHeaderView",
@"MDCHeaderStackView",
@"MDCInkView",
@"MDCNavigationBar",
@"UICollectionView",
@"UICollectionViewControllerWrapperView",
@"UIImageView",
@"UIScrollView",
@"UIView",
]; ];
// If this test fails, the unknown class should be added in other_views if // If this test fails, the unknown class should be added in other_views if
// it doesn't display any strings, otherwise the strings diplay by this // it doesn't display any strings, otherwise the strings diplay by this
......
...@@ -26,6 +26,8 @@ source_set("unified_consent_ui") { ...@@ -26,6 +26,8 @@ source_set("unified_consent_ui") {
sources = [ sources = [
"identity_picker_view.h", "identity_picker_view.h",
"identity_picker_view.mm", "identity_picker_view.mm",
"identity_view.h",
"identity_view.mm",
"unified_consent_view_controller.h", "unified_consent_view_controller.h",
"unified_consent_view_controller.mm", "unified_consent_view_controller.mm",
] ]
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.h" #import "ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.h"
#include "base/logging.h" #include "base/logging.h"
#import "ios/chrome/browser/ui/authentication/unified_consent/identity_view.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h" #import "ios/chrome/browser/ui/uikit_ui_util.h"
#import "ios/chrome/browser/ui/util/constraints_ui_util.h" #import "ios/chrome/browser/ui/util/constraints_ui_util.h"
#import "ios/third_party/material_components_ios/src/components/Ink/src/MaterialInk.h" #import "ios/third_party/material_components_ios/src/components/Ink/src/MaterialInk.h"
...@@ -17,43 +18,27 @@ namespace { ...@@ -17,43 +18,27 @@ namespace {
const CGFloat kIdentityPickerViewRadius = 8.; const CGFloat kIdentityPickerViewRadius = 8.;
// Sizes. // Sizes.
const CGFloat kIdentityAvatarSize = 40.;
const CGFloat kTitleFontSize = 14.;
const CGFloat kSubtitleFontSize = 12.;
const CGFloat kArrowDownSize = 24.; const CGFloat kArrowDownSize = 24.;
// Distances/margins. // Distances/margins.
const CGFloat kTitleOffset = 2;
const CGFloat kArrowDownMargin = 12.; const CGFloat kArrowDownMargin = 12.;
const CGFloat kHorizontalAvatarMargin = 16.; const CGFloat kHorizontalAvatarMargin = 16.;
const CGFloat kVerticalMargin = 12.; const CGFloat kVerticalMargin = 12.;
// Colors // Colors
const int kHeaderBackgroundColor = 0xf1f3f4; const int kHeaderBackgroundColor = 0xf1f3f4;
const CGFloat kTitleTextColorAlpha = .87;
const CGFloat kSubtitleTextColorAlpha = .54;
} // namespace } // namespace
@interface IdentityPickerView () @interface IdentityPickerView ()
@property(nonatomic) UIImageView* avatarImageView; @property(nonatomic, strong) IdentityView* identityView;
@property(nonatomic) UILabel* title; @property(nonatomic, strong) MDCInkView* inkView;
@property(nonatomic) UILabel* subtitle;
@property(nonatomic) MDCInkView* inkView;
@property(nonatomic) NSLayoutConstraint* titleConstraintForNameAndEmail;
@property(nonatomic) NSLayoutConstraint* titleConstraintForEmailOnly;
@end @end
@implementation IdentityPickerView @implementation IdentityPickerView
@synthesize avatarImageView = _avatarImageView; @synthesize identityView = _identityView;
@synthesize title = _title;
@synthesize subtitle = _subtitle;
@synthesize inkView = _inkView; @synthesize inkView = _inkView;
// Constraints when email and name are available.
@synthesize titleConstraintForNameAndEmail = _titleConstraintForNameAndEmail;
// Constraints when only the email is avaiable.
@synthesize titleConstraintForEmailOnly = _titleConstraintForEmailOnly;
- (instancetype)initWithFrame:(CGRect)frame { - (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame]; self = [super initWithFrame:frame];
...@@ -68,11 +53,6 @@ const CGFloat kSubtitleTextColorAlpha = .54; ...@@ -68,11 +53,6 @@ const CGFloat kSubtitleTextColorAlpha = .54;
_inkView.translatesAutoresizingMaskIntoConstraints = NO; _inkView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_inkView]; [self addSubview:_inkView];
// Avatar view.
_avatarImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
_avatarImageView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_avatarImageView];
// Arrow down. // Arrow down.
UIImageView* arrowDownImageView = UIImageView* arrowDownImageView =
[[UIImageView alloc] initWithFrame:CGRectZero]; [[UIImageView alloc] initWithFrame:CGRectZero];
...@@ -81,61 +61,33 @@ const CGFloat kSubtitleTextColorAlpha = .54; ...@@ -81,61 +61,33 @@ const CGFloat kSubtitleTextColorAlpha = .54;
[UIImage imageNamed:@"identity_picker_view_arrow_down"]; [UIImage imageNamed:@"identity_picker_view_arrow_down"];
[self addSubview:arrowDownImageView]; [self addSubview:arrowDownImageView];
// Title. // Main view with avatar, name and email.
_title = [[UILabel alloc] initWithFrame:CGRectZero]; _identityView = [[IdentityView alloc] initWithFrame:CGRectZero];
_title.translatesAutoresizingMaskIntoConstraints = NO; _identityView.translatesAutoresizingMaskIntoConstraints = NO;
_title.textColor = [UIColor colorWithWhite:0 alpha:kTitleTextColorAlpha]; [self addSubview:_identityView];
_title.font = [UIFont systemFontOfSize:kTitleFontSize];
[self addSubview:_title];
// Subtitle.
_subtitle = [[UILabel alloc] initWithFrame:CGRectZero];
_subtitle.translatesAutoresizingMaskIntoConstraints = NO;
_subtitle.textColor =
[UIColor colorWithWhite:0 alpha:kSubtitleTextColorAlpha];
_subtitle.font = [UIFont systemFontOfSize:kSubtitleFontSize];
[self addSubview:_subtitle];
// Layout constraints. // Layout constraints.
NSDictionary* views = @{ NSDictionary* views = @{
@"avatar" : _avatarImageView, @"identityview" : _identityView,
@"title" : _title,
@"subtitle" : _subtitle,
@"arrow" : arrowDownImageView, @"arrow" : arrowDownImageView,
}; };
NSDictionary* metrics = @{ NSDictionary* metrics = @{
@"ArMrg" : @(kArrowDownMargin), @"ArrowMargin" : @(kArrowDownMargin),
@"ArrowSize" : @(kArrowDownSize), @"ArrowSize" : @(kArrowDownSize),
@"AvatarSize" : @(kIdentityAvatarSize),
@"HAvatMrg" : @(kHorizontalAvatarMargin), @"HAvatMrg" : @(kHorizontalAvatarMargin),
@"VMargin" : @(kVerticalMargin), @"VMargin" : @(kVerticalMargin),
}; };
NSArray* constraints = @[ NSArray* constraints = @[
// Horizontal constraints. // Horizontal constraints.
@"H:|-(HAvatMrg)-[avatar]-(HAvatMrg)-[title]-(ArMrg)-[arrow]-(ArMrg)-|", @"H:|[identityview]-(ArrowMargin)-[arrow]-(ArrowMargin)-|",
// Vertical constraints. // Vertical constraints.
@"V:|-(>=VMargin)-[avatar]-(>=VMargin)-|", @"V:|[identityview]|",
@"V:|-(>=VMargin)-[title]",
@"V:[subtitle]-(>=VMargin)-|",
// Size constraints. // Size constraints.
@"H:[avatar(AvatarSize)]",
@"V:[avatar(AvatarSize)]",
@"H:[arrow(ArrowSize)]", @"H:[arrow(ArrowSize)]",
@"V:[arrow(ArrowSize)]", @"V:[arrow(ArrowSize)]",
]; ];
AddSameCenterYConstraint(self, _avatarImageView);
AddSameCenterYConstraint(self, arrowDownImageView); AddSameCenterYConstraint(self, arrowDownImageView);
ApplyVisualConstraintsWithMetrics(constraints, views, metrics); ApplyVisualConstraintsWithMetrics(constraints, views, metrics);
AddSameConstraintsToSides(_title, _subtitle,
LayoutSides::kLeading | LayoutSides::kTrailing);
_titleConstraintForNameAndEmail =
[self.centerYAnchor constraintEqualToAnchor:_title.bottomAnchor
constant:kTitleOffset];
_titleConstraintForEmailOnly =
[self.centerYAnchor constraintEqualToAnchor:_title.centerYAnchor];
[self.centerYAnchor constraintEqualToAnchor:_subtitle.topAnchor
constant:-kTitleOffset]
.active = YES;
} }
return self; return self;
} }
...@@ -143,24 +95,12 @@ const CGFloat kSubtitleTextColorAlpha = .54; ...@@ -143,24 +95,12 @@ const CGFloat kSubtitleTextColorAlpha = .54;
#pragma mark - Setter #pragma mark - Setter
- (void)setIdentityAvatar:(UIImage*)identityAvatar { - (void)setIdentityAvatar:(UIImage*)identityAvatar {
_avatarImageView.image = [self.identityView setAvatar:identityAvatar];
CircularImageFromImage(identityAvatar, kIdentityAvatarSize);
} }
- (void)setIdentityName:(NSString*)name email:(NSString*)email { - (void)setIdentityName:(NSString*)name email:(NSString*)email {
DCHECK(email); DCHECK(email);
if (!name || name.length == 0) { [self.identityView setName:name email:email];
self.titleConstraintForNameAndEmail.active = NO;
self.titleConstraintForEmailOnly.active = YES;
self.subtitle.hidden = YES;
self.title.text = email;
} else {
self.titleConstraintForEmailOnly.active = NO;
self.titleConstraintForNameAndEmail.active = YES;
self.subtitle.hidden = NO;
self.title.text = name;
self.subtitle.text = email;
}
} }
#pragma mark - Private #pragma mark - Private
......
// 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.
#ifndef IOS_CHROME_BROWSER_UI_AUTHENTICATION_UNIFIED_CONSENT_IDENTITY_VIEW_H_
#define IOS_CHROME_BROWSER_UI_AUTHENTICATION_UNIFIED_CONSENT_IDENTITY_VIEW_H_
#import <UIKit/UIKit.h>
// View with the avatar on the leading side, the name and the email address of
// an identity.
// The email address is required. The name and the avatar are optional.
// If the name is empty (or nil), then the email address is vertically centered.
// The avatar is displayed as a round image.
// +--------------------------------+
// | +------+ |
// | | | Full Name |
// | |Avatar| Email address |
// | +------+ |
// +--------------------------------+
@interface IdentityView : UIView
// Initialises IdentityView.
- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
// See -[IdentityView initWithFrame:].
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
// Sets the avatar shown. The image is resized (40px) and shaped as a round
// image.
- (void)setAvatar:(UIImage*)avatar;
// Sets the name and the email address. |name| can be nil.
- (void)setName:(NSString*)name email:(NSString*)email;
@end
#endif // IOS_CHROME_BROWSER_UI_AUTHENTICATION_UNIFIED_CONSENT_IDENTITY_VIEW_H_
// 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/authentication/unified_consent/identity_view.h"
#include "base/logging.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h"
#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Sizes.
const CGFloat kAvatarSize = 40.;
const CGFloat kTitleFontSize = 14.;
const CGFloat kSubtitleFontSize = 12.;
// Distances/margins.
const CGFloat kTitleOffset = 2;
const CGFloat kHorizontalAvatarMargin = 16.;
const CGFloat kVerticalMargin = 12.;
// Colors
const CGFloat kTitleTextColorAlpha = .87;
const CGFloat kSubtitleTextColorAlpha = .54;
} // namespace
@interface IdentityView ()
// Avatar.
@property(nonatomic, strong) UIImageView* avatarView;
// Contains the name if it exists, otherwise it contains the email.
@property(nonatomic, strong) UILabel* title;
// Contains the email if the name exists, otherwise it is hidden.
@property(nonatomic, strong) UILabel* subtitle;
// Constraints if the name exists.
@property(nonatomic, strong) NSLayoutConstraint* titleConstraintForNameAndEmail;
// Constraints if the name doesn't exist.
@property(nonatomic, strong) NSLayoutConstraint* titleConstraintForEmailOnly;
@end
@implementation IdentityView
@synthesize avatarView = _avatarView;
@synthesize title = _title;
@synthesize subtitle = _subtitle;
// Constraints when email and name are available.
@synthesize titleConstraintForNameAndEmail = _titleConstraintForNameAndEmail;
// Constraints when only the email is available.
@synthesize titleConstraintForEmailOnly = _titleConstraintForEmailOnly;
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Avatar view.
_avatarView = [[UIImageView alloc] init];
_avatarView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_avatarView];
// Title.
_title = [[UILabel alloc] init];
_title.translatesAutoresizingMaskIntoConstraints = NO;
_title.textColor = [UIColor colorWithWhite:0 alpha:kTitleTextColorAlpha];
_title.font = [UIFont systemFontOfSize:kTitleFontSize];
[self addSubview:_title];
// Subtitle.
_subtitle = [[UILabel alloc] init];
_subtitle.translatesAutoresizingMaskIntoConstraints = NO;
_subtitle.textColor =
[UIColor colorWithWhite:0 alpha:kSubtitleTextColorAlpha];
_subtitle.font = [UIFont systemFontOfSize:kSubtitleFontSize];
[self addSubview:_subtitle];
// Layout constraints.
NSDictionary* views = @{
@"avatar" : _avatarView,
@"title" : _title,
@"subtitle" : _subtitle,
};
NSDictionary* metrics = @{
@"AvatarSize" : @(kAvatarSize),
@"HAvatarMargin" : @(kHorizontalAvatarMargin),
@"VMargin" : @(kVerticalMargin),
};
NSArray* constraints = @[
// Horizontal constraints.
@"H:|-(HAvatarMargin)-[avatar]-(HAvatarMargin)-[title]|",
// Vertical constraints.
@"V:|-(>=VMargin)-[avatar]-(>=VMargin)-|",
@"V:|-(>=VMargin)-[title]",
@"V:[subtitle]-(>=VMargin)-|",
// Size constraints.
@"H:[avatar(AvatarSize)]",
@"V:[avatar(AvatarSize)]",
];
AddSameCenterYConstraint(self, _avatarView);
ApplyVisualConstraintsWithMetrics(constraints, views, metrics);
AddSameConstraintsToSides(_title, _subtitle,
LayoutSides::kLeading | LayoutSides::kTrailing);
_titleConstraintForNameAndEmail =
[self.centerYAnchor constraintEqualToAnchor:_title.bottomAnchor
constant:kTitleOffset];
_titleConstraintForEmailOnly =
[self.centerYAnchor constraintEqualToAnchor:_title.centerYAnchor];
[self.centerYAnchor constraintEqualToAnchor:_subtitle.topAnchor
constant:-kTitleOffset]
.active = YES;
}
return self;
}
#pragma mark - Setter
- (void)setAvatar:(UIImage*)avatarImage {
if (avatarImage) {
self.avatarView.image = CircularImageFromImage(avatarImage, kAvatarSize);
} else {
self.avatarView.image = nil;
}
}
- (void)setName:(NSString*)name email:(NSString*)email {
DCHECK(email);
if (!name || name.length == 0) {
self.titleConstraintForNameAndEmail.active = NO;
self.titleConstraintForEmailOnly.active = YES;
self.subtitle.hidden = YES;
self.title.text = email;
} else {
self.titleConstraintForEmailOnly.active = NO;
self.titleConstraintForNameAndEmail.active = YES;
self.subtitle.hidden = NO;
self.title.text = name;
self.subtitle.text = email;
}
}
@end
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