chromium/ios/chrome/browser/ui/settings/cells/enhanced_safe_browsing_inline_promo_item.mm

// Copyright 2024 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/settings/cells/enhanced_safe_browsing_inline_promo_item.h"

#import "base/apple/foundation_util.h"
#import "ios/chrome/browser/shared/public/commands/settings_commands.h"
#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
#import "ios/chrome/browser/ui/settings/privacy/safe_browsing/enhanced_safe_browsing_inline_promo_delegate.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/grit/ios_branded_strings.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util.h"

namespace {
// Height of the close button.
constexpr CGFloat kCloseButtonHeightSize = 24;

// The padding to the right of the close button.
constexpr CGFloat kCloseButtonHorizontalOffset = 12;

// The close button's padding to its top.
constexpr CGFloat kCloseButtonVerticalOffset = 16;

// Height and width of the shield image.
constexpr CGFloat kShieldImageSize = 36;

// The top padding for the inline promo.
constexpr CGFloat kInlinePromoVerticalPadding = 24;

// The side padding for the inline promo.
constexpr CGFloat kInlinePromoHorizontalPadding = 30;

// The UIStack spacing.
constexpr CGFloat kStackSpacing = 14;

// Creates the UIButton that dismisses the inline promo from view.
UIButton* CreateCloseButton() {
  UIButton* closeButton = [UIButton buttonWithType:UIButtonTypeSystem];
  closeButton.translatesAutoresizingMaskIntoConstraints = NO;
  closeButton.accessibilityLabel = l10n_util::GetNSString(IDS_IOS_ICON_CLOSE);

  UIImageSymbolConfiguration* symbolConfiguration = [UIImageSymbolConfiguration
      configurationWithPointSize:kCloseButtonHeightSize
                          weight:UIImageSymbolWeightRegular
                           scale:UIImageSymbolScaleSmall];

  UIButtonConfiguration* buttonConfiguration =
      [UIButtonConfiguration plainButtonConfiguration];
  buttonConfiguration.image =
      DefaultSymbolWithConfiguration(kXMarkSymbol, symbolConfiguration);
  buttonConfiguration.baseForegroundColor =
      [UIColor colorNamed:kSolidBlackColor];
  closeButton.configuration = buttonConfiguration;

  return closeButton;
}

// Creates a UIImageView containing either branded or unbranded shield image.
UIImageView* CreateShieldImage() {
#if BUILDFLAG(IOS_USE_BRANDED_SYMBOLS)
  NSString* shieldSymbol = kGoogleShieldSymbol;
#else
  NSString* shieldSymbol = kShieldSymbol;
#endif

  UIImage* image = [UIImage imageNamed:shieldSymbol];

  return [[UIImageView alloc] initWithImage:image];
}

// Creates a UIButton that redirects the user to the Safe Browsing settings
// page.
UIButton* CreatePrimaryButton() {
  UIButton* primaryButton = [UIButton buttonWithType:UIButtonTypeSystem];
  primaryButton.translatesAutoresizingMaskIntoConstraints = NO;
  primaryButton.accessibilityLabel = l10n_util::GetNSString(
      IDS_IOS_SAFE_BROWSING_ENHANCED_PROTECTION_INLINE_PROMO_BUTTON_TEXT);
  UIFont* font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
  NSDictionary* attributes =
      [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];

  UIButtonConfiguration* buttonConfiguration =
      [UIButtonConfiguration plainButtonConfiguration];
  buttonConfiguration.attributedTitle = [[NSAttributedString alloc]
      initWithString:
          l10n_util::GetNSString(
              IDS_IOS_SAFE_BROWSING_ENHANCED_PROTECTION_INLINE_PROMO_BUTTON_TEXT)
          attributes:attributes];
  buttonConfiguration.baseForegroundColor =
      [UIColor colorNamed:kSolidWhiteColor];
  buttonConfiguration.background.backgroundColor =
      [UIColor colorNamed:kBlue600Color];
  primaryButton.configuration = buttonConfiguration;

  return primaryButton;
}

// Creates a UILabel containing the description of the inline promo.
UILabel* CreateLabel() {
  UILabel* textLabel = [[UILabel alloc] init];
  textLabel.text = l10n_util::GetNSString(
      IDS_IOS_SAFE_BROWSING_ENHANCED_PROTECTION_INLINE_PROMO_DESCRIPTION);
  textLabel.lineBreakMode = NSLineBreakByWordWrapping;
  textLabel.numberOfLines = 0;
  textLabel.textAlignment = NSTextAlignmentCenter;
  textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];

