// 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_coordinator.h"
#import "base/strings/sys_string_conversions.h"
#import "components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h"
#import "components/autofill/core/browser/data_model/autofill_profile.h"
#import "components/infobars/core/infobar.h"
#import "ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.h"
#import "ios/chrome/browser/autofill/model/personal_data_manager_factory.h"
#import "ios/chrome/browser/autofill/ui_bundled/autofill_constants.h"
#import "ios/chrome/browser/autofill/ui_bundled/autofill_country_selection_table_view_controller.h"
#import "ios/chrome/browser/autofill/ui_bundled/autofill_profile_edit_mediator.h"
#import "ios/chrome/browser/autofill/ui_bundled/autofill_profile_edit_mediator_delegate.h"
#import "ios/chrome/browser/autofill/ui_bundled/autofill_profile_edit_table_view_controller.h"
#import "ios/chrome/browser/autofill/ui_bundled/bottom_sheet/autofill_edit_profile_bottom_sheet_table_view_controller.h"
#import "ios/chrome/browser/autofill/ui_bundled/cells/country_item.h"
#import "ios/chrome/browser/infobars/model/infobar_ios.h"
#import "ios/chrome/browser/infobars/model/infobar_manager_impl.h"
#import "ios/chrome/browser/infobars/model/infobar_type.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/ui/table_view/table_view_navigation_controller.h"
@interface AutofillEditProfileBottomSheetCoordinator () <
AutofillCountrySelectionTableViewControllerDelegate,
AutofillEditProfileBottomSheetTableViewControllerDelegate,
AutofillProfileEditMediatorDelegate>
@end
@implementation AutofillEditProfileBottomSheetCoordinator {
// Profile to be edited.
std::unique_ptr<autofill::AutofillProfile> _autofillProfile;
// Navigation controller presented by this coordinator.
TableViewNavigationController* _navigationController;
// TVC for displaying the bottom sheet.
AutofillEditProfileBottomSheetTableViewController* _viewController;
// Mediator and view controller used to display the edit view.
AutofillProfileEditTableViewController*
_autofillProfileEditTableViewController;
AutofillProfileEditMediator* _autofillProfileEditMediator;
raw_ptr<autofill::PersonalDataManager> _personalDataManager;
raw_ptr<web::WebState> _webState;
}
- (instancetype)initWithBaseViewController:
(UINavigationController*)viewController
browser:(Browser*)browser {
self = [super initWithBaseViewController:viewController browser:browser];
if (self) {
ChromeBrowserState* browserState = browser->GetBrowserState();
// Address Save Prompt is not shown in the incognito mode.
CHECK(!browserState->IsOffTheRecord());
_personalDataManager =
autofill::PersonalDataManagerFactory::GetForBrowserState(browserState);
_webState = browser->GetWebStateList()->GetActiveWebState();
}
return self;
}
#pragma mark - ChromeCoordinator
- (void)start {
autofill::AutofillSaveUpdateAddressProfileDelegateIOS* delegate =
[self fetchDelegate];
_autofillProfile =
std::make_unique<autofill::AutofillProfile>(*delegate->GetProfile());
AutofillSaveProfilePromptMode saveProfilePromptMode =
AutofillSaveProfilePromptMode::kNewProfile;
if (delegate->IsMigrationToAccount()) {
saveProfilePromptMode = AutofillSaveProfilePromptMode::kMigrateProfile;
} else if (delegate->GetOriginalProfile() != nullptr) {
saveProfilePromptMode = AutofillSaveProfilePromptMode::kUpdateProfile;
}
_autofillProfileEditMediator = [[AutofillProfileEditMediator alloc]
initWithDelegate:self
personalDataManager:_personalDataManager
autofillProfile:_autofillProfile.get()
isMigrationPrompt:delegate->IsMigrationToAccount()];
// Bottom sheet table VC
AutofillEditProfileBottomSheetTableViewController* editModalViewController =
[[AutofillEditProfileBottomSheetTableViewController alloc]
initWithDelegate:self
editSheetMode:saveProfilePromptMode];
// View controller that lays down the table views for the edit profile view.
_autofillProfileEditTableViewController =
[[AutofillProfileEditTableViewController alloc]
initWithDelegate:_autofillProfileEditMediator
userEmail:(delegate->UserAccountEmail()
? base::SysUTF16ToNSString(
delegate->UserAccountEmail().value())
: nil)controller:editModalViewController
settingsView:NO];
_autofillProfileEditMediator.consumer =
_autofillProfileEditTableViewController;
// `editModalViewController` lays down the bottom sheet view and communicates
// with `_autofillProfileEditTableViewController` via
// `AutofillProfileEditHandler` protocol.
// `_autofillProfileEditTableViewController` is responsible for loading the
// model and dealing with the table view user interactions.
editModalViewController.handler = _autofillProfileEditTableViewController;
_viewController = editModalViewController;
_navigationController =
[[TableViewNavigationController alloc] initWithTable:_viewController];
BOOL isIPad =
UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad;
if (isIPad) {
_navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
_navigationController.modalInPresentation = YES;
} else {
_navigationController.modalPresentationStyle =
UIModalPresentationFullScreen;
}
_navigationController.modalTransitionStyle =
UIModalTransitionStyleCoverVertical;
[self.baseViewController presentViewController:_navigationController
animated:YES
completion:nil];
}
- (void)stop {
[super stop];
[_navigationController.presentingViewController
dismissViewControllerAnimated:YES
completion:nil];
_viewController = nil;
_autofillProfileEditMediator = nil;
}
#pragma mark - AutofillProfileEditMediatorDelegate
- (void)autofillEditProfileMediatorDidFinish:
(AutofillProfileEditMediator*)mediator {
// TODO(crbug.com/40281788): Implement.
}
- (void)willSelectCountryWithCurrentlySelectedCountry:(NSString*)country
countryList:(NSArray<CountryItem*>*)
allCountries {
AutofillCountrySelectionTableViewController*
autofillCountrySelectionTableViewController =
[[AutofillCountrySelectionTableViewController alloc]
initWithDelegate:self
selectedCountry:country
allCountries:allCountries
settingsView:NO];
[_navigationController
pushViewController:autofillCountrySelectionTableViewController
animated:YES];
}
- (void)didSaveProfile {
autofill::AutofillSaveUpdateAddressProfileDelegateIOS* delegate =
[self fetchDelegateAndAcceptInfobar];
delegate->SetProfile(_autofillProfile.get());
delegate->EditAccepted();
[self stop];
}
#pragma mark - AutofillCountrySelectionTableViewControllerDelegate
- (void)didSelectCountry:(CountryItem*)selectedCountry {
[_navigationController popViewControllerAnimated:YES];
[_autofillProfileEditMediator didSelectCountry:selectedCountry];
}
#pragma mark - AutofillEditProfileBottomSheetTableViewControllerDelegate
- (void)didCancelBottomSheetView {
autofill::AutofillSaveUpdateAddressProfileDelegateIOS* delegate =
[self fetchDelegate];
if (delegate->IsMigrationToAccount()) {
delegate->Never();
InfoBarManagerImpl::FromWebState(_webState)->RemoveInfoBar(
[self addressInfobar]);
} else {
delegate->EditDeclined();
}
[self stop];
}
#pragma mark - Private
- (autofill::AutofillSaveUpdateAddressProfileDelegateIOS*)
fetchDelegateAndAcceptInfobar {
InfoBarIOS* infobar = static_cast<InfoBarIOS*>([self addressInfobar]);
infobar->set_accepted(YES);
return [self fetchDelegateFromInfobar:infobar];
}
- (autofill::AutofillSaveUpdateAddressProfileDelegateIOS*)fetchDelegate {
InfoBarIOS* infobar = static_cast<InfoBarIOS*>([self addressInfobar]);
return [self fetchDelegateFromInfobar:infobar];
}
- (infobars::InfoBar*)addressInfobar {
InfoBarManagerImpl* manager = InfoBarManagerImpl::FromWebState(_webState);
CHECK(manager);
const auto it = base::ranges::find(
manager->infobars(), InfobarType::kInfobarTypeSaveAutofillAddressProfile,
[](const infobars::InfoBar* infobar) {
return static_cast<const InfoBarIOS*>(infobar)->infobar_type();
});
CHECK(it != manager->infobars().cend());
return *it;
}
- (autofill::AutofillSaveUpdateAddressProfileDelegateIOS*)
fetchDelegateFromInfobar:(InfoBarIOS*)infobar {
autofill::AutofillSaveUpdateAddressProfileDelegateIOS* delegate =
autofill::AutofillSaveUpdateAddressProfileDelegateIOS::
FromInfobarDelegate(infobar->delegate());
CHECK(delegate);
return delegate;
}
@end