chromium/ios/chrome/browser/autofill/ui_bundled/card_name_fix_flow_view_bridge.mm

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import <memory>
#import <string>

#import "base/apple/foundation_util.h"
#import "base/memory/raw_ptr.h"
#import "base/strings/sys_string_conversions.h"
#import "base/values.h"
#import "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/shared/ui/list_model/list_model.h"
#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_edit_item.h"
#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_header_footer_item.h"
#import "ios/chrome/browser/shared/ui/util/rtl_geometry.h"
#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
#import "ios/chrome/browser/autofill/ui_bundled/card_name_fix_flow_view_bridge.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ui/base/l10n/l10n_util.h"

NSString* const kCellReuseID = @"ConfirmNameTableViewTextEditCell";
CGFloat const kMainSection = 0;
CGFloat const kNumberOfRowsInMainSection = 1;

namespace autofill {

#pragma mark CardNameFixFlowViewBridge

CardNameFixFlowViewBridge::CardNameFixFlowViewBridge(
    CardNameFixFlowController* controller,
    UIViewController* presenting_view_controller)
    : controller_(controller),
      presenting_view_controller_(presenting_view_controller) {
  DCHECK(controller_);
  DCHECK(presenting_view_controller_);
}

CardNameFixFlowViewBridge::~CardNameFixFlowViewBridge() {
  if (controller_)
    controller_->OnConfirmNameDialogClosed();
}

void CardNameFixFlowViewBridge::Show() {
  // Wrap CardNameFixFlowViewController with navigation controller to include
  // a navigation bar.
  view_controller_ = [[UINavigationController alloc]
      initWithRootViewController:[[CardNameFixFlowViewController alloc]
                                     initWithBridge:this]];
  [presenting_view_controller_ presentViewController:view_controller_
                                            animated:YES
                                          completion:nil];
}

void CardNameFixFlowViewBridge::ControllerGone() {
  controller_ = nullptr;
  PerformClose();
}

CardNameFixFlowController* CardNameFixFlowViewBridge::GetController() {
  return controller_;
}

void CardNameFixFlowViewBridge::OnConfirmedName(
    const std::u16string& confirmed_name) {
  controller_->OnNameAccepted(confirmed_name);
  PerformClose();
}

void CardNameFixFlowViewBridge::OnDismissed() {
  controller_->OnDismissed();
  PerformClose();
}

void CardNameFixFlowViewBridge::PerformClose() {
  base::WeakPtr<CardNameFixFlowViewBridge> weak_this =
      weak_ptr_factory_.GetWeakPtr();
  [view_controller_ dismissViewControllerAnimated:YES
                                       completion:^{
                                         if (weak_this) {
                                           weak_this->DeleteSelf();
                                         }
                                       }];
}

void CardNameFixFlowViewBridge::DeleteSelf() {
  delete this;
}

}  // namespace autofill

@interface CardNameFixFlowViewController () <UITextFieldDelegate,
                                             UITableViewDelegate> {
  UIBarButtonItem* _confirmButton;
  NSString* _confirmedName;
  TableViewTextHeaderFooterView* _footerView;

  // Owns `self`.
  raw_ptr<autofill::CardNameFixFlowViewBridge> _bridge;  // weak
}

@end

@implementation CardNameFixFlowViewController

- (instancetype)initWithBridge:(autofill::CardNameFixFlowViewBridge*)bridge {
  DCHECK(bridge);

  if ((self = [super initWithStyle:UITableViewStyleGrouped])) {
    _bridge = bridge;
    self.title =
        base::SysUTF16ToNSString(_bridge->GetController()->GetTitleText());
  }

  return self;
}