  return textLabel;
}
}  // namespace

@implementation EnhancedSafeBrowsingInlinePromoItem

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

#pragma mark - CollectionViewItem

- (void)configureCell:(EnhancedSafeBrowsingInlinePromoCell*)cell
           withStyler:(ChromeTableViewStyler*)styler {
  [super configureCell:cell withStyler:styler];
  cell.delegate = self.delegate;
  [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}

@end

@implementation EnhancedSafeBrowsingInlinePromoCell

#pragma mark - EnhancedSafeBrowsingInlinePromoCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style
              reuseIdentifier:(NSString*)reuseIdentifier {
  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  if (self) {
    UIButton* closeButton = CreateCloseButton();
    [closeButton addTarget:self
                    action:@selector(dismissPromo)
          forControlEvents:UIControlEventTouchUpInside];
    UIImageView* shield = CreateShieldImage();
    UIButton* primaryButton = CreatePrimaryButton();
    [primaryButton addTarget:self
                      action:@selector(showSafeBrowsingSettings)
            forControlEvents:UIControlEventTouchUpInside];
    UILabel* textLabel = CreateLabel();
    [self.contentView addSubview:closeButton];

    UIStackView* stack = [[UIStackView alloc]
        initWithArrangedSubviews:@[ shield, textLabel, primaryButton ]];
    stack.translatesAutoresizingMaskIntoConstraints = NO;
    stack.axis = UILayoutConstraintAxisVertical;
    stack.distribution = UIStackViewDistributionEqualSpacing;
    stack.alignment = UIStackViewAlignmentCenter;
    stack.spacing = kStackSpacing;

    [self.contentView addSubview:stack];

    NSUInteger verticalPadding = 2 * kInlinePromoVerticalPadding;
    [NSLayoutConstraint activateConstraints:@[
      [self.contentView.heightAnchor constraintEqualToAnchor:stack.heightAnchor
                                                    constant:verticalPadding],
      [stack.leadingAnchor
          constraintEqualToAnchor:self.contentView.leadingAnchor
                         constant:kInlinePromoHorizontalPadding],
      [stack.trailingAnchor
          constraintEqualToAnchor:self.contentView.trailingAnchor
                         constant:-kInlinePromoHorizontalPadding],
      [stack.topAnchor constraintEqualToAnchor:self.contentView.topAnchor
                                      constant:kInlinePromoVerticalPadding],
      [shield.heightAnchor constraintEqualToConstant:kShieldImageSize],
      [shield.widthAnchor constraintEqualToAnchor:shield.heightAnchor],
      [primaryButton.widthAnchor constraintEqualToAnchor:stack.widthAnchor],
      [closeButton.heightAnchor
          constraintEqualToConstant:kCloseButtonHeightSize],
      [closeButton.widthAnchor
          constraintEqualToAnchor:closeButton.heightAnchor],
      [closeButton.trailingAnchor
          constraintEqualToAnchor:self.contentView.trailingAnchor
                         constant:-kCloseButtonHorizontalOffset],
      [closeButton.topAnchor
          constraintEqualToAnchor:self.contentView.topAnchor
                         constant:kCloseButtonVerticalOffset],
    ]];
  }
  return self;
}

#pragma mark - UITableViewCell

- (void)prepareForReuse {
  [super prepareForReuse];
  self.delegate = nil;
}

#pragma mark - Private

// Invokes the delegate's promo dismissal functionality when the close button is
// tapped.
- (void)dismissPromo {
  [self.delegate dismissEnhancedSafeBrowsingInlinePromo];
}

// Displays the Safe Browsing Settings UI via the `delegate`.
- (void)showSafeBrowsingSettings {
  [self.delegate showSafeBrowsingSettingsMenu];
}

@end