chromium/ios/chrome/browser/find_bar/ui_bundled/find_bar_view.mm

// Copyright 2018 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/find_bar/ui_bundled/find_bar_view.h"

#import "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
#import "ios/chrome/browser/find_bar/ui_bundled/find_bar_constants.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/common/ui/util/constraints_ui_util.h"
#import "ios/chrome/common/ui/util/dynamic_type_util.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util_mac.h"

namespace {
// Horizontal padding betwee all elements (except the previous/next buttons).
const CGFloat kPadding = 8;
// Horizontal padding between the last button and the trailing edge in a
// Regular x Regular environment.
const CGFloat kIPadButtonEdgeSpacing = 17;
const CGFloat kInputFieldCornerRadius = 10;
const CGFloat kFontSize = 15;
const CGFloat kButtonFontSize = 17;
const CGFloat kInputFieldHeight = 36;
const CGFloat kButtonLength = 44;
}  // namespace

@interface FindBarView ()

// The overlay that shows number of results in format "1 of 13".
@property(nonatomic, strong) UILabel* resultsCountLabel;

@end

@implementation FindBarView

@synthesize inputField = _inputField;
@synthesize previousButton = _previousButton;
@synthesize nextButton = _nextButton;
@synthesize closeButton = _closeButton;
@synthesize resultsCountLabel = _resultsCountLabel;

#pragma mark - Public

- (instancetype)init {
  self = [super initWithFrame:CGRectZero];
  return self;
}

- (void)updateResultsLabelWithText:(NSString*)text {
  self.resultsCountLabel.hidden = (text.length == 0);
  self.resultsCountLabel.text = text;
}

- (void)didMoveToSuperview {
  [super didMoveToSuperview];

  if (self.inputField.superview)
    return;

  [self setupSubviews];
  [self setupConstraints];
}

- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
  [super traitCollectionDidChange:previousTraitCollection];
  [self updateFonts];
}

#pragma mark - Private

// Creates, adds and configures the subviews.
- (void)setupSubviews {
  [self addLabel:self.resultsCountLabel asRightViewOfTextField:self.inputField];
  [self addSubview:self.inputField];
  [self addSubview:self.previousButton];
  [self addSubview:self.nextButton];
  [self addSubview:self.closeButton];

  [self setupColors];
  [self updateFonts];
}

