chromium/ios/chrome/browser/parcel_tracking/ui_bundled/parcel_tracking_opt_in_view_controller.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/parcel_tracking/ui_bundled/parcel_tracking_opt_in_view_controller.h"

#import "base/notreached.h"
#import "ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.h"
#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_item.h"
#import "ios/chrome/browser/parcel_tracking/ui_bundled/parcel_tracking_opt_in_view_controller_delegate.h"
#import "ios/chrome/common/string_util.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/ui_util.h"
#import "ios/chrome/grit/ios_branded_strings.h"
#import "ios/chrome/grit/ios_strings.h"
#import "net/base/apple/url_conversions.h"
#import "ui/base/l10n/l10n_util_mac.h"
#import "url/gurl.h"

namespace {
// Name of the parcel tracking icon.
NSString* const kOptInIcon = @"parcel_tracking_icon_new";
// Radius size of the table view.
CGFloat const kTableViewCornerRadius = 10;
// Spacing before the image.
CGFloat const kSpacingBeforeImage = 23;
// Size of the radio buttons.
CGFloat const kRadioButtonSize = 20;
}  // namespace

@interface ParcelTrackingOptInViewController () <UITableViewDelegate,
                                                 UITextViewDelegate,
                                                 UITableViewDataSource>

@end

@implementation ParcelTrackingOptInViewController {
  UITableView* _tableView;
  IOSParcelTrackingOptInStatus _selection;
  NSLayoutConstraint* _tableViewHeightConstraint;
}

- (void)viewDidLoad {
  UIView* tableView = [self createTableView];
  self.underTitleView = tableView;
  self.titleString =
      l10n_util::GetNSString(IDS_IOS_PARCEL_TRACKING_OPT_IN_TITLE);
  self.primaryActionString =
      l10n_util::GetNSString(IDS_IOS_PARCEL_TRACKING_OPT_IN_ENABLE_TRACKING);
  self.secondaryActionString =
      l10n_util::GetNSString(IDS_IOS_PARCEL_TRACKING_OPT_IN_SECONDARY_ACTION);
  self.titleTextStyle = UIFontTextStyleTitle2;
  self.subtitleString =
      l10n_util::GetNSString(IDS_IOS_PARCEL_TRACKING_OPT_IN_SUBTITLE);
  self.subtitleTextStyle = UIFontTextStyleCallout;
  self.showDismissBarButton = NO;
  self.image = [UIImage imageNamed:kOptInIcon];
  self.imageHasFixedSize = true;
  self.topAlignedLayout = YES;
  self.customSpacingAfterImage = 0;
  self.customSpacingBeforeImageIfNoNavigationBar = kSpacingBeforeImage;
  [super viewDidLoad];

  // Assign table view's width anchor now that it is in the same hierarchy as
  // the top view.
  [NSLayoutConstraint activateConstraints:@[
    [tableView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
    [tableView.widthAnchor
        constraintEqualToAnchor:tableView.superview.widthAnchor],
  ]];

  [self setPrimaryButtonConfiguration];
  self.primaryActionButton.enabled = NO;
}

- (void)viewWillLayoutSubviews {
  [super viewWillLayoutSubviews];
  [self updateTableViewHeightConstraint];
}

#pragma mark - ConfirmationAlertViewController

- (void)customizeSubtitle:(UITextView*)subtitle {
  NSMutableParagraphStyle* paragraphStyle =
      [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
  paragraphStyle.alignment = NSTextAlignmentCenter;
  NSDictionary* textAttributes = @{
    NSForegroundColorAttributeName : [UIColor colorNamed:kTextSecondaryColor],
    NSFontAttributeName :
        [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline],
    NSParagraphStyleAttributeName : paragraphStyle,
  };
  NSDictionary* linkAttributes = @{
    NSLinkAttributeName : net::NSURLWithGURL(GURL("chrome://settings")),
    NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle)
  };
  subtitle.attributedText = AttributedStringFromStringWithLink(
      l10n_util::GetNSString(IDS_IOS_PARCEL_TRACKING_OPT_IN_SUBTITLE),
      textAttributes, linkAttributes);
  subtitle.delegate = self;
  subtitle.selectable = YES;
  subtitle.textContainer.lineFragmentPadding = 0;
}

#pragma mark - ConfirmationAlertActionHandler

- (void)confirmationAlertPrimaryAction {
  switch (_selection) {
    case IOSParcelTrackingOptInStatus::kAlwaysTrack:
      [self.delegate alwaysTrackTapped];
      break;
    case IOSParcelTrackingOptInStatus::kAskToTrack:
      [self.delegate askToTrackTapped];
      break;
    case IOSParcelTrackingOptInStatus::kNeverTrack:
    case IOSParcelTrackingOptInStatus::kStatusNotSet:
      NOTREACHED_IN_MIGRATION();
      break;
  }
}

- (void)confirmationAlertSecondaryAction {
  [self.delegate noThanksTapped];
}

#pragma mark - UITextViewDelegate

- (BOOL)textView:(UITextView*)textView
    shouldInteractWithURL:(NSURL*)URL
                  inRange:(NSRange)characterRange
              interaction:(UITextItemInteraction)interaction {
  [self.delegate parcelTrackingSettingsPageLinkTapped];
  return NO;
}

#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView*)tableView
    numberOfRowsInSection:(NSInteger)section {
  return 2;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {
  return 1;
}

- (UITableViewCell*)tableView:(UITableView*)tableView
        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
  TableViewTextCell* cell =
      [tableView dequeueReusableCellWithIdentifier:@"cell"];

  NSString* title = indexPath.row == 0
                        ? l10n_util::GetNSString(
                              IDS_IOS_PARCEL_TRACKING_OPT_IN_PRIMARY_ACTION)
                        : l10n_util::GetNSString(
                              IDS_IOS_PARCEL_TRACKING_OPT_IN_TERTIARY_ACTION);
  cell.selectionStyle = UITableViewCellSelectionStyleNone;
  cell.backgroundColor = [UIColor colorNamed:kSecondaryBackgroundColor];
  cell.userInteractionEnabled = YES;
  cell.textLabel.text = title;
  cell.isAccessibilityElement = YES;
  cell.accessibilityLabel = cell.textLabel.text;
  cell.accessibilityTraits =
      [self accessibilityTraitsForButton:/*selected=*/NO];

  cell.accessoryView =
      [[UIImageView alloc] initWithImage:DefaultSymbolTemplateWithPointSize(
                                             kCircleSymbol, kRadioButtonSize)];
  cell.accessoryView.tintColor = [UIColor colorNamed:kGrey500Color];

  // Make separator invisible on second cell.
  if (indexPath.row > 0) {
    cell.separatorInset =
        UIEdgeInsetsMake(0.f, tableView.frame.size.width, 0.f, 0.f);
  }

  return cell;
}

#pragma mark - UITableViewDelegate

- (void)tableView:(UITableView*)tableView
    didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
  _selection = indexPath.row == 0 ? IOSParcelTrackingOptInStatus::kAlwaysTrack
                                  : IOSParcelTrackingOptInStatus::kAskToTrack;
  UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
  UIImage* icon;
  if (@available(iOS 16.0, *)) {
    icon = DefaultSymbolWithPointSize(kButtonProgrammableSymbol,
                                      kSymbolAccessoryPointSize);
  } else {
    icon = DefaultSymbolWithPointSize(kCircleCircleFillSymbol,
                                      kSymbolAccessoryPointSize);
  }
  cell.accessoryView = [[UIImageView alloc] initWithImage:icon];
  cell.accessoryView.tintColor = [UIColor colorNamed:kBlueColor];
  self.primaryActionButton.enabled = YES;
  cell.accessibilityTraits =
      [self accessibilityTraitsForButton:/*selected=*/YES];
}

