chromium/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/autofill_edit_profile_bottom_sheet_table_view_controller.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/autofill/ui_bundled/bottom_sheet/autofill_edit_profile_bottom_sheet_table_view_controller.h"

#import "base/apple/foundation_util.h"
#import "base/notreached.h"
#import "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/shared/ui/table_view/legacy_chrome_table_view_styler.h"
#import "ios/chrome/browser/shared/ui/table_view/table_view_utils.h"
#import "ios/chrome/browser/autofill/ui_bundled/autofill_profile_edit_table_view_constants.h"
#import "ios/chrome/browser/autofill/ui_bundled/bottom_sheet/bottom_sheet_constants.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/common/ui/table_view/table_view_cells_constants.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util_mac.h"

namespace {

// Custom radius for the half sheet presentation.
CGFloat const kHalfSheetCornerRadius = 20;

// Custom detent identifier for when the bottom sheet is minimized.
NSString* const kCustomMinimizedDetentIdentifier = @"customMinimizedDetent";

// Custom detent identifier for when the bottom sheet is expanded.
NSString* const kCustomExpandedDetentIdentifier = @"customExpandedDetent";

// Deafult height of the header/footer, used to speed the constraints.
const CGFloat kDefaultHeaderFooterHeight = 10;
}  // namespace

@interface AutofillEditProfileBottomSheetTableViewController () <
    UITextFieldDelegate> {
  // Delegate for this view controller.
  __weak id<AutofillEditProfileBottomSheetTableViewControllerDelegate>
      _delegate;

  // Denotes the mode of the address save for the edit profile bottom sheet.
  AutofillSaveProfilePromptMode _editSheetMode;
}

@end

@implementation AutofillEditProfileBottomSheetTableViewController

#pragma mark - Initialization

- (instancetype)
    initWithDelegate:
        (id<AutofillEditProfileBottomSheetTableViewControllerDelegate>)delegate
       editSheetMode:(AutofillSaveProfilePromptMode)editSheetMode {
  self = [super initWithStyle:ChromeTableViewStyle()];
  if (self) {
    _delegate = delegate;
    _editSheetMode = editSheetMode;
  }
  return self;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  [self setUpBottomSheetPresentationController];
  [self setUpBottomSheetDetents];

  [self.tableView
      setSeparatorInset:UIEdgeInsetsMake(0, kTableViewHorizontalSpacing, 0, 0)];

  // Configure the NavigationBar.
  UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc]
      initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
                           target:self
                           action:@selector(handleCancelButton)];
  cancelButton.accessibilityIdentifier = kEditProfileBottomSheetCancelButton;

  self.navigationItem.leftBarButtonItem = cancelButton;
  self.navigationController.navigationBar.prefersLargeTitles = NO;
  switch (_editSheetMode) {
    case AutofillSaveProfilePromptMode::kNewProfile:
      [self setTitle:l10n_util::GetNSString(
                         IDS_IOS_AUTOFILL_SAVE_ADDRESS_PROMPT_TITLE)];
      break;
    case AutofillSaveProfilePromptMode::kUpdateProfile:
      [self setTitle:l10n_util::GetNSString(
                         IDS_IOS_AUTOFILL_UPDATE_ADDRESS_PROMPT_TITLE)];
      break;
    case AutofillSaveProfilePromptMode::kMigrateProfile:
      [self
          setTitle:
              l10n_util::GetNSString(
                  IDS_IOS_AUTOFILL_ADDRESS_MIGRATION_TO_ACCOUNT_PROMPT_TITLE)];
      break;
  }

  self.tableView.allowsSelectionDuringEditing = YES;

  [self loadModel];
}

- (void)loadModel {
  [super loadModel];
  [self.handler
      setMigrationPrompt:(_editSheetMode ==
                          AutofillSaveProfilePromptMode::kMigrateProfile)];
  [self.handler loadModel];
  [self.handler
      loadMessageAndButtonForModalIfSaveOrUpdate:
          (_editSheetMode == AutofillSaveProfilePromptMode::kUpdateProfile)];
}

- (void)expandBottomSheet {
  UISheetPresentationController* presentationController =
      self.sheetPresentationController;
  // Expand to large detent.
  [presentationController animateChanges:^{
    presentationController.selectedDetentIdentifier =
        UISheetPresentationControllerDetentIdentifierLarge;
  }];
}

- (void)setUpBottomSheetPresentationController {
  UISheetPresentationController* presentationController =
      self.sheetPresentationController;
  presentationController.prefersEdgeAttachedInCompactHeight = YES;
  presentationController.widthFollowsPreferredContentSizeWhenEdgeAttached = YES;
  presentationController.preferredCornerRadius = kHalfSheetCornerRadius;
}

- (void)setUpBottomSheetDetents {
  UISheetPresentationController* presentationController =
      self.sheetPresentationController;
  presentationController.detents = @[
    [UISheetPresentationControllerDetent mediumDetent],
    [UISheetPresentationControllerDetent largeDetent]
  ];
  presentationController.selectedDetentIdentifier =
      UISheetPresentationControllerDetentIdentifierLarge;
}

#pragma mark - UITableViewDataSource

- (UITableViewCell*)tableView:(UITableView*)tableView
        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
  UITableViewCell* cell = [super tableView:tableView
                     cellForRowAtIndexPath:indexPath];
  return [self.handler cell:cell
          forRowAtIndexPath:indexPath
           withTextDelegate:self];
}

- (void)tableView:(UITableView*)tableView
    didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
  [self.handler didSelectRowAtIndexPath:indexPath];
}

- (UIView*)tableView:(UITableView*)tableView
    viewForFooterInSection:(NSInteger)section {
  UIView* view = [super tableView:tableView viewForFooterInSection:section];
  [self.handler configureView:view forFooterInSection:section];
  return view;
}

- (CGFloat)tableView:(UITableView*)tableView
    heightForHeaderInSection:(NSInteger)section {
  if ([self.tableViewModel headerForSectionIndex:section]) {
    return UITableViewAutomaticDimension;
  }

  return kDefaultHeaderFooterHeight;
}

- (CGFloat)tableView:(UITableView*)tableView
    heightForFooterInSection:(NSInteger)section {
  if ([self.handler heightForFooterShouldBeZeroInSection:section]) {
    return 0;
  }

  if ([self.tableViewModel footerForSectionIndex:section]) {
    return UITableViewAutomaticDimension;
  }

  return kDefaultHeaderFooterHeight;
}

#pragma mark - Actions

- (void)handleCancelButton {
  CHECK(_delegate);
  [_delegate didCancelBottomSheetView];
}

#pragma mark - UITextFieldDelegate

- (BOOL)textFieldShouldReturn:(UITextField*)textField {
  [textField resignFirstResponder];
  return NO;
}

@end