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

#import "base/feature_list.h"
#import "components/plus_addresses/features.h"
#import "components/plus_addresses/plus_address_service.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/address_coordinator.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/card_coordinator.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/expanded_manual_fill_view_controller.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_password_coordinator.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_plus_address_mediator.h"
#import "ios/chrome/browser/favicon/model/favicon_loader.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
#import "ios/chrome/browser/plus_addresses/model/plus_address_service_factory.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
#import "ios/web/public/web_state.h"
#import "url/gurl.h"

using manual_fill::ManualFillDataType;

@interface ExpandedManualFillCoordinator () <
    ExpandedManualFillViewControllerDelegate>

// Main view controller for this coordinator.
@property(nonatomic, strong)
    ExpandedManualFillViewController* expandedManualFillViewController;

@end

@implementation ExpandedManualFillCoordinator {
  // Focused field data type to present in the expanded manual fill view.
  ManualFillDataType _focusedFieldDataType;

  // Stores the selected segment's data type.
  ManualFillDataType _selectedSegmentDataType;

  // Reauthentication Module used for re-authentication.
  ReauthenticationModule* _reauthenticationModule;

  // Used to fetch the plus addresses.
  ManualFillPlusAddressMediator* _manualFillPlusAddressMediator;
}

- (instancetype)initWithBaseViewController:(UIViewController*)viewController
                                   browser:(Browser*)browser
                               forDataType:(ManualFillDataType)dataType
                    reauthenticationModule:
                        (ReauthenticationModule*)reauthenticationModule {
  self = [super initWithBaseViewController:viewController browser:browser];
  if (self) {
    _focusedFieldDataType = dataType;
    _selectedSegmentDataType = dataType;
    _reauthenticationModule = reauthenticationModule;
    _manualFillPlusAddressMediator = nil;
  }
  return self;
}

- (void)start {
  self.expandedManualFillViewController =
      [[ExpandedManualFillViewController alloc]
          initWithDelegate:self
               forDataType:_focusedFieldDataType];

  [self showManualFillingOptionsForDataType:_focusedFieldDataType];
}

- (void)stop {
  [self stopChildCoordinators];
  _manualFillPlusAddressMediator = nil;
  self.expandedManualFillViewController = nil;
}

- (UIViewController*)viewController {
  return self.expandedManualFillViewController;
}

#pragma mark - ExpandedManualFillViewControllerDelegate

- (void)expandedManualFillViewController:
            (ExpandedManualFillViewController*)expandedManualFillViewController
                     didPressCloseButton:(UIButton*)closeButton {
  [self.delegate stopExpandedManualFillCoordinator:self];
}

- (void)expandedManualFillViewController:
            (ExpandedManualFillViewController*)expandedManualFillViewController
                  didSelectSegmentOfType:(ManualFillDataType)dataType {
  _selectedSegmentDataType = dataType;
  [self showManualFillingOptionsForDataType:_selectedSegmentDataType];
}

#pragma mark - FallbackCoordinatorDelegate

- (void)fallbackCoordinatorDidDismissPopover:
    (FallbackCoordinator*)fallbackCoordinator {
  // No-op as the expanded manual fill view is never presented as a popover for
  // now.
}

#pragma mark - FormInputInteractionDelegate

- (void)focusDidChangedWithFillingProduct:
    (autofill::FillingProduct)fillingProduct {
  ManualFillDataType previousFocusedFieldDataType = _focusedFieldDataType;
  _focusedFieldDataType =
      [ManualFillUtil manualFillDataTypeFromFillingProduct:fillingProduct];
  if (previousFocusedFieldDataType == _focusedFieldDataType) {
    return;
  }

  BOOL autofillFormButtonCurrentlyVisible =
      previousFocusedFieldDataType == _selectedSegmentDataType;
  BOOL shouldAutofillFormButtonBeVisible =
      _focusedFieldDataType == _selectedSegmentDataType;
  if (autofillFormButtonCurrentlyVisible != shouldAutofillFormButtonBeVisible) {
    [self showManualFillingOptionsForDataType:_selectedSegmentDataType];
  }
}

#pragma mark - Private

// Stops and deletes all active child coordinators.
- (void)stopChildCoordinators {
  for (ChromeCoordinator* coordinator in self.childCoordinators) {
    [coordinator stop];
  }
  [self.childCoordinators removeAllObjects];
}

