chromium/ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_coordinator.mm

// Copyright 2023 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/ui/settings/password/password_sharing/password_sharing_coordinator.h"

#import "base/strings/sys_string_conversions.h"
#import "components/password_manager/core/browser/password_ui_utils.h"
#import "components/password_manager/core/browser/sharing/recipients_fetcher.h"
#import "components/password_manager/core/browser/ui/credential_ui_entry.h"
#import "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
#import "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/passwords/model/ios_chrome_password_sender_service_factory.h"
#import "ios/chrome/browser/shared/coordinator/alert/alert_coordinator.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/ui/table_view/table_view_utils.h"
#import "ios/chrome/browser/signin/model/identity_manager_factory.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/family_picker_coordinator.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/family_picker_coordinator_delegate.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/family_promo_coordinator.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/family_promo_coordinator_delegate.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/password_picker_coordinator.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/password_picker_coordinator_delegate.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_constants.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_coordinator_delegate.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_mediator.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_mediator_delegate.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/recipient_info.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_coordinator_delegate.h"
#import "ios/chrome/grit/ios_branded_strings.h"
#import "ios/chrome/grit/ios_strings.h"
#import "services/network/public/cpp/shared_url_loader_factory.h"
#import "ui/base/l10n/l10n_util.h"

using password_manager::FetchFamilyMembersRequestStatus;

@interface PasswordSharingCoordinator () <
    FamilyPickerCoordinatorDelegate,
    FamilyPromoCoordinatorDelegate,
    PasswordPickerCoordinatorDelegate,
    PasswordSharingMediatorDelegate,
    SharingStatusCoordinatorDelegate> {
  // The credentials for the password group from which the sharing originated.
  std::vector<password_manager::CredentialUIEntry> _credentials;

  // Service providing a view on user's saved passwords.
  raw_ptr<password_manager::SavedPasswordsPresenter> _savedPasswordsPresenter;
}

// Main mediator for this coordinator.
@property(nonatomic, strong) PasswordSharingMediator* mediator;

// Coordinator for family picker.
@property(nonatomic, strong) FamilyPickerCoordinator* familyPickerCoordinator;

// Coordinator for family promo view.
@property(nonatomic, strong) FamilyPromoCoordinator* familyPromoCoordinator;

// Coordinator to display modal alerts to the user.
@property(nonatomic, strong) AlertCoordinator* alertCoordinator;

// Coordinator for password picker.
@property(nonatomic, strong)
    PasswordPickerCoordinator* passwordPickerCoordinator;

// Coordinator for sharing status view.
@property(nonatomic, strong) SharingStatusCoordinator* sharingStatusCoordinator;

// Information about potential password sharing recipients of the user.
@property(nonatomic, strong) NSArray<RecipientInfoForIOSDisplay*>* recipients;

@end

@implementation PasswordSharingCoordinator

- (instancetype)
    initWithBaseViewController:(UIViewController*)viewController
                       browser:(Browser*)browser
                   credentials:
                       (const std::vector<password_manager::CredentialUIEntry>&)
                           credentials
       savedPasswordsPresenter:
           (password_manager::SavedPasswordsPresenter*)savedPasswordsPresenter {
  self = [super initWithBaseViewController:viewController browser:browser];
  if (self) {
    _credentials = credentials;
    _savedPasswordsPresenter = savedPasswordsPresenter;
  }
  return self;
}

- (void)start {
  [super start];

  ChromeBrowserState* browserState = self.browser->GetBrowserState();
  self.mediator = [[PasswordSharingMediator alloc]
             initWithDelegate:self
       sharedURLLoaderFactory:browserState->GetSharedURLLoaderFactory()
              identityManager:IdentityManagerFactory::GetForBrowserState(
                                  browserState)
      savedPasswordsPresenter:_savedPasswordsPresenter
        passwordSenderService:IOSChromePasswordSenderServiceFactory::
                                  GetForBrowserState(browserState)];

  // With more than 1 credential an additional UI will be presented to select
  // which one should be shared.
  if (_credentials.size() == 1) {
    self.mediator.selectedCredential = _credentials[0];
  }
}

