blob: 68ac8392a4eb058614ba215d14148b146bec1dc2 [file] [log] [blame]
// 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/views/identity_view.h"
#import "base/check.h"
#import "base/notreached.h"
#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
#import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h"
#import "ios/chrome/common/ui/util/constraints_ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// List of constants related to the IdentityViewStyle.
typedef struct {
const CGFloat avatarLeadingMargin;
const CGFloat avatarSize;
const CGFloat titleOffset;
const CGFloat minimumTopMargin;
const CGFloat minimumBottomMargin;
} StyleValues;
const StyleValues kDefaultStyle = {
16., /* avatarLeadingMargin */
40., /* avatarSize */
4., /* titleOffset */
12., /* minimumTopMargin */
12., /* minimumBottomMargin */
};
const StyleValues kSignInChooseryStyle = {
24., /* avatarLeadingMargin */
40., /* avatarSize */
4., /* titleOffset */
7., /* minimumTopMargin */
7., /* minimumBottomMargin */
};
const StyleValues kConsistencyStyle = {
16., /* avatarLeadingMargin */
30., /* avatarSize */
0., /* titleOffset */
10., /* minimumTopMargin */
8., /* minimumBottomMargin */
};
// Distances/margins.
constexpr CGFloat kHorizontalAvatarLeadingMargin = 16.;
} // 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;
// Constraints to update when |self.minimumTopMargin| is updated.
@property(nonatomic, strong) NSArray<NSLayoutConstraint*>* topConstraints;
// Constraints to update when |self.minimumBottomMargin| is updated.
@property(nonatomic, strong) NSArray<NSLayoutConstraint*>* bottomConstraints;
// Constraints for the avatar size.
@property(nonatomic, strong)
NSArray<NSLayoutConstraint*>* avatarSizeConstraints;
// Leading margin constraint for the avatar.
@property(nonatomic, strong) NSLayoutConstraint* avatarLeadingMarginConstraint;
@end
@implementation IdentityView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.userInteractionEnabled = NO;
self.clipsToBounds = YES;
// Avatar view.
_avatarView = [[UIImageView alloc] init];
_avatarView.translatesAutoresizingMaskIntoConstraints = NO;
_avatarView.clipsToBounds = YES;
[self addSubview:_avatarView];
// Title.
_title = [[UILabel alloc] init];
_title.adjustsFontForContentSizeCategory = YES;
_title.translatesAutoresizingMaskIntoConstraints = NO;
_title.numberOfLines = 0;
_title.textColor = UIColor.cr_labelColor;
_title.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
[self addSubview:_title];
// Subtitle.
_subtitle = [[UILabel alloc] init];
_subtitle.adjustsFontForContentSizeCategory = YES;
_subtitle.translatesAutoresizingMaskIntoConstraints = NO;
_subtitle.numberOfLines = 0;
_subtitle.textColor = UIColor.cr_secondaryLabelColor;
_subtitle.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
[self addSubview:_subtitle];
// Text container.
UILayoutGuide* textContainerGuide = [[UILayoutGuide alloc] init];
[self addLayoutGuide:textContainerGuide];
// Layout constraints.
_avatarLeadingMarginConstraint = [_avatarView.leadingAnchor
constraintEqualToAnchor:self.leadingAnchor
constant:kDefaultStyle.avatarLeadingMargin];
[NSLayoutConstraint activateConstraints:@[
[textContainerGuide.leadingAnchor
constraintEqualToAnchor:_avatarView.trailingAnchor
constant:kHorizontalAvatarLeadingMargin],
_avatarLeadingMarginConstraint,
]];
_avatarSizeConstraints = @[
[_avatarView.heightAnchor
constraintEqualToConstant:kDefaultStyle.avatarSize],
[_avatarView.widthAnchor
constraintEqualToConstant:kDefaultStyle.avatarSize],
];
[NSLayoutConstraint activateConstraints:_avatarSizeConstraints];
AddSameCenterYConstraint(self, _avatarView);
AddSameConstraintsToSides(_title, _subtitle,
LayoutSides::kLeading | LayoutSides::kTrailing);
_titleConstraintForNameAndEmail =
[_subtitle.topAnchor constraintEqualToAnchor:_title.bottomAnchor
constant:kDefaultStyle.titleOffset];
_titleConstraintForEmailOnly = [textContainerGuide.bottomAnchor
constraintEqualToAnchor:_title.bottomAnchor];
[NSLayoutConstraint activateConstraints:@[
[self.centerYAnchor
constraintEqualToAnchor:textContainerGuide.centerYAnchor],
[textContainerGuide.leadingAnchor
constraintEqualToAnchor:_title.leadingAnchor],
[textContainerGuide.leadingAnchor
constraintEqualToAnchor:_subtitle.leadingAnchor],
[textContainerGuide.trailingAnchor
constraintEqualToAnchor:_title.trailingAnchor],
[textContainerGuide.trailingAnchor
constraintEqualToAnchor:_subtitle.trailingAnchor],
[textContainerGuide.topAnchor constraintEqualToAnchor:_title.topAnchor],
[textContainerGuide.bottomAnchor
constraintEqualToAnchor:_subtitle.bottomAnchor],
]];
_topConstraints = @[
[_avatarView.topAnchor
constraintGreaterThanOrEqualToAnchor:self.topAnchor
constant:kDefaultStyle.minimumTopMargin],
[_title.topAnchor
constraintGreaterThanOrEqualToAnchor:self.topAnchor
constant:kDefaultStyle.minimumTopMargin],
];
[NSLayoutConstraint activateConstraints:_topConstraints];
_bottomConstraints = @[
[self.bottomAnchor
constraintGreaterThanOrEqualToAnchor:_avatarView.bottomAnchor
constant:kDefaultStyle
.minimumBottomMargin],
[self.bottomAnchor
constraintGreaterThanOrEqualToAnchor:_subtitle.bottomAnchor
constant:kDefaultStyle
.minimumBottomMargin],
];
[NSLayoutConstraint activateConstraints:_bottomConstraints];
}
return self;
}
#pragma mark - Setter
- (void)setAvatar:(UIImage*)avatarImage {
if (avatarImage) {
const StyleValues* style = [self styleValues];
self.avatarView.image = avatarImage;
self.avatarView.layer.cornerRadius = style->avatarSize / 2.0;
} else {
self.avatarView.image = nil;
}
}
- (void)setTitle:(NSString*)title subtitle:(NSString*)subtitle {
DCHECK(title);
self.title.text = title;
if (!subtitle.length) {
self.titleConstraintForNameAndEmail.active = NO;
self.titleConstraintForEmailOnly.active = YES;
self.subtitle.hidden = YES;
} else {
self.titleConstraintForEmailOnly.active = NO;
self.titleConstraintForNameAndEmail.active = YES;
self.subtitle.hidden = NO;
self.subtitle.text = subtitle;
}
}
#pragma mark - properties
- (void)setTitleFont:(UIFont*)titleFont {
self.title.font = titleFont;
}
- (UIFont*)titleFont {
return self.title.font;
}
- (void)setSubtitleFont:(UIFont*)subtitleFont {
self.subtitle.font = subtitleFont;
}
- (UIFont*)subtitleFont {
return self.subtitleFont;
}
- (void)setStyle:(IdentityViewStyle)style {
if (_style == style)
return;
_style = style;
[self updateStyle];
}
#pragma mark - private
// Returns the default style values according to |self.style|.
- (const StyleValues*)styleValues {
switch (self.style) {
case IdentityViewStyleDefault:
return &kDefaultStyle;
case IdentityViewStyleIdentityChooser:
return &kSignInChooseryStyle;
case IdentityViewStyleConsistency:
return &kConsistencyStyle;
}
NOTREACHED();
return nullptr;
}
// Updates the current view according the style.
- (void)updateStyle {
const StyleValues* style = [self styleValues];
switch (self.style) {
case IdentityViewStyleDefault:
self.titleFont =
[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
self.subtitleFont =
[UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
break;
case IdentityViewStyleIdentityChooser:
self.titleFont =
[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
self.subtitleFont =
[UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
break;
case IdentityViewStyleConsistency:
self.titleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
self.subtitleFont =
[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
break;
}
DCHECK(style);
self.avatarLeadingMarginConstraint.constant = style->avatarLeadingMargin;
for (NSLayoutConstraint* constraint in self.avatarSizeConstraints) {
constraint.constant = style->avatarSize;
}
self.avatarView.layer.cornerRadius = style->avatarSize / 2.;
for (NSLayoutConstraint* constraint in self.topConstraints) {
constraint.constant = style->minimumTopMargin;
}
for (NSLayoutConstraint* constraint in self.bottomConstraints) {
constraint.constant = style->minimumBottomMargin;
}
self.titleConstraintForNameAndEmail.constant = style->titleOffset;
}
@end