chromium/ios/chrome/browser/overlays/ui_bundled/infobar_modal/passwords/password_infobar_modal_overlay_mediator.mm

// Copyright 2020 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/overlays/ui_bundled/infobar_modal/passwords/password_infobar_modal_overlay_mediator.h"

#import "base/memory/raw_ptr.h"
#import "base/metrics/histogram_macros.h"
#import "base/metrics/user_metrics.h"
#import "base/strings/sys_string_conversions.h"
#import "base/strings/utf_string_conversions.h"
#import "components/password_manager/core/browser/manage_passwords_referrer.h"
#import "ios/chrome/browser/overlays/model/public/default/default_infobar_overlay_request_config.h"
#import "ios/chrome/browser/overlays/model/public/overlay_callback_manager.h"
#import "ios/chrome/browser/overlays/model/public/overlay_request.h"
#import "ios/chrome/browser/overlays/model/public/overlay_request_support.h"
#import "ios/chrome/browser/overlays/model/public/overlay_response.h"
#import "ios/chrome/browser/passwords/model/ios_chrome_save_password_infobar_delegate.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/settings_commands.h"
#import "ios/chrome/browser/overlays/ui_bundled/overlay_request_mediator+subclassing.h"
#import "ios/chrome/grit/ios_branded_strings.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util.h"

@interface PasswordInfobarModalOverlayMediator ()
// The save password modal config from the request.
@property(nonatomic, readonly) DefaultInfobarOverlayRequestConfig* config;
@end

@implementation PasswordInfobarModalOverlayMediator {
  raw_ptr<IOSChromeSavePasswordInfoBarDelegate> delegate_;
  InfobarType infobarType_;
}

#pragma mark - Accessors

- (DefaultInfobarOverlayRequestConfig*)config {
  return self.request
             ? self.request->GetConfig<DefaultInfobarOverlayRequestConfig>()
             : nullptr;
}

- (void)setConsumer:(id<InfobarPasswordModalConsumer>)consumer {
  if (_consumer == consumer) {
    return;
  }
  _consumer = consumer;

  if (!_consumer || !self.config) {
    return;
  }

  delegate_ = static_cast<IOSChromeSavePasswordInfoBarDelegate*>(
      self.config->delegate());
  infobarType_ = self.config->infobar_type();

  [_consumer setUsername:delegate_->GetUserNameText()];
  NSString* password = delegate_->GetPasswordText();
  [_consumer setMaskedPassword:[@"" stringByPaddingToLength:password.length
                                                 withString:@"•"
                                            startingAtIndex:0]];
  [_consumer setUnmaskedPassword:password];
  std::optional<std::string> account_string =
      delegate_->GetAccountToStorePassword();
  NSString* details_text =
      account_string
          ? l10n_util::GetNSStringF(
                IDS_SAVE_PASSWORD_FOOTER_DISPLAYING_USER_EMAIL,
                base::UTF8ToUTF16(*account_string))
          : l10n_util::GetNSString(IDS_IOS_SAVE_PASSWORD_FOOTER_NOT_SYNCING);
  [_consumer setDetailsTextMessage:details_text];

  NSString* save_button_text = base::SysUTF16ToNSString(
      delegate_->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK));
  [_consumer setSaveButtonText:save_button_text];

  NSString* cancel_button_text = base::SysUTF16ToNSString(
      delegate_->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL));
  [_consumer setCancelButtonText:cancel_button_text];

  [_consumer setURL:delegate_->GetURLHostText()];
  [_consumer setCurrentCredentialsSaved:delegate_->IsCurrentPasswordSaved()];
}

#pragma mark - OverlayRequestMediator

+ (const OverlayRequestSupport*)requestSupport {
  return DefaultInfobarOverlayRequestConfig::RequestSupport();
}

#pragma mark - InfobarPasswordModalDelegate

- (void)updateCredentialsWithUsername:(NSString*)username
                             password:(NSString*)password {
  // Receiving this delegate callback when the request is null means that the
  // update credentials button was tapped after the request was cancelled, but
  // before the modal UI has finished being dismissed.
  if (!self.request) {
    return;
  }

  delegate_->UpdateCredentials(username, password);
  delegate_->Accept();

  [self dismissInfobarModal:nil];
}

- (void)neverSaveCredentialsForCurrentSite {
  // Receiving this delegate callback when the request is null means that the
  // never save credentials button was tapped after the request was cancelled,
  // but before the modal UI has finished being dismissed.
  if (!self.request) {
    return;
  }

  delegate_->Cancel();
  [self dismissInfobarModal:nil];
}

- (void)presentPasswordSettings {
  // Receiving this delegate callback when the request is null means that the
  // present passwords settings button was tapped after the request was
  // cancelled, but before the modal UI has finished being dismissed.
  if (!self.request) {
    return;
  }

  [self dismissInfobarModal:nil];

  id<SettingsCommands> settings_command_handler =
      HandlerForProtocol(delegate_->GetDispatcher(), SettingsCommands);
  [settings_command_handler showSavedPasswordsSettingsFromViewController:nil
                                                        showCancelButton:YES];

  UMA_HISTOGRAM_ENUMERATION(
      "PasswordManager.ManagePasswordsReferrer",
      password_manager::ManagePasswordsReferrer::kManagePasswordsBubble);
  base::RecordAction(
      base::UserMetricsAction("MobilePasswordInfobarModalOpenPasswordManager"));
}

@end