- (void)stop {
  self.mediator = nil;

  [self stopFamilyPickerCoordinator];
  [self stopFamilyPromoCoordinator];
  [self stopAlertCoordinator];
  [self stopPasswordPickerCoordinator];
  [self stopSharingStatusCoordinator];
}

#pragma mark - FamilyPickerCoordinatorDelegate

- (void)familyPickerCoordinatorWasDismissed:
    (FamilyPickerCoordinator*)coordinator {
  [self.delegate passwordSharingCoordinatorDidRemove:self];
}

- (void)familyPickerCoordinator:(FamilyPickerCoordinator*)coordinator
            didSelectRecipients:
                (NSArray<RecipientInfoForIOSDisplay*>*)recipients {
  self.mediator.selectedRecipients = recipients;

  if (self.familyPickerCoordinator == coordinator) {
    [self stopFamilyPickerCoordinator];
  }

  [self startSharingStatusCoordinator];
}

- (void)familyPickerCoordinatorNavigatedBack:
    (FamilyPickerCoordinator*)coordinator {
  if (self.familyPickerCoordinator == coordinator) {
    [self stopFamilyPickerCoordinator];
  }
}

#pragma mark - FamilyPromoCoordinatorDelegate

- (void)familyPromoCoordinatorWasDismissed:
    (FamilyPromoCoordinator*)coordinator {
  if (self.familyPromoCoordinator == coordinator) {
    [self stopFamilyPromoCoordinator];
  }

  [self.delegate passwordSharingCoordinatorDidRemove:self];
}

#pragma mark - PasswordPickerCoordinatorDelegate

- (void)passwordPickerCoordinatorWasDismissed:
    (PasswordPickerCoordinator*)coordinator {
  [self.delegate passwordSharingCoordinatorDidRemove:self];
}

- (void)passwordPickerWithNavigationController:
            (UINavigationController*)navigationController
                           didSelectCredential:
                               (const password_manager::CredentialUIEntry&)
                                   credential {
  self.mediator.selectedCredential = credential;
  [self startFamilyPickerCoordinatorWithNavigationController:
            navigationController];
}

#pragma mark - PasswordSharingMediatorDelegate

- (void)onFetchFamilyMembers:
            (NSArray<RecipientInfoForIOSDisplay*>*)familyMembers
                  withStatus:(const FetchFamilyMembersRequestStatus&)status {
  [self.delegate shareFlowEntered];

  self.recipients = familyMembers;

  switch (status) {
    case FetchFamilyMembersRequestStatus::kSuccess: {
      if (_credentials.size() == 1) {
        [self startFamilyPickerCoordinator];
      } else {
        [self startPasswordPickerCoordinator];
      }
      break;
    }
    case FetchFamilyMembersRequestStatus::kNoFamily: {
      [self startFamilyPromoCoordinatorWithType:FamilyPromoType::
                                                    kUserNotInFamilyGroup];
      break;
    }
    case FetchFamilyMembersRequestStatus::kNoOtherFamilyMembers: {
      [self startFamilyPromoCoordinatorWithType:
                FamilyPromoType::kUserWithNoOtherFamilyMembers];
      break;
    }
    default: {
      [self startAlertCoordinator];
      break;
    }
  }
}

#pragma mark - SharingStatusCoordinatorDelegate

- (void)sharingStatusCoordinatorWasDismissed:
    (SharingStatusCoordinator*)coordinator {
  [self.delegate passwordSharingCoordinatorDidRemove:self];
}

- (void)startPasswordSharing {
  [self.mediator sendSelectedCredentialToSelectedRecipients];
}

#pragma mark - Private

- (void)startFamilyPickerCoordinator {
  [self.familyPickerCoordinator stop];
  self.familyPickerCoordinator = [[FamilyPickerCoordinator alloc]
      initWithBaseViewController:self.baseViewController
                         browser:self.browser
                      recipients:self.recipients];
  self.familyPickerCoordinator.delegate = self;
  [self.familyPickerCoordinator start];
}

