chromium/ios/chrome/browser/autofill/ui_bundled/manual_fill/chip_button.mm

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/chip_button.h"

#import "base/apple/foundation_util.h"
#import "base/ios/ios_util.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"

namespace {

// Padding for the button. Used when the kIOSKeyboardAccessoryUpgrade feature is
// disabled.
constexpr CGFloat kChipPadding = 14;

// Leading and trailing padding for the button. Used when the
// kIOSKeyboardAccessoryUpgrade feature is enabled.
constexpr CGFloat kChipHorizontalPadding = 12;

// Top and bottom padding for the button. Used when the
// kIOSKeyboardAccessoryUpgrade feature is enabled.
constexpr CGFloat kChipVerticalPadding = 11.5;

// Vertical margin for the button. How much bigger the tap target is. Used when
// the kIOSKeyboardAccessoryUpgrade feature is disabled.
constexpr CGFloat kChipVerticalMargin = 4;

// Minimal height and width for the button.
constexpr CGFloat kChipMinSize = 44;

// Font size for the button's title.
constexpr CGFloat kFontSize = 14;

// Line spacing for the button's title.
constexpr CGFloat kLineSpacing = 6;

// Returns the vertical margin to use.
CGFloat GetChipVerticalMargin() {
  return IsKeyboardAccessoryUpgradeEnabled() ? 0 : kChipVerticalMargin;
}

// Returns the horizontal padding to use.
CGFloat GetChipHorizontalPadding() {
  return IsKeyboardAccessoryUpgradeEnabled() ? kChipHorizontalPadding
                                             : kChipPadding;
}

// Returns the vertical padding to use.
CGFloat GetChipVerticalPadding() {
  return IsKeyboardAccessoryUpgradeEnabled() ? kChipVerticalPadding
                                             : kChipPadding;
}

}  // namespace

@interface ChipButton ()

// Gray rounded background view which gives the aspect of a chip.
@property(strong, nonatomic) UIView* backgroundView;

// Attributes of the button's title.
@property(strong, nonatomic) NSDictionary* titleAttributes;

@end

@implementation ChipButton

- (id)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self) {
    [self initializeStyling];
    [[NSNotificationCenter defaultCenter]
        addObserver:self
           selector:@selector(updateTitleLabelFont)
               name:UIContentSizeCategoryDidChangeNotification
             object:nil];
  }
  return self;
}

- (id)initWithCoder:(NSCoder*)aDecoder {
  self = [super initWithCoder:aDecoder];
  if (self) {
    [self initializeStyling];
  }
  return self;
}

- (void)awakeFromNib {
  [super awakeFromNib];
  [self initializeStyling];
}

- (void)layoutSubviews {
  [super layoutSubviews];
  CGFloat height = IsKeyboardAccessoryUpgradeEnabled()
                       ? kChipMinSize
                       : self.backgroundView.bounds.size.height;
  self.backgroundView.layer.cornerRadius = height / 2.0;
}

- (void)setHighlighted:(BOOL)highlighted {
  [super setHighlighted:highlighted];
  self.backgroundView.backgroundColor =
      highlighted ? [UIColor colorNamed:kGrey300Color]
                  : [UIColor colorNamed:kGrey100Color];
}

- (void)setEnabled:(BOOL)enabled {
  [super setEnabled:enabled];
  self.backgroundView.hidden = !enabled;
  UIButtonConfiguration* buttonConfiguration = self.configuration;
  buttonConfiguration.contentInsets = enabled
                                          ? [self chipNSDirectionalEdgeInsets]
                                          : NSDirectionalEdgeInsetsZero;
  self.configuration = buttonConfiguration;
}

#pragma mark - Getters

