chromium/ios/chrome/browser/bring_android_tabs/ui_bundled/tab_list_from_android_table_view_item.mm

// Copyright 2023 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/bring_android_tabs/ui_bundled/tab_list_from_android_table_view_item.h"

#import "base/apple/foundation_util.h"
#import "base/strings/sys_string_conversions.h"
#import "components/url_formatter/elide_url.h"
#import "ios/chrome/browser/net/model/crurl.h"
#import "ios/chrome/browser/bring_android_tabs/ui_bundled/constants.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/common/ui/favicon/favicon_container_view.h"
#import "ios/chrome/common/ui/favicon/favicon_view.h"
#import "ios/chrome/common/ui/table_view/table_view_cells_constants.h"

@implementation TabListFromAndroidTableViewItem

- (instancetype)initWithType:(NSInteger)type {
  if ((self = [super initWithType:type])) {
    self.cellClass = [TabListFromAndroidTableViewCell class];
  }
  return self;
}

- (void)configureCell:(TableViewCell*)tableCell
           withStyler:(ChromeTableViewStyler*)styler {
  [super configureCell:tableCell withStyler:styler];

  TabListFromAndroidTableViewCell* cell =
      base::apple::ObjCCastStrict<TabListFromAndroidTableViewCell>(tableCell);
  cell.titleLabel.text = [self titleLabelText];
  cell.URLLabel.text = [self URLLabelText];
  cell.cellUniqueIdentifier = self.uniqueIdentifier;
  cell.accessibilityTraits |= UIAccessibilityTraitButton;
}

- (NSString*)uniqueIdentifier {
  return self.URL ? base::SysUTF8ToNSString(self.URL.gurl.host()) : @"";
}

#pragma mark - Private

// Returns the text to use when configuring a TabListFromAndroidTableViewCell's
// title label.
- (NSString*)titleLabelText {
  if (self.title.length) {
    return self.title;
  }
  if (!self.URL) {
    return @"";
  }
  NSString* hostname = [self displayedURL];
  if (hostname.length) {
    return hostname;
  }
  // Backup in case host returns nothing (e.g. about:blank).
  return base::SysUTF8ToNSString(self.URL.gurl.spec());
}

// Returns the text to use when configuring a TabListFromAndroidTableViewCell's
// URL label.
- (NSString*)URLLabelText {
  return self.URL ? [self displayedURL] : @"";
}

// Returns a formatted URL text.
- (NSString*)displayedURL {
  return base::SysUTF16ToNSString(
      url_formatter::
          FormatUrlForDisplayOmitSchemePathTrivialSubdomainsAndMobilePrefix(
              self.URL.gurl));
}

@end

@implementation TabListFromAndroidTableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style
              reuseIdentifier:(NSString*)reuseIdentifier {
  if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
    _faviconView = [[FaviconView alloc] init];
    _titleLabel = [[UILabel alloc] init];
    _URLLabel = [[UILabel alloc] init];
    self.isAccessibilityElement = YES;
  }
  return self;
}

#pragma mark - UIView

- (void)willMoveToSuperview:(UIView*)newSuperview {
  [super willMoveToSuperview:newSuperview];

  [self createSubviews];
}

#pragma mark - Accessors

- (NSString*)accessibilityLabel {
  NSString* accessibilityLabel = self.titleLabel.text;
  accessibilityLabel = [NSString
      stringWithFormat:@"%@, %@", accessibilityLabel, self.URLLabel.text];
  return accessibilityLabel;
}

- (NSArray<NSString*>*)accessibilityUserInputLabels {
  NSMutableArray<NSString*>* userInputLabels = [[NSMutableArray alloc] init];
  if (self.titleLabel.text) {
    [userInputLabels addObject:self.titleLabel.text];
  }
  return userInputLabels;
}

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

#pragma mark - Private