// Sets the constraints for the subviews up.
// The subviews layout is the following:
// |-[inputField]-[previousButton][nextButton]-[closeButton]-|
- (void)setupConstraints {
  id<LayoutGuideProvider> safeArea = self.safeAreaLayoutGuide;

  [self.closeButton
      setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh + 1
                                      forAxis:UILayoutConstraintAxisHorizontal];
  [self.inputField setContentHuggingPriority:UILayoutPriorityDefaultLow - 1
                                     forAxis:UILayoutConstraintAxisHorizontal];

  const CGFloat closeButtonTrailingPadding =
      ShouldShowCompactToolbar(self) ? kPadding : kIPadButtonEdgeSpacing;

  NSLayoutConstraint* inputFieldHeightConstraint = [self.inputField.heightAnchor
      constraintEqualToConstant:kInputFieldHeight];

  [NSLayoutConstraint activateConstraints:@[
    // Input Field.
    [self.inputField.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
    inputFieldHeightConstraint,
    [self.inputField.leadingAnchor
        constraintEqualToAnchor:safeArea.leadingAnchor
                       constant:kPadding],
    [self.inputField.trailingAnchor
        constraintEqualToAnchor:self.previousButton.leadingAnchor
                       constant:-kPadding],

    // Previous Button.
    [self.previousButton.centerYAnchor
        constraintEqualToAnchor:self.centerYAnchor],
    [self.previousButton.widthAnchor constraintEqualToConstant:kButtonLength],
    [self.previousButton.heightAnchor constraintEqualToConstant:kButtonLength],

    [self.previousButton.trailingAnchor
        constraintEqualToAnchor:self.nextButton.leadingAnchor],

    // Next Button.
    [self.nextButton.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
    [self.nextButton.widthAnchor constraintEqualToConstant:kButtonLength],
    [self.nextButton.heightAnchor constraintEqualToConstant:kButtonLength],

    [self.nextButton.trailingAnchor
        constraintEqualToAnchor:self.closeButton.leadingAnchor
                       constant:-kPadding],

    // Close Button.
    [self.closeButton.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
    [self.closeButton.heightAnchor constraintEqualToConstant:kButtonLength],
    // Use button intrinsic width.
    [self.closeButton.trailingAnchor
        constraintEqualToAnchor:safeArea.trailingAnchor
                       constant:-closeButtonTrailingPadding],
  ]];
}

// Sets the colors for the different subviews.
- (void)setupColors {
  UIColor* inputFieldBackground =
      [UIColor colorNamed:kTextfieldBackgroundColor];
  UIColor* inputFieldPlaceHolderTextColor =
      [UIColor colorNamed:kTextfieldPlaceholderColor];
  UIColor* inputFieldTextColor = [UIColor colorNamed:kTextPrimaryColor];
  UIColor* resultsCountLabelTextColor =
      [UIColor colorNamed:kTextfieldPlaceholderColor];
  UIColor* buttonTintColor = [UIColor colorNamed:kBlueColor];

  self.inputField.backgroundColor = inputFieldBackground;
  NSString* placeholder = [self.inputField placeholder];
  NSDictionary* attributes =
      @{NSForegroundColorAttributeName : inputFieldPlaceHolderTextColor};
  [self.inputField setAttributedPlaceholder:[[NSAttributedString alloc]
                                                initWithString:placeholder
                                                    attributes:attributes]];
  self.inputField.textColor = inputFieldTextColor;
  self.inputField.tintColor = buttonTintColor;

  // Results count.
  self.resultsCountLabel.textColor = resultsCountLabelTextColor;

  // Buttons.
  self.previousButton.tintColor = buttonTintColor;
  self.nextButton.tintColor = buttonTintColor;
  self.closeButton.tintColor = buttonTintColor;
}

#pragma mark - Configuration

// Update fonts to account for new preferred content size category.
- (void)updateFonts {
  _inputField.font = PreferredFontForTextStyleWithMaxCategory(
      UIFontTextStyleBody, self.traitCollection.preferredContentSizeCategory,
      UIContentSizeCategoryAccessibilityLarge);
  _resultsCountLabel.font = PreferredFontForTextStyleWithMaxCategory(
      UIFontTextStyleBody, self.traitCollection.preferredContentSizeCategory,
      UIContentSizeCategoryAccessibilityMedium);
  _closeButton.titleLabel.font = PreferredFontForTextStyleWithMaxCategory(
      UIFontTextStyleBody, self.traitCollection.preferredContentSizeCategory,
      UIContentSizeCategoryAccessibilityMedium);
}

// Adds `rightLabel` as right view of the `textField`.
- (void)addLabel:(UILabel*)rightLabel
    asRightViewOfTextField:(UITextField*)textField {
  UIView* rightView = [[UIView alloc] init];
  rightView.userInteractionEnabled = NO;
  rightView.translatesAutoresizingMaskIntoConstraints = NO;
  [rightView addSubview:rightLabel];
  AddSameConstraintsToSidesWithInsets(
      rightLabel, rightView,
      LayoutSides::kTop | LayoutSides::kBottom | LayoutSides::kLeading |
          LayoutSides::kTrailing,
      NSDirectionalEdgeInsetsMake(0, kPadding, 0, kPadding));
  textField.rightView = rightView;
  textField.rightViewMode = UITextFieldViewModeAlways;
}

#pragma mark - Property accessors

// Creates and returns the input text field.
- (UITextField*)inputField {
  if (!_inputField) {
    _inputField = [[UITextField alloc] init];
    UIView* leftPadding =
        [[UIView alloc] initWithFrame:CGRectMake(0, 0, kPadding, 0)];
    leftPadding.userInteractionEnabled = NO;
    _inputField.leftView = leftPadding;
    _inputField.leftViewMode = UITextFieldViewModeAlways;

    _inputField.layer.cornerRadius = kInputFieldCornerRadius;
    _inputField.translatesAutoresizingMaskIntoConstraints = NO;
    _inputField.placeholder =
        l10n_util::GetNSString(IDS_IOS_PLACEHOLDER_FIND_IN_PAGE);
    _inputField.font = [UIFont systemFontOfSize:kFontSize];
    _inputField.accessibilityIdentifier = kFindInPageInputFieldId;
  }
  return _inputField;
}

// Creates and returns the results count label.
- (UILabel*)resultsCountLabel {
  if (!_resultsCountLabel) {
    _resultsCountLabel = [[UILabel alloc] init];
    _resultsCountLabel.translatesAutoresizingMaskIntoConstraints = NO;
    _resultsCountLabel.font = [UIFont systemFontOfSize:kFontSize];
    _resultsCountLabel.accessibilityElementsHidden = YES;
    _resultsCountLabel.accessibilityIdentifier = kFindInPageResultsCountLabelId;
  }

  return _resultsCountLabel;
}

// Creates and returns the previous button.
- (UIButton*)previousButton {
  if (!_previousButton) {
    _previousButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [_previousButton
        setImage:[[UIImage imageNamed:@"find_prev"]
                     imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]
        forState:UIControlStateNormal];
    _previousButton.translatesAutoresizingMaskIntoConstraints = NO;
    SetA11yLabelAndUiAutomationName(_previousButton,
                                    IDS_FIND_IN_PAGE_PREVIOUS_TOOLTIP,
                                    kFindInPagePreviousButtonId);
    _previousButton.pointerInteractionEnabled = YES;
  }

  return _previousButton;
}

// Creates and returns the next button.
- (UIButton*)nextButton {
  if (!_nextButton) {
    _nextButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [_nextButton
        setImage:[[UIImage imageNamed:@"find_next"]
                     imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]
        forState:UIControlStateNormal];
    _nextButton.translatesAutoresizingMaskIntoConstraints = NO;
    SetA11yLabelAndUiAutomationName(_nextButton, IDS_FIND_IN_PAGE_NEXT_TOOLTIP,
                                    kFindInPageNextButtonId);
    _nextButton.pointerInteractionEnabled = YES;
  }

  return _nextButton;
}

// Creates and returns the closes button.
- (UIButton*)closeButton {
  if (!_closeButton) {
    _closeButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [_closeButton setTitle:l10n_util::GetNSString(IDS_DONE)
                  forState:UIControlStateNormal];
    _closeButton.translatesAutoresizingMaskIntoConstraints = NO;
    _closeButton.accessibilityIdentifier = kFindInPageCloseButtonId;
    _closeButton.titleLabel.font = [UIFont systemFontOfSize:kButtonFontSize];
    _closeButton.pointerInteractionEnabled = YES;
  }

  return _closeButton;
}

@end