- (void)tableView:(UITableView*)tableView
    didDeselectRowAtIndexPath:(NSIndexPath*)indexPath {
  UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
  cell.accessoryView = [[UIImageView alloc]
      initWithImage:DefaultSymbolTemplateWithPointSize(
                        kCircleSymbol, kSymbolAccessoryPointSize)];
  cell.accessoryView.tintColor = [UIColor colorNamed:kGrey500Color];
  cell.accessibilityTraits =
      [self accessibilityTraitsForButton:/*selected=*/NO];
}

#pragma mark - Private

// Creates the view with the "always track" and "ask to track" options.
- (UITableView*)createTableView {
  _tableView = [[UITableView alloc] initWithFrame:CGRectZero
                                            style:UITableViewStylePlain];
  _tableView.layer.cornerRadius = kTableViewCornerRadius;
  _tableView.estimatedRowHeight = UITableViewAutomaticDimension;
  _tableView.scrollEnabled = NO;
  _tableView.showsVerticalScrollIndicator = NO;
  _tableView.delegate = self;
  _tableView.userInteractionEnabled = YES;
  _tableView.translatesAutoresizingMaskIntoConstraints = NO;
  _tableView.dataSource = self;
  _tableView.separatorInset = UIEdgeInsetsZero;
  [_tableView registerClass:TableViewTextCell.class
      forCellReuseIdentifier:@"cell"];
  _tableViewHeightConstraint =
      [_tableView.heightAnchor constraintEqualToConstant:0];
  _tableViewHeightConstraint.active = YES;

  return _tableView;
}

// Updates the tableView's height constraint.
- (void)updateTableViewHeightConstraint {
  CGFloat totalCellHeight = 0;
  for (UITableViewCell* cell in _tableView.visibleCells) {
    totalCellHeight += cell.frame.size.height;
  }
  _tableViewHeightConstraint.constant = totalCellHeight;
}

// Sets the configurationUpdateHandler for the primaryActionButton to handle the
// button's state changes. The button should be disabled initially and only
// enabled after an option, either "always track" or "ask to track", has been
// selected by the user.
- (void)setPrimaryButtonConfiguration {
  UIButton* button = self.primaryActionButton;
  button.configurationUpdateHandler = ^(UIButton* incomingButton) {
    UIButtonConfiguration* updatedConfig = incomingButton.configuration;
    switch (incomingButton.state) {
      case UIControlStateDisabled: {
        updatedConfig.background.backgroundColor =
            [UIColor colorNamed:kGrey200Color];
        updatedConfig.baseForegroundColor = [UIColor colorNamed:kGrey600Color];
        break;
      }
      case UIControlStateNormal: {
        updatedConfig.background.backgroundColor =
            [UIColor colorNamed:kBlueColor];
        updatedConfig.baseForegroundColor =
            [UIColor colorNamed:kBackgroundColor];
        break;
      }
      default:
        break;
    }
    incomingButton.configuration = updatedConfig;
  };
}

// Returns the accessibility traits for the radio button options. `selected`
// should be true if the radio button is selected.
- (UIAccessibilityTraits)accessibilityTraitsForButton:(BOOL)selected {
  UIAccessibilityTraits accessibilityTraits = UIAccessibilityTraitButton;
  if (selected) {
    accessibilityTraits |= UIAccessibilityTraitSelected;
  }
  return accessibilityTraits;
}

@end