[go: up one dir, main page]

blob: c6af82bd03424884a4575664451fcb4ae964784f [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// 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/infobars/coordinators/infobar_password_coordinator.h"
#include "base/strings/sys_string_conversions.h"
#include "ios/chrome/browser/infobars/infobar_controller_delegate.h"
#import "ios/chrome/browser/passwords/ios_chrome_password_infobar_metrics_recorder.h"
#import "ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.h"
#import "ios/chrome/browser/ui/infobars/coordinators/infobar_coordinator_implementation.h"
#import "ios/chrome/browser/ui/infobars/infobar_badge_ui_delegate.h"
#import "ios/chrome/browser/ui/infobars/infobar_container.h"
#import "ios/chrome/browser/ui/infobars/modals/infobar_password_modal_delegate.h"
#import "ios/chrome/browser/ui/infobars/modals/infobar_password_table_view_controller.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface InfobarPasswordCoordinator () <InfobarCoordinatorImplementation,
InfobarPasswordModalDelegate>
// Delegate that holds the Infobar information and actions.
@property(nonatomic, readonly)
IOSChromeSavePasswordInfoBarDelegate* passwordInfoBarDelegate;
// InfobarBannerViewController owned by this Coordinator.
@property(nonatomic, strong) InfobarBannerViewController* bannerViewController;
// InfobarPasswordTableViewController owned by this Coordinator.
@property(nonatomic, strong)
InfobarPasswordTableViewController* modalViewController;
// The InfobarType for the banner presented by this Coordinator.
@property(nonatomic, assign, readonly) InfobarType infobarBannerType;
@end
@implementation InfobarPasswordCoordinator
// Synthesize since readonly property from superclass is changed to readwrite.
@synthesize bannerViewController = _bannerViewController;
// Synthesize since readonly property from superclass is changed to readwrite.
@synthesize modalViewController = _modalViewController;
- (instancetype)initWithInfoBarDelegate:(IOSChromeSavePasswordInfoBarDelegate*)
passwordInfoBarDelegate
type:(InfobarType)infobarType {
self = [super initWithInfoBarDelegate:passwordInfoBarDelegate
type:infobarType];
if (self) {
_passwordInfoBarDelegate = passwordInfoBarDelegate;
// Set |_infobarBannerType| at init time since
// passwordInfoBarDelegate->IsPasswordUpdate() can change after the user has
// interacted with the ModalInfobar.
_infobarBannerType = infobarType;
}
return self;
}
#pragma mark - ChromeCoordinator
- (void)start {
if (!self.started) {
self.started = YES;
self.bannerViewController = [[InfobarBannerViewController alloc]
initWithDelegate:self
type:self.infobarBannerType];
self.bannerViewController.titleText = base::SysUTF16ToNSString(
self.passwordInfoBarDelegate->GetMessageText());
NSString* username = self.passwordInfoBarDelegate->GetUserNameText();
NSString* password = self.passwordInfoBarDelegate->GetPasswordText();
password = [@"" stringByPaddingToLength:[password length]
withString:@"•"
startingAtIndex:0];
self.bannerViewController.subTitleText =
[NSString stringWithFormat:@"%@ %@", username, password];
self.bannerViewController.buttonText =
base::SysUTF16ToNSString(self.passwordInfoBarDelegate->GetButtonLabel(
ConfirmInfoBarDelegate::BUTTON_OK));
self.bannerViewController.iconImage =
[UIImage imageNamed:@"infobar_passwords_icon"];
NSString* hiddenPasswordText =
l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_HIDDEN_LABEL);
self.bannerViewController.optionalAccessibilityLabel = [NSString
stringWithFormat:@"%@,%@, %@", self.bannerViewController.titleText,
username, hiddenPasswordText];
}
}
- (void)stop {
if (self.started) {
self.started = NO;
// RemoveInfoBar() will delete the InfobarIOS that owns this Coordinator
// from memory.
self.delegate->RemoveInfoBar();
_passwordInfoBarDelegate = nil;
[self.infobarContainer childCoordinatorStopped];
}
}
#pragma mark - InfobarCoordinatorImplementation
- (void)configureModalViewController {
// Do not use |self.infobarBannerType| since the modal type might change each
// time is presented. e.g. We present a Modal of type Save and tap on "Save".
// The next time the Modal is presented we'll present a Modal of Type "Update"
// since the credentials are currently saved.
InfobarType infobarModalType =
self.passwordInfoBarDelegate->IsPasswordUpdate()
? InfobarType::kInfobarTypePasswordUpdate
: InfobarType::kInfobarTypePasswordSave;
self.modalViewController = [[InfobarPasswordTableViewController alloc]
initWithDelegate:self
type:infobarModalType];
self.modalViewController.title =
self.passwordInfoBarDelegate->GetInfobarModalTitleText();
self.modalViewController.username =
self.passwordInfoBarDelegate->GetUserNameText();
NSString* password = self.passwordInfoBarDelegate->GetPasswordText();
self.modalViewController.maskedPassword =
[@"" stringByPaddingToLength:[password length]
withString:@"•"
startingAtIndex:0];
self.modalViewController.unmaskedPassword = password;
self.modalViewController.detailsTextMessage =
self.passwordInfoBarDelegate->GetDetailsMessageText();
self.modalViewController.saveButtonText =
base::SysUTF16ToNSString(self.passwordInfoBarDelegate->GetButtonLabel(
ConfirmInfoBarDelegate::BUTTON_OK));
self.modalViewController.cancelButtonText =
base::SysUTF16ToNSString(self.passwordInfoBarDelegate->GetButtonLabel(
ConfirmInfoBarDelegate::BUTTON_CANCEL));
self.modalViewController.URL = self.passwordInfoBarDelegate->GetURLHostText();
self.modalViewController.currentCredentialsSaved =
self.passwordInfoBarDelegate->IsCurrentPasswordSaved();
[self recordModalPresentationMetricsUsingModalType:infobarModalType];
}
- (void)infobarBannerWasPresented {
// There's a chance the Delegate was destroyed while the presentation was
// taking place e.g. User navigated away. Check if the delegate still exists.
if (self.passwordInfoBarDelegate)
self.passwordInfoBarDelegate->InfobarPresenting(YES /*automatic*/);
}
- (void)infobarModalPresentedFromBanner:(BOOL)presentedFromBanner {
// If the modal is being expanded from the banner we count that as the same
// presentation from infobarBannerWasPresented.
if (presentedFromBanner)
return;
self.passwordInfoBarDelegate->InfobarPresenting(NO /*automatic*/);
}
- (void)dismissBannerWhenInteractionIsFinished {
[self.bannerViewController dismissWhenInteractionIsFinished];
}
- (void)performInfobarAction {
self.passwordInfoBarDelegate->Accept();
}
- (void)infobarWasDismissed {
// Release these strong ViewControllers at the time of infobar dismissal.
self.bannerViewController = nil;
self.modalViewController = nil;
// While navigating away the Infobar delegate might be niled before the banner
// has been dismissed. Check that the delegate still exists.
if (self.passwordInfoBarDelegate)
self.passwordInfoBarDelegate->InfobarDismissed();
}
- (CGFloat)infobarModalContentHeight {
UITableView* tableView = self.modalViewController.tableView;
[tableView setNeedsLayout];
[tableView layoutIfNeeded];
return tableView.contentSize.height;
}
#pragma mark - InfobarPasswordModalDelegate
- (void)updateCredentialsWithUsername:(NSString*)username
password:(NSString*)password {
self.passwordInfoBarDelegate->UpdateCredentials(username, password);
[self modalInfobarButtonWasAccepted:self];
}
- (void)neverSaveCredentialsForCurrentSite {
self.passwordInfoBarDelegate->Cancel();
// Completely remove the Infobar along with its badge after blacklisting the
// Website.
[self detachView];
}
- (void)presentPasswordSettings {
DCHECK(self.dispatcher);
[self
dismissInfobarModal:self
animated:NO
completion:^{
[self.dispatcher showSavedPasswordsSettingsFromViewController:
self.baseViewController];
}];
}
#pragma mark - Helpers
- (void)recordModalPresentationMetricsUsingModalType:
(InfobarType)infobarModalType {
IOSChromePasswordInfobarMetricsRecorder* passwordMetricsRecorder;
switch (infobarModalType) {
case InfobarType::kInfobarTypePasswordUpdate:
passwordMetricsRecorder = [[IOSChromePasswordInfobarMetricsRecorder alloc]
initWithType:PasswordInfobarType::kPasswordInfobarTypeUpdate];
break;
case InfobarType::kInfobarTypePasswordSave:
passwordMetricsRecorder = [[IOSChromePasswordInfobarMetricsRecorder alloc]
initWithType:PasswordInfobarType::kPasswordInfobarTypeSave];
break;
default:
NOTREACHED();
break;
}
switch (self.infobarBannerType) {
case InfobarType::kInfobarTypePasswordUpdate:
[passwordMetricsRecorder
recordModalPresent:MobileMessagesPasswordsModalPresent::
PresentedAfterUpdateBanner];
break;
case InfobarType::kInfobarTypePasswordSave:
[passwordMetricsRecorder
recordModalPresent:MobileMessagesPasswordsModalPresent::
PresentedAfterSaveBanner];
break;
default:
NOTREACHED();
break;
}
}
@end