// Shows the right manual filling options depending on `dataType`.
- (void)showManualFillingOptionsForDataType:(ManualFillDataType)dataType {
  switch (dataType) {
    case ManualFillDataType::kPassword:
      [self showPasswordManualFillingOptions];
      break;
    case ManualFillDataType::kPaymentMethod:
      [self showPaymentMethodManualFillingOptions];
      break;
    case ManualFillDataType::kAddress:
      [self showAddressManualFillingOptions];
      break;
    case ManualFillDataType::kOther:
      NOTREACHED();
  }
}

// Shows the password manual filling options.
- (void)showPasswordManualFillingOptions {
  [self stopChildCoordinators];

  WebStateList* webStateList = self.browser->GetWebStateList();
  CHECK(webStateList->GetActiveWebState());
  const GURL& URL = webStateList->GetActiveWebState()->GetLastCommittedURL();

  ManualFillPasswordCoordinator* passwordCoordinator =
      [[ManualFillPasswordCoordinator alloc]
             initWithBaseViewController:self.baseViewController
                                browser:self.browser
          manualFillPlusAddressMediator:[self manualFillPlusAddressMediator]
                                    URL:URL
                       injectionHandler:self.injectionHandler
               invokedOnObfuscatedField:self.invokedOnObfuscatedField
                 showAutofillFormButton:(_focusedFieldDataType ==
                                         ManualFillDataType::kPassword)];
  passwordCoordinator.delegate = self.delegate;

  self.expandedManualFillViewController.childViewController =
      passwordCoordinator.viewController;

  [self.childCoordinators addObject:passwordCoordinator];
}

// Shows the payment method manual filling options.
- (void)showPaymentMethodManualFillingOptions {
  [self stopChildCoordinators];

  CardCoordinator* cardCoordinator = [[CardCoordinator alloc]
      initWithBaseViewController:self.baseViewController
                         browser:self.browser
                injectionHandler:self.injectionHandler
          reauthenticationModule:_reauthenticationModule
          showAutofillFormButton:(_focusedFieldDataType ==
                                  ManualFillDataType::kPaymentMethod)];
  cardCoordinator.delegate = self.delegate;

  self.expandedManualFillViewController.childViewController =
      cardCoordinator.viewController;

  [self.childCoordinators addObject:cardCoordinator];
}

// Shows the address manual filling options.
- (void)showAddressManualFillingOptions {
  [self stopChildCoordinators];

  AddressCoordinator* addressCoordinator = [[AddressCoordinator alloc]
         initWithBaseViewController:self.baseViewController
                            browser:self.browser
      manualFillPlusAddressMediator:[self manualFillPlusAddressMediator]
                   injectionHandler:self.injectionHandler
             showAutofillFormButton:(_focusedFieldDataType ==
                                     ManualFillDataType::kAddress)];
  addressCoordinator.delegate = self.delegate;

  self.expandedManualFillViewController.childViewController =
      addressCoordinator.viewController;

  [self.childCoordinators addObject:addressCoordinator];
}

// Initializes `_manualFillPlusAddressMediator`.
- (ManualFillPlusAddressMediator*)manualFillPlusAddressMediator {
  if (!base::FeatureList::IsEnabled(
          plus_addresses::features::kPlusAddressIOSManualFallbackEnabled)) {
    return nil;
  }

  if (_manualFillPlusAddressMediator) {
    return _manualFillPlusAddressMediator;
  }

  ChromeBrowserState* browserState = self.browser->GetBrowserState();
  FaviconLoader* faviconLoader =
      IOSChromeFaviconLoaderFactory::GetForBrowserState(browserState);

  WebStateList* webStateList = self.browser->GetWebStateList();
  CHECK(webStateList->GetActiveWebState());
  const GURL& URL = webStateList->GetActiveWebState()->GetLastCommittedURL();

  plus_addresses::PlusAddressService* plusAddressService =
      PlusAddressServiceFactory::GetForBrowserState(browserState);
  CHECK(plusAddressService);

  _manualFillPlusAddressMediator = [[ManualFillPlusAddressMediator alloc]
      initWithFaviconLoader:faviconLoader
         plusAddressService:plusAddressService
                        URL:URL];

  return _manualFillPlusAddressMediator;
}

@end