// Creates and lays out the favicon, title, and URL subviews.
- (void)createSubviews {
  // Return if the subviews have already been created and added.
  if (self.contentView.subviews.count != 0) {
    return;
  }
  FaviconContainerView* faviconContainerView = [self faviconContainerView];
  UIStackView* verticalStack = [self stackView];

  UIView* contentView = self.contentView;
  contentView.frame = self.frame;
  [contentView addSubview:faviconContainerView];
  [contentView addSubview:verticalStack];

  NSLayoutConstraint* heightConstraint = [contentView.heightAnchor
      constraintGreaterThanOrEqualToConstant:kTabListFromAndroidCellHeight];
  // Don't set the priority to required to avoid clashing with the estimated
  // height.
  heightConstraint.priority = UILayoutPriorityRequired - 1;

  CGFloat faviconContainerSize = kBringAndroidTabsFaviconSize + 3;

  [NSLayoutConstraint activateConstraints:@[
    [faviconContainerView.leadingAnchor
        constraintEqualToAnchor:contentView.leadingAnchor
                       constant:kTableViewHorizontalSpacing],
    [faviconContainerView.centerYAnchor
        constraintEqualToAnchor:contentView.centerYAnchor],
    [faviconContainerView.widthAnchor
        constraintEqualToConstant:faviconContainerSize],
    [faviconContainerView.heightAnchor
        constraintEqualToAnchor:faviconContainerView.widthAnchor],

    [_faviconView.widthAnchor
        constraintEqualToConstant:kBringAndroidTabsFaviconSize],
    [_faviconView.heightAnchor
        constraintEqualToAnchor:_faviconView.widthAnchor],
    [_faviconView.centerYAnchor
        constraintEqualToAnchor:faviconContainerView.centerYAnchor],
    [_faviconView.centerXAnchor
        constraintEqualToAnchor:faviconContainerView.centerXAnchor],

    [verticalStack.leadingAnchor
        constraintEqualToAnchor:faviconContainerView.trailingAnchor
                       constant:kTableViewSubViewHorizontalSpacing],
    [verticalStack.trailingAnchor
        constraintEqualToAnchor:contentView.trailingAnchor
                       constant:-kTableViewHorizontalSpacing],
    [verticalStack.centerYAnchor
        constraintEqualToAnchor:contentView.centerYAnchor],
    [verticalStack.topAnchor
        constraintGreaterThanOrEqualToAnchor:contentView.topAnchor
                                    constant:
                                        kTableViewTwoLabelsCellVerticalSpacing],
    [verticalStack.bottomAnchor
        constraintLessThanOrEqualToAnchor:contentView.bottomAnchor
                                 constant:
                                     -kTableViewTwoLabelsCellVerticalSpacing],
    heightConstraint
  ]];
}

// Creates and returns the vertical stack view. The stack consists of a title
// and URL.
- (UIStackView*)stackView {
  _titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
  _titleLabel.adjustsFontForContentSizeCategory = YES;
  _titleLabel.numberOfLines = 2;
  _URLLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
  _URLLabel.adjustsFontForContentSizeCategory = YES;
  _URLLabel.textColor = [UIColor colorNamed:kTextSecondaryColor];

  UIStackView* verticalStack = [[UIStackView alloc]
      initWithArrangedSubviews:@[ _titleLabel, _URLLabel ]];
  verticalStack.axis = UILayoutConstraintAxisVertical;
  verticalStack.translatesAutoresizingMaskIntoConstraints = NO;
  return verticalStack;
}

// Creates and returns the container for the favicon view.
- (FaviconContainerView*)faviconContainerView {
  FaviconContainerView* faviconContainerView =
      [[FaviconContainerView alloc] init];
  [faviconContainerView addSubview:_faviconView];
  faviconContainerView.translatesAutoresizingMaskIntoConstraints = NO;
  _faviconView.translatesAutoresizingMaskIntoConstraints = NO;
  _faviconView.contentMode = UIViewContentModeScaleAspectFill;
  _faviconView.clipsToBounds = YES;
  _faviconView.layer.masksToBounds = YES;
  return faviconContainerView;
}

@end