// Copyright 2018 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/card_coordinator.h"
#import "base/memory/raw_ptr.h"
#import "base/memory/ref_counted.h"
#import "components/autofill/core/browser/data_model/credit_card.h"
#import "components/autofill/core/browser/personal_data_manager.h"
#import "components/autofill/ios/browser/autofill_driver_ios.h"
#import "ios/chrome/browser/autofill/model/personal_data_manager_factory.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/card_list_delegate.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_card_mediator.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_full_card_requester.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_injection_handler.h"
#import "ios/chrome/browser/net/model/crurl.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/browser/shared/public/commands/application_commands.h"
#import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/open_new_tab_command.h"
#import "ios/chrome/browser/shared/ui/table_view/table_view_navigation_controller.h"
#import "ios/chrome/common/ui/reauthentication/reauthentication_event.h"
#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ios/web/public/js_messaging/web_frame.h"
#import "ui/base/device_form_factor.h"
#import "ui/base/l10n/l10n_util_mac.h"
@interface CardCoordinator () <CardListDelegate> {
// Opening links on the enrollment bottom sheet is delegated to this
// dispatcher.
__weak id<ApplicationCommands> _dispatcher;
// Reauthentication Module used for re-authentication.
ReauthenticationModule* _reauthenticationModule;
// PersonalDataManager
autofill::PersonalDataManager* _personalDataManager;
}
// The view controller presented above the keyboard where the user can select
// one of their cards.
@property(nonatomic, strong) CardViewController* cardViewController;
// Fetches and filters the cards for the view controller.
@property(nonatomic, strong) ManualFillCardMediator* cardMediator;
// Requesters to unlock (through user CVC input) of server side credit cards.
@property(nonatomic, strong) ManualFillFullCardRequester* cardRequester;
@end
@implementation CardCoordinator
// Property tagged dynamic because it overrides super class delegate with and
// extension of the super delegate type (i.e. CardCoordinatorDelegate extends
// FallbackCoordinatorDelegate)
@dynamic delegate;
- (instancetype)
initWithBaseViewController:(UIViewController*)viewController
browser:(Browser*)browser
injectionHandler:(ManualFillInjectionHandler*)injectionHandler
reauthenticationModule:(ReauthenticationModule*)reauthenticationModule
showAutofillFormButton:(BOOL)showAutofillFormButton {
self = [super initWithBaseViewController:viewController
browser:browser
injectionHandler:injectionHandler];
if (self) {
_cardViewController = [[CardViewController alloc] init];
_reauthenticationModule = reauthenticationModule;
// Service must use regular browser state, even if the Browser has an
// OTR browser state.
_personalDataManager =
autofill::PersonalDataManagerFactory::GetForBrowserState(
super.browser->GetBrowserState()->GetOriginalChromeBrowserState());
CHECK(_personalDataManager);
_cardMediator = [[ManualFillCardMediator alloc]
initWithPersonalDataManager:_personalDataManager
reauthenticationModule:_reauthenticationModule
showAutofillFormButton:showAutofillFormButton];
_cardMediator.navigationDelegate = self;
_cardMediator.contentInjector = super.injectionHandler;
_cardMediator.consumer = _cardViewController;
_cardRequester = [[ManualFillFullCardRequester alloc]
initWithBrowserState:super.browser->GetBrowserState()
->GetOriginalChromeBrowserState()
webStateList:super.browser->GetWebStateList()
resultDelegate:_cardMediator];
_dispatcher = HandlerForProtocol(self.browser->GetCommandDispatcher(),
ApplicationCommands);
}
return self;
}
- (void)stop {
[_cardMediator disconnect];
_cardMediator = nil;
_cardViewController = nil;
}
#pragma mark - FallbackCoordinator
- (UIViewController*)viewController {
return self.cardViewController;
}
#pragma mark - CardListDelegate
- (void)openAddCreditCard {
__weak __typeof(self) weakSelf = self;
[self dismissIfNecessaryThenDoCompletion:^{
[weakSelf.delegate cardCoordinatorDidTriggerOpenAddCreditCard:weakSelf];
}];
}
- (void)openCardDetails:(const autofill::CreditCard*)card
inEditMode:(BOOL)editMode {
CHECK(_personalDataManager);
if (card->record_type() == autofill::CreditCard::RecordType::kLocalCard &&
_personalDataManager->payments_data_manager()
.IsPaymentMethodsMandatoryReauthEnabled() &&
[_reauthenticationModule canAttemptReauth]) {
NSString* reason = l10n_util::GetNSString(IDS_IOS_AUTOFILL_REAUTH_REASON);
auto completionHandler = ^(ReauthenticationResult result) {
if (result != ReauthenticationResult::kFailure) {
[self didTriggerOpenCardDetails:card inEditMode:editMode];
}
};
[_reauthenticationModule
attemptReauthWithLocalizedReason:reason
canReusePreviousAuth:YES
handler:completionHandler];
return;
}
[self didTriggerOpenCardDetails:card inEditMode:editMode];
}
- (void)openCardSettings {
__weak __typeof(self) weakSelf = self;
[self dismissIfNecessaryThenDoCompletion:^{
[weakSelf.delegate cardCoordinatorDidTriggerOpenCardSettings:weakSelf];
}];
}
- (void)requestFullCreditCard:(ManualFillCreditCard*)card
fieldType:(manual_fill::PaymentFieldType)fieldType {
__weak __typeof(self) weakSelf = self;
[self dismissIfNecessaryThenDoCompletion:^{
if (!weakSelf)
return;
const autofill::CreditCard* autofillCreditCard =
[weakSelf.cardMediator findCreditCardfromGUID:card.GUID];
if (!autofillCreditCard)
return;
[weakSelf.cardRequester requestFullCreditCard:*autofillCreditCard
withBaseViewController:weakSelf.baseViewController
recordType:card.recordType
fieldType:fieldType];
}];
}
- (void)openURL:(CrURL*)url withTitle:(NSString*)title {
[_dispatcher
openURLInNewTab:[OpenNewTabCommand
commandWithURLFromChrome:url.gurl
inIncognito:self.browser
->GetBrowserState()
->IsOffTheRecord()]];
}
#pragma mark - Private
- (void)didTriggerOpenCardDetails:(const autofill::CreditCard*)card
inEditMode:(BOOL)editMode {
__weak __typeof(self) weakSelf = self;
[self dismissIfNecessaryThenDoCompletion:^{
[weakSelf.delegate cardCoordinator:weakSelf
didTriggerOpenCardDetails:card
inEditMode:editMode];
}];
}
@end