[go: nahoru, domu]

blob: 7100ea864bbbd4ec35ad9c1fa4d257705786bf80 [file] [log] [blame]
// 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_checkup/password_checkup_view_controller.h"
#import "base/apple/foundation_util.h"
#import "base/metrics/user_metrics.h"
#import "base/strings/string_number_conversions.h"
#import "components/google/core/common/google_util.h"
#import "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/net/crurl.h"
#import "ios/chrome/browser/passwords/password_checkup_metrics.h"
#import "ios/chrome/browser/passwords/password_checkup_utils.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_item.h"
#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
#import "ios/chrome/browser/ui/settings/cells/settings_check_cell.h"
#import "ios/chrome/browser/ui/settings/cells/settings_check_item.h"
#import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_commands.h"
#import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_constants.h"
#import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_consumer.h"
#import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller_delegate.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util.h"
using password_manager::InsecurePasswordCounts;
using password_manager::WarningType;
namespace {
// Height of the image used as a header for the table view.
constexpr CGFloat kHeaderImageHeight = 99;
// Sections of the Password Checkup Homepage UI.
typedef NS_ENUM(NSInteger, SectionIdentifier) {
SectionIdentifierInsecureTypes = kSectionIdentifierEnumZero,
SectionIdentifierLastPasswordCheckup,
};
// Items within the Password Checkup Homepage UI.
typedef NS_ENUM(NSInteger, ItemType) {
// Section: SectionIdentifierInsecureTypes
ItemTypeCompromisedPasswords = kItemTypeEnumZero,
ItemTypeReusedPasswords,
ItemTypeWeakPasswords,
// Section: SectionIdentifierLastPasswordCheckup
ItemTypePasswordCheckupTimestamp,
ItemTypeCheckPasswordsButton,
ItemTypePasswordCheckupDescriptionFooter,
};
// Helper method to get the right header image depending on the
// `password_checkup_state`.
UIImage* GetHeaderImage(PasswordCheckupHomepageState password_checkup_state,
InsecurePasswordCounts counts) {
bool has_compromised_passwords = counts.compromised_count > 0;
bool has_insecure_passwords =
counts.compromised_count > 0 || counts.dismissed_count > 0 ||
counts.reused_count > 0 || counts.weak_count > 0;
switch (password_checkup_state) {
case PasswordCheckupHomepageStateDone:
if (has_compromised_passwords) {
return [UIImage
imageNamed:password_manager::kPasswordCheckupHeaderImageRed];
} else if (has_insecure_passwords) {
return [UIImage
imageNamed:password_manager::kPasswordCheckupHeaderImageYellow];
}
return [UIImage
imageNamed:password_manager::kPasswordCheckupHeaderImageGreen];
case PasswordCheckupHomepageStateRunning:
return [UIImage
imageNamed:password_manager::kPasswordCheckupHeaderImageLoading];
case PasswordCheckupHomepageStateDisabled:
return nil;
}
}
NSString* GetCompromisedPasswordsItemDetailText(bool has_compromised_passwords,
bool has_dismissed_warnings,
int dismissed_count) {
NSString* detailText;
if (has_compromised_passwords) {
detailText = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_COMPROMISED_PASSWORDS_SUBTITLE);
} else if (has_dismissed_warnings) {
detailText = l10n_util::GetPluralNSStringF(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_DISMISSED_WARNINGS_SUBTITLE,
dismissed_count);
} else {
detailText = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_NO_COMPROMISED_PASSWORDS_SUBTITLE);
}
return detailText;
}
// Sets up the trailing icon and the accessory type of the given `item`
// depending on the `password_checkup_state`, whether there are insecure
// passwords and whether the insecure passwords are compromised. This is used to
// set up the items in the insecure types section.
void SetUpTrailingIconAndAccessoryType(
PasswordCheckupHomepageState password_checkup_state,
SettingsCheckItem* item,
BOOL has_insecure_passwords,
BOOL has_compromised_passwords = false) {
item.indicatorHidden = YES;
item.accessoryType = UITableViewCellAccessoryNone;
switch (password_checkup_state) {
case PasswordCheckupHomepageStateDone:
if (has_insecure_passwords) {
item.warningState = has_compromised_passwords
? WarningState::kSevereWarning
: WarningState::kWarning;
item.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else {
item.warningState = WarningState::kSafe;
}
break;
case PasswordCheckupHomepageStateRunning: {
item.trailingImage = nil;
item.indicatorHidden = NO;
break;
}
case PasswordCheckupHomepageStateDisabled:
break;
}
}
} // namespace
@interface PasswordCheckupViewController () {
// Whether the consumer has been updated at least once.
BOOL _consumerHasBeenUpdated;
// The item related to the compromised passwords.
SettingsCheckItem* _compromisedPasswordsItem;
// The item related to the reused passwords.
SettingsCheckItem* _reusedPasswordsItem;
// The item related to the weak passwords.
SettingsCheckItem* _weakPasswordsItem;
// The item related to the timestamp of the last password check.
SettingsCheckItem* _passwordCheckupTimestampItem;
// The button to start password check.
TableViewTextItem* _checkPasswordsButtonItem;
// The footer item briefly explaining the purpose of Password Checkup.
TableViewLinkHeaderFooterItem* _passwordCheckupDescriptionFooterItem;
// Whether Settings have been dismissed.
BOOL _settingsAreDismissed;
// Current PasswordCheckupHomepageState.
PasswordCheckupHomepageState _passwordCheckupState;
// Password counts associated with the different insecure types.
InsecurePasswordCounts _insecurePasswordCounts;
// The string containing the timestamp of the last completed check.
NSString* _formattedElapsedTimeSinceLastCheck;
// The number of affiliated groups for which the user has saved passwords.
NSInteger _affiliatedGroupCount;
// Image view at the top of the screen, indicating the overall Password
// Checkup status.
UIImageView* _headerImageView;
// Whether the previous password checkup state was the running state.
BOOL _wasRunning;
}
@end
@implementation PasswordCheckupViewController
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.accessibilityIdentifier =
password_manager::kPasswordCheckupTableViewId;
self.title = l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECKUP);
_headerImageView = [self createHeaderImageView];
[self updateHeaderImage];
[self updateTableViewHeaderView];
[self loadModel];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Update the navigation bar background color as it is different for the
// PasswordCheckupViewController than for its parent.
[self updateNavigationBarBackgroundColorForDismissal:NO];
}
- (void)willMoveToParentViewController:(UIViewController*)parent {
[super willMoveToParentViewController:parent];
if (!parent) {
// Reset the navigation bar background color to what it was before getting
// to the PasswordCheckupViewController.
[self updateNavigationBarBackgroundColorForDismissal:YES];
}
}
- (void)didMoveToParentViewController:(UIViewController*)parent {
[super didMoveToParentViewController:parent];
if (!parent) {
[self.handler dismissPasswordCheckupViewController];
}
}
- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
[super traitCollectionDidChange:previousTraitCollection];
if (self.traitCollection.verticalSizeClass !=
previousTraitCollection.verticalSizeClass) {
[self updateNavigationBarBackgroundColorForDismissal:NO];
[self updateTableViewHeaderView];
}
}
#pragma mark - SettingsRootTableViewController
- (void)loadModel {
[super loadModel];
TableViewModel* model = self.tableViewModel;
// Insecure types section.
[model addSectionWithIdentifier:SectionIdentifierInsecureTypes];
if (!_compromisedPasswordsItem) {
_compromisedPasswordsItem = [self compromisedPasswordsItem];
}
[model addItem:_compromisedPasswordsItem
toSectionWithIdentifier:SectionIdentifierInsecureTypes];
if (!_reusedPasswordsItem) {
_reusedPasswordsItem = [self reusedPasswordsItem];
}
[model addItem:_reusedPasswordsItem
toSectionWithIdentifier:SectionIdentifierInsecureTypes];
if (!_weakPasswordsItem) {
_weakPasswordsItem = [self weakPasswordsItem];
}
[model addItem:_weakPasswordsItem
toSectionWithIdentifier:SectionIdentifierInsecureTypes];
// Last password checkup section.
[model addSectionWithIdentifier:SectionIdentifierLastPasswordCheckup];
if (!_passwordCheckupTimestampItem) {
_passwordCheckupTimestampItem = [self passwordCheckupTimestampItem];
}
[model addItem:_passwordCheckupTimestampItem
toSectionWithIdentifier:SectionIdentifierLastPasswordCheckup];
if (!_checkPasswordsButtonItem) {
_checkPasswordsButtonItem = [self checkPasswordsButtonItem];
}
[model addItem:_checkPasswordsButtonItem
toSectionWithIdentifier:SectionIdentifierLastPasswordCheckup];
if (!_passwordCheckupDescriptionFooterItem) {
_passwordCheckupDescriptionFooterItem =
[self passwordCheckupDescriptionFooterItem];
}
[model setFooter:_passwordCheckupDescriptionFooterItem
forSectionWithIdentifier:SectionIdentifierLastPasswordCheckup];
if (_consumerHasBeenUpdated) {
[self updateItemsDependingOnPasswordCheckupState];
}
[self updatePasswordCheckupTimestampDetailText];
}
#pragma mark - Items
- (SettingsCheckItem*)compromisedPasswordsItem {
SettingsCheckItem* compromisedPasswordsItem =
[[SettingsCheckItem alloc] initWithType:ItemTypeCompromisedPasswords];
compromisedPasswordsItem.enabled = YES;
compromisedPasswordsItem.indicatorHidden = YES;
compromisedPasswordsItem.infoButtonHidden = YES;
compromisedPasswordsItem.accessibilityIdentifier =
password_manager::kPasswordCheckupCompromisedPasswordsItemId;
return compromisedPasswordsItem;
}
- (SettingsCheckItem*)reusedPasswordsItem {
SettingsCheckItem* reusedPasswordsItem =
[[SettingsCheckItem alloc] initWithType:ItemTypeReusedPasswords];
reusedPasswordsItem.enabled = YES;
reusedPasswordsItem.indicatorHidden = YES;
reusedPasswordsItem.infoButtonHidden = YES;
reusedPasswordsItem.accessibilityIdentifier =
password_manager::kPasswordCheckupReusedPasswordsItemId;
return reusedPasswordsItem;
}
- (SettingsCheckItem*)weakPasswordsItem {
SettingsCheckItem* weakPasswordsItem =
[[SettingsCheckItem alloc] initWithType:ItemTypeWeakPasswords];
weakPasswordsItem.enabled = YES;
weakPasswordsItem.indicatorHidden = YES;
weakPasswordsItem.infoButtonHidden = YES;
weakPasswordsItem.accessibilityIdentifier =
password_manager::kPasswordCheckupWeakPasswordsItemId;
return weakPasswordsItem;
}
- (SettingsCheckItem*)passwordCheckupTimestampItem {
SettingsCheckItem* passwordCheckupTimestampItem =
[[SettingsCheckItem alloc] initWithType:ItemTypePasswordCheckupTimestamp];
passwordCheckupTimestampItem.enabled = YES;
passwordCheckupTimestampItem.indicatorHidden = YES;
passwordCheckupTimestampItem.infoButtonHidden = YES;
return passwordCheckupTimestampItem;
}
- (TableViewTextItem*)checkPasswordsButtonItem {
TableViewTextItem* checkPasswordsButtonItem =
[[TableViewTextItem alloc] initWithType:ItemTypeCheckPasswordsButton];
checkPasswordsButtonItem.text = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_CHECK_AGAIN_BUTTON);
checkPasswordsButtonItem.textColor = [UIColor colorNamed:kBlueColor];
checkPasswordsButtonItem.accessibilityTraits = UIAccessibilityTraitButton;
return checkPasswordsButtonItem;
}
- (TableViewLinkHeaderFooterItem*)passwordCheckupDescriptionFooterItem {
TableViewLinkHeaderFooterItem* footerItem =
[[TableViewLinkHeaderFooterItem alloc]
initWithType:ItemTypePasswordCheckupDescriptionFooter];
footerItem.text =
l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_FOOTER);
CrURL* footerURL = [[CrURL alloc]
initWithGURL:
google_util::AppendGoogleLocaleParam(
GURL(password_manager::
kPasswordManagerHelpCenterChangeUnsafePasswordsURL),
GetApplicationContext()->GetApplicationLocale())];
footerItem.urls = @[ footerURL ];
return footerItem;
}
#pragma mark - SettingsControllerProtocol
- (void)reportDismissalUserAction {
base::RecordAction(
base::UserMetricsAction("MobilePasswordCheckupSettingsClose"));
}
- (void)reportBackUserAction {
base::RecordAction(
base::UserMetricsAction("MobilePasswordCheckupSettingsBack"));
}
- (void)settingsWillBeDismissed {
DCHECK(!_settingsAreDismissed);
_settingsAreDismissed = YES;
}
#pragma mark - PasswordCheckupConsumer
- (void)setPasswordCheckupHomepageState:(PasswordCheckupHomepageState)state
insecurePasswordCounts:
(InsecurePasswordCounts)insecurePasswordCounts
formattedElapsedTimeSinceLastCheck:
(NSString*)formattedElapsedTimeSinceLastCheck {
// If the consumer has been updated at least once and the state and insecure
// password counts haven't changed, there is no need to update anything.
if (_consumerHasBeenUpdated && _passwordCheckupState == state &&
_insecurePasswordCounts == insecurePasswordCounts) {
return;
}
// If state is PasswordCheckupHomepageStateDisabled, it means that there is no
// saved password to check, so we return to the Password Manager.
if (state == PasswordCheckupHomepageStateDisabled) {
[self.handler dismissAfterAllPasswordsGone];
}
// If the previous state was PasswordCheckupHomepageStateRunning, focus
// accessibility on the Compromised Passwords cell to let the user know that
// the Password Checkup results are available.
if (_passwordCheckupState == PasswordCheckupHomepageStateRunning) {
[self focusAccessibilityOnCellForItemType:ItemTypeCompromisedPasswords
sectionIdentifier:SectionIdentifierInsecureTypes];
}
_passwordCheckupState = state;
_insecurePasswordCounts = insecurePasswordCounts;
_formattedElapsedTimeSinceLastCheck = formattedElapsedTimeSinceLastCheck;
[self updateItemsDependingOnPasswordCheckupState];
_consumerHasBeenUpdated = YES;
}
- (void)setAffiliatedGroupCount:(NSInteger)affiliatedGroupCount {
// If the affiliated group count hasn't changed, there is no need to update
// the item.
if (_affiliatedGroupCount == affiliatedGroupCount) {
return;
}
_affiliatedGroupCount = affiliatedGroupCount;
[self updatePasswordCheckupTimestampDetailText];
}
// TODO(crbug.com/1453276): Make the coordinator present the alert instead.
- (void)showErrorDialogWithMessage:(NSString*)message {
NSString* title = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_ERROR_DIALOG_TITLE);
UIAlertController* alert =
[UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* okAction =
[UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_OK)
style:UIAlertActionStyleDefault
handler:nil];
// TODO(crbug.com/1453276): Once fixed, setting the accessibilityIdentifier
// will no longer be neeeded since it will be handled by the AlertCoordinator.
okAction.accessibilityIdentifier =
[l10n_util::GetNSString(IDS_OK) stringByAppendingString:@"AlertAction"];
[alert addAction:okAction];
[self presentViewController:alert animated:YES completion:nil];
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView*)tableView
didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
TableViewModel* model = self.tableViewModel;
ItemType itemType =
static_cast<ItemType>([model itemTypeForIndexPath:indexPath]);
switch (itemType) {
case ItemTypeCompromisedPasswords:
[self showPasswordIssuesWithWarningType:WarningType::
kCompromisedPasswordsWarning];
break;
case ItemTypeReusedPasswords:
[self showPasswordIssuesWithWarningType:WarningType::
kReusedPasswordsWarning];
break;
case ItemTypeWeakPasswords:
[self
showPasswordIssuesWithWarningType:WarningType::kWeakPasswordsWarning];
break;
case ItemTypePasswordCheckupTimestamp:
case ItemTypePasswordCheckupDescriptionFooter:
break;
case ItemTypeCheckPasswordsButton:
if (_checkPasswordsButtonItem.isEnabled) {
password_manager::LogStartPasswordCheckManually();
[self.delegate startPasswordCheck];
// Focus accessibility on the Password Checkup Timestamp cell to let the
// user know that their passwords are being checked.
[self
focusAccessibilityOnCellForItemType:ItemTypePasswordCheckupTimestamp
sectionIdentifier:
SectionIdentifierLastPasswordCheckup];
}
break;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (BOOL)tableView:(UITableView*)tableView
shouldHighlightRowAtIndexPath:(NSIndexPath*)indexPath {
NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
switch (itemType) {
case ItemTypeCompromisedPasswords:
return _compromisedPasswordsItem.accessoryType ==
UITableViewCellAccessoryDisclosureIndicator;
case ItemTypeReusedPasswords:
return _reusedPasswordsItem.accessoryType ==
UITableViewCellAccessoryDisclosureIndicator;
case ItemTypeWeakPasswords:
return _weakPasswordsItem.accessoryType ==
UITableViewCellAccessoryDisclosureIndicator;
case ItemTypePasswordCheckupTimestamp:
return NO;
case ItemTypeCheckPasswordsButton:
return _checkPasswordsButtonItem.isEnabled;
}
return YES;
}
- (UIView*)tableView:(UITableView*)tableView
viewForFooterInSection:(NSInteger)section {
UIView* view = [super tableView:tableView viewForFooterInSection:section];
NSInteger sectionIdentifier =
[self.tableViewModel sectionIdentifierForSectionIndex:section];
if (sectionIdentifier == SectionIdentifierLastPasswordCheckup &&
[self.tableViewModel footerForSectionIndex:section]) {
// Attach self as delegate to handle clicks in page footer.
TableViewLinkHeaderFooterView* footerView =
base::apple::ObjCCastStrict<TableViewLinkHeaderFooterView>(view);
footerView.delegate = self;
}
return view;
}
#pragma mark - TableViewLinkHeaderFooterItemDelegate
- (void)view:(TableViewLinkHeaderFooterView*)view didTapLinkURL:(CrURL*)URL {
[self.handler dismissAndOpenURL:URL];
}
#pragma mark - Private
// Creates the header image view.
- (UIImageView*)createHeaderImageView {
UIImageView* headerImageView = [[UIImageView alloc] init];
headerImageView.contentMode = UIViewContentModeScaleAspectFill;
headerImageView.frame = CGRectMake(0, 0, 0, kHeaderImageHeight);
headerImageView.accessibilityIdentifier =
password_manager::kPasswordCheckupHeaderImageViewId;
return headerImageView;
}
// Updates the background color of the navigation bar. When iPhones are in
// landscape mode, we want to hide the header image, and so we want to update
// the background color of the navigation bar accordingly. We also want to set
// the background color back to `nil` when returning to the previous view
// controller to cleanup the color change made in this view controller.
- (void)updateNavigationBarBackgroundColorForDismissal:
(BOOL)viewControllerWillBeDismissed {
if (viewControllerWillBeDismissed || IsCompactHeight(self)) {
self.navigationController.navigationBar.backgroundColor = nil;
return;
}
self.navigationController.navigationBar.backgroundColor =
[UIColor colorNamed:@"password_checkup_header_background_color"];
}
// Updates the table view's header view depending on whether the header image
// view should be shown or not. When we're in iPhone landscape mode, we want to
// hide the image header view.
- (void)updateTableViewHeaderView {
if (IsCompactHeight(self)) {
self.tableView.tableHeaderView = nil;
} else {
self.tableView.tableHeaderView = _headerImageView;
}
}
// Updates the header image according to the current
// PasswordCheckupHomepageState.
- (void)updateHeaderImage {
switch (_passwordCheckupState) {
case PasswordCheckupHomepageStateDone:
case PasswordCheckupHomepageStateRunning: {
UIImage* headerImage =
GetHeaderImage(_passwordCheckupState, _insecurePasswordCounts);
[_headerImageView setImage:headerImage];
break;
}
case PasswordCheckupHomepageStateDisabled:
break;
}
}
// Updates the `_compromisedPasswordsItem`.
- (void)updateCompromisedPasswordsItem {
if (!_compromisedPasswordsItem) {
return;
}
BOOL hasCompromisedPasswords = _insecurePasswordCounts.compromised_count > 0;
BOOL hasDismissedWarnings = _insecurePasswordCounts.dismissed_count > 0;
_compromisedPasswordsItem.text = l10n_util::GetPluralNSStringF(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_COMPROMISED_PASSWORDS_TITLE,
_insecurePasswordCounts.compromised_count);
_compromisedPasswordsItem.detailText = GetCompromisedPasswordsItemDetailText(
hasCompromisedPasswords, hasDismissedWarnings,
_insecurePasswordCounts.dismissed_count);
SetUpTrailingIconAndAccessoryType(
_passwordCheckupState, _compromisedPasswordsItem,
hasDismissedWarnings || hasCompromisedPasswords, hasCompromisedPasswords);
[self reconfigureCellsForItems:@[ _compromisedPasswordsItem ]];
}
// Updates the `_reusedPasswordsItem`.
- (void)updateReusedPasswordsItem {
if (!_reusedPasswordsItem) {
return;
}
BOOL hasReusedPasswords = _insecurePasswordCounts.reused_count > 0;
NSString* text;
NSString* detailText;
if (hasReusedPasswords) {
text = l10n_util::GetNSStringF(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_REUSED_PASSWORDS_TITLE,
base::NumberToString16(_insecurePasswordCounts.reused_count));
detailText = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_REUSED_PASSWORDS_SUBTITLE);
} else {
text = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_NO_REUSED_PASSWORDS_TITLE);
detailText = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_NO_REUSED_PASSWORDS_SUBTITLE);
}
_reusedPasswordsItem.text = text;
_reusedPasswordsItem.detailText = detailText;
SetUpTrailingIconAndAccessoryType(_passwordCheckupState, _reusedPasswordsItem,
hasReusedPasswords);
[self reconfigureCellsForItems:@[ _reusedPasswordsItem ]];
}
// Updates the `_weakPasswordsItem`.
- (void)updateWeakPasswordsItem {
if (!_weakPasswordsItem) {
return;
}
BOOL hasWeakPasswords = _insecurePasswordCounts.weak_count > 0;
NSString* text;
NSString* detailText;
if (hasWeakPasswords) {
text = l10n_util::GetPluralNSStringF(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_WEAK_PASSWORDS_TITLE,
_insecurePasswordCounts.weak_count);
detailText = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_WEAK_PASSWORDS_SUBTITLE);
} else {
text = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_NO_WEAK_PASSWORDS_TITLE);
detailText = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECKUP_HOMEPAGE_NO_WEAK_PASSWORDS_SUBTITLE);
}
_weakPasswordsItem.text = text;
_weakPasswordsItem.detailText = detailText;
SetUpTrailingIconAndAccessoryType(_passwordCheckupState, _weakPasswordsItem,
hasWeakPasswords);
[self reconfigureCellsForItems:@[ _weakPasswordsItem ]];
}
// Updates the `_passwordCheckupTimestampItem` text.
- (void)updatePasswordCheckupTimestampText {
if (!_passwordCheckupTimestampItem) {
return;
}
switch (_passwordCheckupState) {
case PasswordCheckupHomepageStateRunning: {
_passwordCheckupTimestampItem.text =
l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECKUP_ONGOING);
_passwordCheckupTimestampItem.indicatorHidden = NO;
break;
}
case PasswordCheckupHomepageStateDone:
case PasswordCheckupHomepageStateDisabled:
_passwordCheckupTimestampItem.text = _formattedElapsedTimeSinceLastCheck;
_passwordCheckupTimestampItem.indicatorHidden = YES;
break;
}
[self reconfigureCellsForItems:@[ _passwordCheckupTimestampItem ]];
}
// Updates the `_passwordCheckupTimestampItem` detail text.
- (void)updatePasswordCheckupTimestampDetailText {
if (!_passwordCheckupTimestampItem) {
return;
}
_passwordCheckupTimestampItem.detailText = l10n_util::GetPluralNSStringF(
IDS_IOS_PASSWORD_CHECKUP_SITES_AND_APPS_COUNT, _affiliatedGroupCount);
[self reconfigureCellsForItems:@[ _passwordCheckupTimestampItem ]];
}
// Updates the `_checkPasswordsButtonItem`.
- (void)updateCheckPasswordsButtonItem {
if (!_checkPasswordsButtonItem) {
return;
}
if (_passwordCheckupState == PasswordCheckupHomepageStateRunning) {
_checkPasswordsButtonItem.enabled = NO;
_checkPasswordsButtonItem.textColor =
[UIColor colorNamed:kTextSecondaryColor];
_checkPasswordsButtonItem.accessibilityTraits |=
UIAccessibilityTraitNotEnabled;
} else {
_checkPasswordsButtonItem.enabled = YES;
_checkPasswordsButtonItem.textColor = [UIColor colorNamed:kBlueColor];
_checkPasswordsButtonItem.accessibilityTraits &=
~UIAccessibilityTraitNotEnabled;
}
[self reconfigureCellsForItems:@[ _checkPasswordsButtonItem ]];
}
// Updates all items whose content is depending on `_passwordCheckupState`.
- (void)updateItemsDependingOnPasswordCheckupState {
// Make these updates in a `performBatchUpdates` completion block to make sure
// the cell's height adjust if the new content takes up more lines than the
// current one.
[self.tableView
performBatchUpdates:^{
[self updateHeaderImage];
[self updateCompromisedPasswordsItem];
[self updateReusedPasswordsItem];
[self updateWeakPasswordsItem];
[self updatePasswordCheckupTimestampText];
[self updateCheckPasswordsButtonItem];
}
completion:nil];
}
// Opens the Password Issues list for the given `warningType` and resets the
// navigation bar background color to what it was before getting to the
// PasswordCheckupViewController.
- (void)showPasswordIssuesWithWarningType:(WarningType)warningType {
[self.handler showPasswordIssuesWithWarningType:warningType];
[self updateNavigationBarBackgroundColorForDismissal:YES];
}
// Notifies accessibility to focus on the cell for the given ItemType and
// SectionIdentifierCompromised when its layout changed.
- (void)focusAccessibilityOnCellForItemType:(ItemType)itemType
sectionIdentifier:
(SectionIdentifier)sectionIdentifier {
if (!UIAccessibilityIsVoiceOverRunning() ||
![self.tableViewModel hasItemForItemType:itemType
sectionIdentifier:sectionIdentifier]) {
return;
}
NSIndexPath* indexPath =
[self.tableViewModel indexPathForItemType:itemType
sectionIdentifier:sectionIdentifier];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,
cell);
}
@end