chromium/ios/chrome/browser/ui/reading_list/text_badge_view.mm

// Copyright 2017 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/ui/reading_list/text_badge_view.h"

#import "base/check.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"

namespace {
const CGFloat kFontSize = 11.0f;
// The margin between the top and bottom of the label and the badge.
const CGFloat kLabelVerticalMargin = 2.5f;
// The default value for the margin between the sides of the label and the
// badge.
const CGFloat kDefaultLabelHorizontalMargin = 8.5f;
}

@interface TextBadgeView ()
// Label containing the text displayed on the badge.
@property(nonatomic, strong) UILabel* label;
// The margin between the sides of the label and the badge.
@property(nonatomic, assign, readonly) CGFloat labelHorizontalMargin;
// Indicate whether `label` has been added as a subview of the TextBadgeView.
@property(nonatomic, assign) BOOL didAddSubviews;
@end

@implementation TextBadgeView

@synthesize label = _label;
@synthesize labelHorizontalMargin = _labelHorizontalMargin;
@synthesize didAddSubviews = _didAddSubviews;

- (instancetype)initWithText:(NSString*)text
       labelHorizontalMargin:(CGFloat)margin {
  self = [super initWithFrame:CGRectZero];
  if (self) {
    _label = [TextBadgeView labelWithText:text];
    _labelHorizontalMargin = margin;
    _didAddSubviews = NO;
  }
  return self;
}

- (instancetype)initWithText:(NSString*)text {
  return [self initWithText:text
      labelHorizontalMargin:kDefaultLabelHorizontalMargin];
}

#pragma mark - UIView overrides

// Override `willMoveToSuperview` to add view properties to the view hierarchy
// and set the badge's appearance.
- (void)willMoveToSuperview:(UIView*)newSuperview {
  if (!self.didAddSubviews) {
    [self addSubview:self.label];
    self.didAddSubviews = YES;
    [self activateConstraints];
    [self setBackgroundColor:[UIColor colorNamed:kBlueHaloColor]];
    [self setAccessibilityLabel:self.label.text];
    self.isAccessibilityElement = YES;
  }
  [super willMoveToSuperview:newSuperview];
}

- (void)layoutSubviews {
  [super layoutSubviews];
  // Set the badge's corner radius to be one half of its height. This causes the
  // ends of the badge to be circular.
  self.layer.cornerRadius = self.bounds.size.height / 2.0f;
}

#pragma mark - Public properties

- (NSString*)text {
  return self.label.text;
}

- (void)setText:(NSString*)text {
  DCHECK(text.length);
  self.label.text = text;
}

#pragma mark - Private class methods

// Return a label that displays text in white with center alignment.
+ (UILabel*)labelWithText:(NSString*)text {
  UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
  [label
      setFont:[UIFont systemFontOfSize:kFontSize weight:UIFontWeightSemibold]];
  [label setTextColor:[UIColor colorNamed:kBlueColor]];
  [label setTranslatesAutoresizingMaskIntoConstraints:NO];
  [label setText:text];
  [label setTextAlignment:NSTextAlignmentCenter];
  return label;
}

#pragma mark - Private instance methods

// Activate constraints to properly position the badge and its subviews.
- (void)activateConstraints {
  // Make the badge width fit the label, adding a margin on both sides.
  NSLayoutConstraint* badgeWidthConstraint =
      [self.widthAnchor constraintEqualToAnchor:self.label.widthAnchor
                                       constant:self.labelHorizontalMargin * 2];
  // This constraint should not be satisfied if the label is taller than it is
  // wide, so make it optional.
  badgeWidthConstraint.priority = UILayoutPriorityDefaultHigh;

  [NSLayoutConstraint activateConstraints:@[
    // Center label on badge.
    [self.label.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
    [self.label.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
    // Make the badge height fit the label.
    [self.heightAnchor constraintEqualToAnchor:self.label.heightAnchor
                                      constant:kLabelVerticalMargin * 2],
    // Ensure that the badge will never be taller than it is wide. For
    // a tall label, the badge will look like a circle instead of an ellipse.
    [self.widthAnchor constraintGreaterThanOrEqualToAnchor:self.heightAnchor],
    badgeWidthConstraint
  ]];
}

@end