- (void)startFamilyPickerCoordinatorWithNavigationController:
    (UINavigationController*)navigationController {
  [self.familyPickerCoordinator stop];
  self.familyPickerCoordinator = [[FamilyPickerCoordinator alloc]
      initWithBaseNavigationController:navigationController
                               browser:self.browser
                            recipients:self.recipients];
  self.familyPickerCoordinator.delegate = self;
  [self.familyPickerCoordinator start];
}

- (void)startPasswordPickerCoordinator {
  [self.passwordPickerCoordinator stop];
  self.passwordPickerCoordinator = [[PasswordPickerCoordinator alloc]
      initWithBaseViewController:self.baseViewController
                         browser:self.browser
                     credentials:_credentials];
  self.passwordPickerCoordinator.delegate = self;
  [self.passwordPickerCoordinator start];
}

- (void)startFamilyPromoCoordinatorWithType:(FamilyPromoType)type {
  [self.familyPromoCoordinator stop];
  self.familyPromoCoordinator = [[FamilyPromoCoordinator alloc]
      initWithFamilyPromoType:type
           baseViewController:self.baseViewController
                      browser:self.browser];
  self.familyPromoCoordinator.delegate = self;
  [self.familyPromoCoordinator start];
}

- (void)startSharingStatusCoordinator {
  [self.sharingStatusCoordinator stop];
  password_manager::CredentialUIEntry credential =
      self.mediator.selectedCredential;
  self.sharingStatusCoordinator = [[SharingStatusCoordinator alloc]
      initWithBaseViewController:self.baseViewController
                         browser:self.browser
                      recipients:self.mediator.selectedRecipients
                         website:base::SysUTF8ToNSString(
                                     password_manager::GetShownOrigin(
                                         credential))
                             URL:credential.GetURL()
               changePasswordURL:credential.GetChangePasswordURL()];
  self.sharingStatusCoordinator.delegate = self;
  [self.sharingStatusCoordinator start];
}

- (void)startAlertCoordinator {
  NSString* title = l10n_util::GetNSString(
      IDS_IOS_PASSWORD_SHARING_FETCHING_RECIPIENTS_ERROR_TITLE);
  NSString* message = l10n_util::GetNSString(
      IDS_IOS_PASSWORD_SHARING_FETCHING_RECIPIENTS_ERROR);
  [self.alertCoordinator stop];
  self.alertCoordinator = [[AlertCoordinator alloc]
      initWithBaseViewController:self.baseViewController
                         browser:self.browser
                           title:title
                         message:message];
  __weak __typeof(self) weakSelf = self;
  [self.alertCoordinator
      addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
                action:^() {
                  [weakSelf stopAlertCoordinator];
                  [weakSelf.delegate
                      passwordSharingCoordinatorDidRemove:weakSelf];
                }
                 style:UIAlertActionStyleCancel];
  [self.alertCoordinator start];
}

- (void)stopFamilyPickerCoordinator {
  [self.familyPickerCoordinator stop];
  self.familyPickerCoordinator.delegate = nil;
  self.familyPickerCoordinator = nil;
}

- (void)stopPasswordPickerCoordinator {
  [self.passwordPickerCoordinator stop];
  self.passwordPickerCoordinator.delegate = nil;
  self.passwordPickerCoordinator = nil;
}

- (void)stopFamilyPromoCoordinator {
  [self.familyPromoCoordinator stop];
  self.familyPromoCoordinator.delegate = nil;
  self.familyPromoCoordinator = nil;
}

- (void)stopAlertCoordinator {
  [self.alertCoordinator stop];
  self.alertCoordinator = nil;
}

- (void)stopSharingStatusCoordinator {
  [self.sharingStatusCoordinator stop];
  self.sharingStatusCoordinator.delegate = nil;
  self.sharingStatusCoordinator = nil;
}

@end