- (NSDictionary*)titleAttributes {
  // `titleAttributes` shouldn't be accessed if the Keyboard Accessory Upgrade
  // is disabled.
  CHECK(IsKeyboardAccessoryUpgradeEnabled());

  if (_titleAttributes) {
    return _titleAttributes;
  }

  UIFont* font = [UIFont systemFontOfSize:kFontSize weight:UIFontWeightMedium];
  NSMutableParagraphStyle* paragraphStyle =
      [[NSMutableParagraphStyle alloc] init];
  paragraphStyle.lineSpacing = kLineSpacing;
  _titleAttributes = @{
    NSFontAttributeName :
        [[UIFontMetrics defaultMetrics] scaledFontForFont:font],
    NSParagraphStyleAttributeName : paragraphStyle,
  };

  return _titleAttributes;
}

#pragma mark - Setters

- (void)setTitle:(NSString*)title forState:(UIControlState)state {
  if (IsKeyboardAccessoryUpgradeEnabled()) {
    UIButtonConfiguration* buttonConfiguration = self.configuration;
    NSAttributedString* attributedTitle =
        [[NSAttributedString alloc] initWithString:title
                                        attributes:self.titleAttributes];
    buttonConfiguration.attributedTitle = attributedTitle;
    self.configuration = buttonConfiguration;
  } else {
    [super setTitle:title forState:state];
  }
}

#pragma mark - Private

- (NSDirectionalEdgeInsets)chipNSDirectionalEdgeInsets {
  CGFloat horizontalPadding = GetChipHorizontalPadding();
  CGFloat verticalPadding = GetChipVerticalPadding();

  return NSDirectionalEdgeInsetsMake(verticalPadding, horizontalPadding,
                                     verticalPadding, horizontalPadding);
}

- (void)initializeStyling {
  _backgroundView = [[UIView alloc] init];
  _backgroundView.userInteractionEnabled = NO;
  _backgroundView.backgroundColor = [UIColor colorNamed:kGrey100Color];
  _backgroundView.translatesAutoresizingMaskIntoConstraints = NO;

  [self addSubview:_backgroundView];
  [self sendSubviewToBack:_backgroundView];

  if (IsKeyboardAccessoryUpgradeEnabled()) {
    [NSLayoutConstraint activateConstraints:@[
      [_backgroundView.heightAnchor
          constraintGreaterThanOrEqualToConstant:kChipMinSize],
      [_backgroundView.widthAnchor
          constraintGreaterThanOrEqualToConstant:kChipMinSize],
    ]];
  }

  [NSLayoutConstraint activateConstraints:@[
    [_backgroundView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
    [_backgroundView.trailingAnchor
        constraintEqualToAnchor:self.trailingAnchor],
    [_backgroundView.topAnchor constraintEqualToAnchor:self.topAnchor
                                              constant:GetChipVerticalMargin()],
    [_backgroundView.bottomAnchor
        constraintEqualToAnchor:self.bottomAnchor
                       constant:-GetChipVerticalMargin()]
  ]];

  self.translatesAutoresizingMaskIntoConstraints = NO;

  self.titleLabel.adjustsFontForContentSizeCategory = YES;

  [self updateTitleLabelFont];

  UIButtonConfiguration* buttonConfiguration =
      [UIButtonConfiguration plainButtonConfiguration];
  buttonConfiguration.contentInsets = [self chipNSDirectionalEdgeInsets];
  buttonConfiguration.baseForegroundColor =
      [UIColor colorNamed:kTextPrimaryColor];
  self.configuration = buttonConfiguration;
}

- (void)updateTitleLabelFont {
  // With the Keyboard Accessory Upgrade feature, the title's font is applied
  // through the button's `attributedTitle`.
  if (IsKeyboardAccessoryUpgradeEnabled()) {
    return;
  }

  UIFont* font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
  UIFontDescriptor* boldFontDescriptor = [font.fontDescriptor
      fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
  DCHECK(boldFontDescriptor);
  self.titleLabel.font = [UIFont fontWithDescriptor:boldFontDescriptor size:0];
}

@end