#pragma mark - UIViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  self.tableView.delegate = self;

  autofill::CardNameFixFlowController* controller = _bridge->GetController();

  NSString* cancelButtonLabel =
      base::SysUTF16ToNSString(controller->GetCancelButtonLabel());
  self.navigationItem.leftBarButtonItem =
      [[UIBarButtonItem alloc] initWithTitle:cancelButtonLabel
                                       style:UIBarButtonItemStylePlain
                                      target:self
                                      action:@selector(onCancel:)];
  NSString* saveButtonLabel =
      base::SysUTF16ToNSString(controller->GetSaveButtonLabel());
  _confirmButton =
      [[UIBarButtonItem alloc] initWithTitle:saveButtonLabel
                                       style:UIBarButtonItemStylePlain
                                      target:self
                                      action:@selector(onConfirm:)];
  self.navigationItem.rightBarButtonItem = _confirmButton;

  _confirmedName =
      base::SysUTF16ToNSString(controller->GetInferredCardholderName());

  [self updateSaveButtonEnabledStatus];

  NSString* inferredNameTooltipText =
      (_confirmedName.length > 0)
          ? base::SysUTF16ToNSString(controller->GetInferredNameTooltipText())
          : nil;

  _footerView = [[TableViewTextHeaderFooterView alloc] init];
  [_footerView setSubtitle:inferredNameTooltipText];

  [self.tableView registerClass:[TableViewTextEditCell class]
         forCellReuseIdentifier:kCellReuseID];
}

#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView*)tableView
    numberOfRowsInSection:(NSInteger)section {
  DCHECK(section == kMainSection);
  return kNumberOfRowsInMainSection;
}

- (UITableViewCell*)tableView:(UITableView*)tableView
        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
  DCHECK(indexPath.section == kMainSection);

  UITableViewCell* cellAtIndex =
      [self.tableView dequeueReusableCellWithIdentifier:kCellReuseID
                                           forIndexPath:indexPath];

  DCHECK([cellAtIndex isKindOfClass:[TableViewTextEditCell class]]);
  autofill::CardNameFixFlowController* controller = _bridge->GetController();

  TableViewTextEditCell* confirmNameCell = (TableViewTextEditCell*)cellAtIndex;
  confirmNameCell.selectionStyle = UITableViewCellSelectionStyleNone;
  confirmNameCell.useCustomSeparator = NO;
  confirmNameCell.textLabel.text =
      base::SysUTF16ToNSString(controller->GetInputLabel());

  UITextField* textField = confirmNameCell.textField;
  textField.placeholder =
      base::SysUTF16ToNSString(controller->GetInputPlaceholderText());

  textField.text = _confirmedName;
  textField.textColor = [UIColor colorNamed:kBlueColor];
  textField.delegate = self;

  return confirmNameCell;
}

#pragma mark - UITableViewDelegate

- (UIView*)tableView:(UITableView*)tableView
    viewForFooterInSection:(NSInteger)section {
  DCHECK(section == kMainSection);

  return _footerView;
}

#pragma mark - UITextFieldDelegate

- (BOOL)textField:(UITextField*)textField
    shouldChangeCharactersInRange:(NSRange)range
                replacementString:(NSString*)string {
  [self didChangeConfirmedName:[textField.text
                                   stringByReplacingCharactersInRange:range
                                                           withString:string]];
  return YES;
}

- (BOOL)textFieldShouldClear:(UITextField*)textField {
  [self didChangeConfirmedName:@""];
  return YES;
}

#pragma mark - Private

- (void)onCancel:(id)sender {
  _bridge->OnDismissed();
}

- (void)onConfirm:(id)sender {
  DCHECK(_confirmedName.length > 0);
  _bridge->OnConfirmedName(base::SysNSStringToUTF16(_confirmedName));
}

- (void)updateSaveButtonEnabledStatus {
  _confirmButton.enabled = _confirmedName.length > 0;
}

- (void)didChangeConfirmedName:(NSString*)confirmedName {
  confirmedName = [confirmedName
      stringByTrimmingCharactersInSet:NSCharacterSet
                                          .whitespaceAndNewlineCharacterSet];

  // After an edit, refresh footer text to no longer include name tooltip.
  [_footerView setSubtitle:nil];

  _confirmedName = confirmedName;
  [self updateSaveButtonEnabledStatus];
}

@end