Commit 115ebd8b authored by harrisonsean's avatar harrisonsean Committed by Commit Bot

[iOS][Safety Check] Add further password support, ok and issues

Add support for safety check safe state and issues.

Issues support includes deleting/managing in settings and on site.

Add support for password check error popovers.

Tests coming in later cl

Bug: 1078782
Change-Id: I6c2b388fce4d397a1c1e01d161b4e0b35c91e9b3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2339322Reviewed-by: default avatarJavier Ernesto Flores Robles <javierrobles@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Commit-Queue: Sean Harrison <harrisonsean@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797251}
parent 945fdda1
...@@ -331,6 +331,9 @@ locale. The strings in this file are specific to iOS. ...@@ -331,6 +331,9 @@ locale. The strings in this file are specific to iOS.
<message name="IDS_IOS_PASSWORD_CHECK_ERROR" desc="Description of the password check cell, explaining that Password Check failed. [iOS only]" meaning="Password Check failed due to some error."> <message name="IDS_IOS_PASSWORD_CHECK_ERROR" desc="Description of the password check cell, explaining that Password Check failed. [iOS only]" meaning="Password Check failed due to some error.">
Chromium can't check your passwords Chromium can't check your passwords
</message> </message>
<message name="IDS_IOS_PASSWORD_CHECK_ERROR_NO_PASSWORDS" desc="Description text for when password check cannot be run because the user has no saved passwords">
No saved passwords. Chromium can check your passwords when you save them.
</message>
<message name="IDS_IOS_PASSWORD_CHECK_ERROR_OFFLINE" desc="Text inside popover which is shown when the user wants to see detailed information about the error. [iOS only]" meaning="The user has no internet connection and can't check passwords."> <message name="IDS_IOS_PASSWORD_CHECK_ERROR_OFFLINE" desc="Text inside popover which is shown when the user wants to see detailed information about the error. [iOS only]" meaning="The user has no internet connection and can't check passwords.">
Chromium couldn't check your passwords. Try checking your internet connection. Chromium couldn't check your passwords. Try checking your internet connection.
</message> </message>
......
79dd83f5a48633878501b3b1cc8eebd4123017b6
\ No newline at end of file
...@@ -331,6 +331,9 @@ locale. The strings in this file are specific to iOS. ...@@ -331,6 +331,9 @@ locale. The strings in this file are specific to iOS.
<message name="IDS_IOS_PASSWORD_CHECK_ERROR" desc="Description of the password check cell, explaining that Password Check failed. [iOS only]" meaning="Password Check failed due to some error."> <message name="IDS_IOS_PASSWORD_CHECK_ERROR" desc="Description of the password check cell, explaining that Password Check failed. [iOS only]" meaning="Password Check failed due to some error.">
Chrome can't check your passwords Chrome can't check your passwords
</message> </message>
<message name="IDS_IOS_PASSWORD_CHECK_ERROR_NO_PASSWORDS" desc="Description text for when password check cannot be run because the user has no saved passwords">
No saved passwords. Chrome can check your passwords when you save them.
</message>
<message name="IDS_IOS_PASSWORD_CHECK_ERROR_OFFLINE" desc="Text inside popover which is shown when the user wants to see detailed information about the error. [iOS only]" meaning="The user has no internet connection and can't check passwords."> <message name="IDS_IOS_PASSWORD_CHECK_ERROR_OFFLINE" desc="Text inside popover which is shown when the user wants to see detailed information about the error. [iOS only]" meaning="The user has no internet connection and can't check passwords.">
Chrome couldn't check your passwords. Try checking your internet connection. Chrome couldn't check your passwords. Try checking your internet connection.
</message> </message>
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include "base/mac/foundation_util.h" #include "base/mac/foundation_util.h"
#import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/main/browser.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h"
#import "ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h" #import "ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h"
#import "ios/chrome/browser/ui/settings/password/password_issue_with_form.h" #import "ios/chrome/browser/ui/settings/password/password_issue_with_form.h"
...@@ -52,6 +54,8 @@ ...@@ -52,6 +54,8 @@
if (self) { if (self) {
_baseNavigationController = navigationController; _baseNavigationController = navigationController;
_manager = manager; _manager = manager;
_dispatcher = HandlerForProtocol(self.browser->GetCommandDispatcher(),
ApplicationCommands);
} }
return self; return self;
} }
......
...@@ -1317,7 +1317,6 @@ std::vector<std::unique_ptr<autofill::PasswordForm>> CopyOf( ...@@ -1317,7 +1317,6 @@ std::vector<std::unique_ptr<autofill::PasswordForm>> CopyOf(
browser:_browser browser:_browser
passwordCheckManager:_passwordCheck.get()]; passwordCheckManager:_passwordCheck.get()];
_passwordIssuesCoordinator.delegate = self; _passwordIssuesCoordinator.delegate = self;
_passwordIssuesCoordinator.dispatcher = self.dispatcher;
_passwordIssuesCoordinator.reauthModule = _reauthenticationModule; _passwordIssuesCoordinator.reauthModule = _reauthenticationModule;
[_passwordIssuesCoordinator start]; [_passwordIssuesCoordinator start];
} }
......
...@@ -16,6 +16,8 @@ source_set("safety_check_ui") { ...@@ -16,6 +16,8 @@ source_set("safety_check_ui") {
"//ios/chrome/app/strings", "//ios/chrome/app/strings",
"//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui:feature_flags",
"//ios/chrome/browser/ui/settings:settings_root", "//ios/chrome/browser/ui/settings:settings_root",
"//ios/chrome/browser/ui/settings/cells",
"//ios/chrome/browser/ui/settings/cells:public",
"//ios/chrome/browser/ui/settings/utils", "//ios/chrome/browser/ui/settings/utils",
"//ios/chrome/browser/ui/table_view", "//ios/chrome/browser/ui/table_view",
"//ui/base", "//ui/base",
...@@ -43,16 +45,22 @@ source_set("safety_check") { ...@@ -43,16 +45,22 @@ source_set("safety_check") {
"//ios/chrome/browser/content_settings", "//ios/chrome/browser/content_settings",
"//ios/chrome/browser/main:public", "//ios/chrome/browser/main:public",
"//ios/chrome/browser/passwords", "//ios/chrome/browser/passwords",
"//ios/chrome/browser/signin",
"//ios/chrome/browser/sync",
"//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui:feature_flags",
"//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
"//ios/chrome/browser/ui/settings:settings_root", "//ios/chrome/browser/ui/settings:settings_root",
"//ios/chrome/browser/ui/settings/cells", "//ios/chrome/browser/ui/settings/cells",
"//ios/chrome/browser/ui/settings/cells:public", "//ios/chrome/browser/ui/settings/cells:public",
"//ios/chrome/browser/ui/settings/password",
"//ios/chrome/browser/ui/settings/utils", "//ios/chrome/browser/ui/settings/utils",
"//ios/chrome/browser/ui/table_view", "//ios/chrome/browser/ui/table_view",
"//ios/chrome/browser/ui/table_view/cells:cells_constants", "//ios/chrome/browser/ui/table_view/cells:cells_constants",
"//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util",
"//ios/chrome/common",
"//ios/chrome/common/ui/colors",
"//ios/chrome/common/ui/elements:popover_label_view_controller",
"//ui/base", "//ui/base",
] ]
frameworks = [ "UIKit.framework" ] frameworks = [ "UIKit.framework" ]
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
@protocol ApplicationCommands;
@class SafetyCheckCoordinator; @class SafetyCheckCoordinator;
// Delegate that allows to dereference the SafetyCheckCoordinator. // Delegate that allows to dereference the SafetyCheckCoordinator.
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
// The coordinator for the Safety Check screen. // The coordinator for the Safety Check screen.
@interface SafetyCheckCoordinator : ChromeCoordinator @interface SafetyCheckCoordinator : ChromeCoordinator
// Delegate to pass user interactions to the mediator.
@property(nonatomic, weak) id<SafetyCheckCoordinatorDelegate> delegate; @property(nonatomic, weak) id<SafetyCheckCoordinatorDelegate> delegate;
- (instancetype)initWithBaseViewController:(UIViewController*)viewController - (instancetype)initWithBaseViewController:(UIViewController*)viewController
......
...@@ -5,20 +5,32 @@ ...@@ -5,20 +5,32 @@
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.h" #import "ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.h"
#include "base/mac/foundation_util.h" #include "base/mac/foundation_util.h"
#include "base/memory/scoped_refptr.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/main/browser.h" #include "ios/chrome/browser/main/browser.h"
#include "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h" #include "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h"
#include "ios/chrome/browser/passwords/ios_chrome_password_check_manager_factory.h" #include "ios/chrome/browser/passwords/ios_chrome_password_check_manager_factory.h"
#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
#import "ios/chrome/browser/signin/authentication_service_factory.h"
#include "ios/chrome/browser/sync/profile_sync_service_factory.h"
#import "ios/chrome/browser/sync/sync_setup_service.h"
#import "ios/chrome/browser/sync/sync_setup_service_factory.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/browser_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/settings/password/password_issues_coordinator.h"
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.h" #import "ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.h"
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_navigation_commands.h" #import "ios/chrome/browser/ui/settings/safety_check/safety_check_navigation_commands.h"
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_table_view_controller.h" #import "ios/chrome/browser/ui/settings/safety_check/safety_check_table_view_controller.h"
#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
#import "ios/chrome/common/ui/elements/popover_label_view_controller.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
@interface SafetyCheckCoordinator () < @interface SafetyCheckCoordinator () <
PasswordIssuesCoordinatorDelegate,
SafetyCheckNavigationCommands, SafetyCheckNavigationCommands,
SafetyCheckTableViewControllerPresentationDelegate> SafetyCheckTableViewControllerPresentationDelegate>
...@@ -28,6 +40,13 @@ ...@@ -28,6 +40,13 @@
// The container view controller. // The container view controller.
@property(nonatomic, strong) SafetyCheckTableViewController* viewController; @property(nonatomic, strong) SafetyCheckTableViewController* viewController;
// Coordinator for passwords issues screen.
@property(nonatomic, strong)
PasswordIssuesCoordinator* passwordIssuesCoordinator;
// Dispatcher which can handle changing passwords on sites.
@property(nonatomic, strong) id<ApplicationCommands> handler;
@end @end
@implementation SafetyCheckCoordinator @implementation SafetyCheckCoordinator
...@@ -41,6 +60,8 @@ ...@@ -41,6 +60,8 @@
browser:browser]; browser:browser];
if (self) { if (self) {
_baseNavigationController = navigationController; _baseNavigationController = navigationController;
_handler = HandlerForProtocol(self.browser->GetCommandDispatcher(),
ApplicationCommands);
} }
return self; return self;
} }
...@@ -53,12 +74,18 @@ ...@@ -53,12 +74,18 @@
initWithStyle:UITableViewStylePlain]; initWithStyle:UITableViewStylePlain];
self.viewController = viewController; self.viewController = viewController;
scoped_refptr<IOSChromePasswordCheckManager> passwordCheckManager =
IOSChromePasswordCheckManagerFactory::GetForBrowserState(
self.browser->GetBrowserState());
self.mediator = [[SafetyCheckMediator alloc] self.mediator = [[SafetyCheckMediator alloc]
initWithUserPrefService:self.browser->GetBrowserState()->GetPrefs() initWithUserPrefService:self.browser->GetBrowserState()->GetPrefs()
passwordCheckManager:IOSChromePasswordCheckManagerFactory:: passwordCheckManager:passwordCheckManager
GetForBrowserState( authService:AuthenticationServiceFactory::GetForBrowserState(
self.browser->GetBrowserState())]; self.browser->GetBrowserState())
syncService:SyncSetupServiceFactory::GetForBrowserState(
self.browser->GetBrowserState())];
self.mediator.consumer = self.viewController; self.mediator.consumer = self.viewController;
self.mediator.handler = self;
self.viewController.serviceDelegate = self.mediator; self.viewController.serviceDelegate = self.mediator;
self.viewController.presentationDelegate = self; self.viewController.presentationDelegate = self;
...@@ -75,4 +102,57 @@ ...@@ -75,4 +102,57 @@
[self.delegate safetyCheckCoordinatorDidRemove:self]; [self.delegate safetyCheckCoordinatorDidRemove:self];
} }
#pragma mark - SafetyCheckNavigationCommands
- (void)showPasswordIssuesPage {
IOSChromePasswordCheckManager* passwordCheckManager =
IOSChromePasswordCheckManagerFactory::GetForBrowserState(
self.browser->GetBrowserState())
.get();
self.passwordIssuesCoordinator = [[PasswordIssuesCoordinator alloc]
initWithBaseNavigationController:self.baseNavigationController
browser:self.browser
passwordCheckManager:passwordCheckManager];
self.passwordIssuesCoordinator.delegate = self;
self.passwordIssuesCoordinator.reauthModule = nil;
[self.passwordIssuesCoordinator start];
}
- (void)showErrorInfoFrom:(UIButton*)buttonView
withText:(NSAttributedString*)text {
PopoverLabelViewController* errorInfoPopover =
[[PopoverLabelViewController alloc] initWithPrimaryAttributedString:text
secondaryAttributedString:nil];
errorInfoPopover.popoverPresentationController.sourceView = buttonView;
errorInfoPopover.popoverPresentationController.sourceRect = buttonView.bounds;
errorInfoPopover.popoverPresentationController.permittedArrowDirections =
UIPopoverArrowDirectionAny;
[self.viewController presentViewController:errorInfoPopover
animated:YES
completion:nil];
}
- (void)showUpdateOnAppStorePage {
// TODO(crbug.com/1078782): Add navigation to App Store Chrome page.
}
- (void)showSafeBrowsingPreferencePage {
// TODO(crbug.com/1078782): Add navigation to Safe Browsing preference page.
}
#pragma mark - PasswordIssuesCoordinatorDelegate
- (void)passwordIssuesCoordinatorDidRemove:
(PasswordIssuesCoordinator*)coordinator {
DCHECK_EQ(self.passwordIssuesCoordinator, coordinator);
[self.passwordIssuesCoordinator stop];
self.passwordIssuesCoordinator.delegate = nil;
self.passwordIssuesCoordinator = nil;
}
- (BOOL)willHandlePasswordDeletion:(const autofill::PasswordForm&)password {
return NO;
}
@end @end
...@@ -11,9 +11,12 @@ ...@@ -11,9 +11,12 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
class AuthenticationService;
class IOSChromePasswordCheckManager; class IOSChromePasswordCheckManager;
class PrefService; class PrefService;
@protocol SafetyCheckConsumer; @protocol SafetyCheckConsumer;
@protocol SafetyCheckNavigationCommands;
class SyncSetupService;
@class SafetyCheckTableViewController; @class SafetyCheckTableViewController;
...@@ -27,13 +30,19 @@ class PrefService; ...@@ -27,13 +30,19 @@ class PrefService;
- (instancetype)initWithUserPrefService:(PrefService*)userPrefService - (instancetype)initWithUserPrefService:(PrefService*)userPrefService
passwordCheckManager: passwordCheckManager:
(scoped_refptr<IOSChromePasswordCheckManager>) (scoped_refptr<IOSChromePasswordCheckManager>)
passwordCheckManager NS_DESIGNATED_INITIALIZER; passwordCheckManager
authService:(AuthenticationService*)authService
syncService:(SyncSetupService*)syncService
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE;
// The consumer for the Safety Check mediator. // The consumer for the Safety Check mediator.
@property(nonatomic, weak) id<SafetyCheckConsumer> consumer; @property(nonatomic, weak) id<SafetyCheckConsumer> consumer;
// Handler used to navigate inside the safety check.
@property(nonatomic, weak) id<SafetyCheckNavigationCommands> handler;
@end @end
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_SAFETY_CHECK_SAFETY_CHECK_MEDIATOR_H_ #endif // IOS_CHROME_BROWSER_UI_SETTINGS_SAFETY_CHECK_SAFETY_CHECK_MEDIATOR_H_
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.h" #import "ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.h"
#include "base/mac/foundation_util.h" #include "base/mac/foundation_util.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
#include "components/password_manager/core/common/password_manager_features.h" #include "components/password_manager/core/common/password_manager_features.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
...@@ -14,18 +18,26 @@ ...@@ -14,18 +18,26 @@
#include "ios/chrome/browser/passwords/password_check_observer_bridge.h" #include "ios/chrome/browser/passwords/password_check_observer_bridge.h"
#include "ios/chrome/browser/passwords/password_store_observer_bridge.h" #include "ios/chrome/browser/passwords/password_store_observer_bridge.h"
#include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/pref_names.h"
#import "ios/chrome/browser/signin/authentication_service.h"
#include "ios/chrome/browser/sync/sync_setup_service.h"
#import "ios/chrome/browser/ui/settings/cells/settings_check_item.h" #import "ios/chrome/browser/ui/settings/cells/settings_check_item.h"
#import "ios/chrome/browser/ui/settings/cells/settings_multiline_detail_item.h"
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_consumer.h" #import "ios/chrome/browser/ui/settings/safety_check/safety_check_consumer.h"
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_navigation_commands.h"
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_table_view_controller.h" #import "ios/chrome/browser/ui/settings/safety_check/safety_check_table_view_controller.h"
#import "ios/chrome/browser/ui/settings/utils/observable_boolean.h" #import "ios/chrome/browser/ui/settings/utils/observable_boolean.h"
#import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h" #import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
#import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/ui_feature_flags.h"
#import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
#import "ios/chrome/common/string_util.h"
#import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#include "ios/chrome/grit/ios_chromium_strings.h" #include "ios/chrome/grit/ios_chromium_strings.h"
#include "ios/chrome/grit/ios_strings.h" #include "ios/chrome/grit/ios_strings.h"
#import "net/base/mac/url_conversions.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support." #error "This file requires ARC support."
...@@ -132,7 +144,7 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -132,7 +144,7 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
@property(nonatomic, assign) PasswordCheckRowStates passwordCheckRowState; @property(nonatomic, assign) PasswordCheckRowStates passwordCheckRowState;
// Row button to start the safety check. // Row button to start the safety check.
@property(nonatomic, strong) SettingsMultilineDetailItem* checkStartItem; @property(nonatomic, strong) TableViewTextItem* checkStartItem;
// Current state of the start safety check row button. // Current state of the start safety check row button.
@property(nonatomic, assign) CheckStartStates checkStartState; @property(nonatomic, assign) CheckStartStates checkStartState;
...@@ -151,6 +163,12 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -151,6 +163,12 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
// How many safety check items are still running (max 3). // How many safety check items are still running (max 3).
@property(nonatomic, assign) int checkRunningRemaining; @property(nonatomic, assign) int checkRunningRemaining;
// Service used to check if user is signed in.
@property(nonatomic, assign) AuthenticationService* authService;
// Service to check if passwords are synced.
@property(nonatomic, assign) SyncSetupService* syncService;
@end @end
@implementation SafetyCheckMediator @implementation SafetyCheckMediator
...@@ -158,11 +176,18 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -158,11 +176,18 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
- (instancetype)initWithUserPrefService:(PrefService*)userPrefService - (instancetype)initWithUserPrefService:(PrefService*)userPrefService
passwordCheckManager: passwordCheckManager:
(scoped_refptr<IOSChromePasswordCheckManager>) (scoped_refptr<IOSChromePasswordCheckManager>)
passwordCheckManager { passwordCheckManager
authService:(AuthenticationService*)authService
syncService:(SyncSetupService*)syncService {
self = [super init]; self = [super init];
if (self) { if (self) {
DCHECK(userPrefService); DCHECK(userPrefService);
DCHECK(passwordCheckManager); DCHECK(passwordCheckManager);
DCHECK(authService);
DCHECK(syncService);
_authService = authService;
_syncService = syncService;
_passwordCheckManager = passwordCheckManager; _passwordCheckManager = passwordCheckManager;
_currentPasswordCheckState = _passwordCheckManager->GetPasswordCheckState(); _currentPasswordCheckState = _passwordCheckManager->GetPasswordCheckState();
...@@ -196,8 +221,9 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -196,8 +221,9 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
_checkStartState = CheckStartStateDefault; _checkStartState = CheckStartStateDefault;
_checkStartItem = _checkStartItem =
[[SettingsMultilineDetailItem alloc] initWithType:CheckStartItemType]; [[TableViewTextItem alloc] initWithType:CheckStartItemType];
_checkStartItem.text = GetNSString(IDS_IOS_CHECK_PASSWORDS_NOW_BUTTON); _checkStartItem.text = GetNSString(IDS_IOS_CHECK_PASSWORDS_NOW_BUTTON);
_checkStartItem.textColor = [UIColor colorNamed:kBlueColor];
} }
return self; return self;
} }
...@@ -261,13 +287,10 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -261,13 +287,10 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
case PasswordCheckRowStateSafe: // No tap action. case PasswordCheckRowStateSafe: // No tap action.
break; break;
case PasswordCheckRowStateUnSafe: case PasswordCheckRowStateUnSafe:
// Link to compromised password page. [self.handler showPasswordIssuesPage];
break;
case PasswordCheckRowStateDisabled:
// Popover for no passwords.
break; break;
case PasswordCheckRowStateError: case PasswordCheckRowStateDisabled: // Popover handled by cellitem.
// Various popover states case PasswordCheckRowStateError: // Popover handled by cellitem.
break; break;
} }
break; break;
...@@ -295,6 +318,23 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -295,6 +318,23 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
} }
} }
- (BOOL)isItemWithErrorInfo:(TableViewItem*)item {
ItemType type = static_cast<ItemType>(item.type);
return (type != CheckStartItemType);
}
- (void)infoButtonWasTapped:(UIButton*)buttonView
usingItemType:(NSInteger)itemType {
NSAttributedString* info = [self getPopoverInfoForType:itemType];
// If |info| is empty there is no popover to display.
if (!info)
return;
// Push popover to coordinator.
[self.handler showErrorInfoFrom:buttonView withText:info];
}
#pragma mark - BooleanObserver #pragma mark - BooleanObserver
- (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean { - (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean {
...@@ -305,6 +345,19 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -305,6 +345,19 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
#pragma mark - Private methods #pragma mark - Private methods
// Computes the text needed for a popover on |itemType| if available.
- (NSAttributedString*)getPopoverInfoForType:(NSInteger)itemType {
ItemType type = static_cast<ItemType>(itemType);
switch (type) {
case PasswordItemType:
return [self passwordCheckErrorInfo];
case SafeBrowsingItemType:
case UpdateItemType:
case CheckStartItemType:
return nil;
}
}
// Computes the appropriate display state of the password check row based on // Computes the appropriate display state of the password check row based on
// currentPasswordCheckState. // currentPasswordCheckState.
- (PasswordCheckRowStates)computePasswordCheckRowState: - (PasswordCheckRowStates)computePasswordCheckRowState:
...@@ -317,7 +370,7 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -317,7 +370,7 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
case PasswordCheckState::kRunning: case PasswordCheckState::kRunning:
return PasswordCheckRowStateRunning; return PasswordCheckRowStateRunning;
case PasswordCheckState::kNoPasswords: case PasswordCheckState::kNoPasswords:
return PasswordCheckRowStateDisabled; return PasswordCheckRowStateDefault;
case PasswordCheckState::kSignedOut: case PasswordCheckState::kSignedOut:
case PasswordCheckState::kOffline: case PasswordCheckState::kOffline:
case PasswordCheckState::kQuotaLimit: case PasswordCheckState::kQuotaLimit:
...@@ -340,6 +393,84 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -340,6 +393,84 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
} }
} }
// Computes the appropriate error info to be displayed in the passwords popover.
- (NSAttributedString*)passwordCheckErrorInfo {
if (!self.passwordCheckManager->GetCompromisedCredentials().empty())
return nil;
NSString* message;
GURL linkURL;
switch (self.currentPasswordCheckState) {
case PasswordCheckState::kRunning:
case PasswordCheckState::kNoPasswords:
message =
l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECK_ERROR_NO_PASSWORDS);
break;
case PasswordCheckState::kCanceled:
case PasswordCheckState::kIdle:
return nil;
case PasswordCheckState::kSignedOut:
message = l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECK_ERROR_SIGNED_OUT);
break;
case PasswordCheckState::kOffline:
message = l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECK_ERROR_OFFLINE);
break;
case PasswordCheckState::kQuotaLimit:
if ([self canUseAccountPasswordCheckup]) {
message = l10n_util::GetNSString(
IDS_IOS_PASSWORD_CHECK_ERROR_QUOTA_LIMIT_VISIT_GOOGLE);
linkURL = password_manager::GetPasswordCheckupURL(
password_manager::PasswordCheckupReferrer::kPasswordCheck);
} else {
message =
l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECK_ERROR_QUOTA_LIMIT);
}
break;
case PasswordCheckState::kOther:
message = l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECK_ERROR_OTHER);
break;
}
return [self attributedStringWithText:message link:linkURL];
}
// Computes whether user is capable to run password check in Google Account.
- (BOOL)canUseAccountPasswordCheckup {
return (self.authService->IsAuthenticated() &&
self.authService->GetAuthenticatedIdentity()) &&
(self.syncService->IsSyncEnabled() &&
!self.syncService->IsEncryptEverythingEnabled());
}
// Configures check passwords error info with a link.
- (NSAttributedString*)attributedStringWithText:(NSString*)text
link:(GURL)link {
NSRange range;
NSString* strippedText = ParseStringWithLink(text, &range);
NSRange fullRange = NSMakeRange(0, strippedText.length);
NSMutableAttributedString* attributedText =
[[NSMutableAttributedString alloc] initWithString:strippedText];
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor colorNamed:kTextSecondaryColor]
range:fullRange];
[attributedText
addAttribute:NSFontAttributeName
value:[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]
range:fullRange];
if (range.location != NSNotFound && range.length != 0) {
NSURL* URL = net::NSURLWithGURL(link);
id linkValue = URL ? URL : @"";
[attributedText addAttribute:NSLinkAttributeName
value:linkValue
range:range];
}
return attributedText;
}
// Upon a tap of checkStartItem either starts or cancels a safety check. // Upon a tap of checkStartItem either starts or cancels a safety check.
- (void)checkStartOrCancel { - (void)checkStartOrCancel {
// If a check is already running cancel it. // If a check is already running cancel it.
...@@ -355,6 +486,9 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -355,6 +486,9 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
// Set remaining check running counter to 0. // Set remaining check running counter to 0.
self.checkRunningRemaining = 0; self.checkRunningRemaining = 0;
// Stop any running checks.
self.passwordCheckManager->StopPasswordCheck();
} else { } else {
// Otherwise start a check. // Otherwise start a check.
...@@ -375,6 +509,27 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -375,6 +509,27 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
[self reconfigurePasswordCheckItem]; [self reconfigurePasswordCheckItem];
[self reconfigureSafeBrowsingCheckItem]; [self reconfigureSafeBrowsingCheckItem];
[self reconfigureCheckStartSection]; [self reconfigureCheckStartSection];
// The display should be changed to loading icons before any checks are
// started.
if (self.checkRunningRemaining > 0) {
// This handles a discrepancy between password check and safety check. In
// password check a user cannot start a check if they have no passwords, but
// in safety check they can, but the |passwordCheckManager| won't even start
// a check. This if block below allows safety check to push the disabled
// state after check now is pressed.
if (self.currentPasswordCheckState == PasswordCheckState::kNoPasswords) {
self.passwordCheckRowState = PasswordCheckRowStateDisabled;
// Want to show the loading wheel momentarily.
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
[self reconfigurePasswordCheckItem];
});
} else {
self.passwordCheckManager->StartPasswordCheck();
}
}
} }
// Reconfigures the display of the |updateCheckItem| based on current state of // Reconfigures the display of the |updateCheckItem| based on current state of
...@@ -386,12 +541,11 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -386,12 +541,11 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
self.updateCheckItem.infoButtonHidden = YES; self.updateCheckItem.infoButtonHidden = YES;
self.updateCheckItem.detailText = nil; self.updateCheckItem.detailText = nil;
self.updateCheckItem.trailingImage = nil; self.updateCheckItem.trailingImage = nil;
self.updateCheckItem.trailingImageTintColor = nil;
switch (self.updateCheckRowState) { switch (self.updateCheckRowState) {
case UpdateCheckRowStateDefault: { case UpdateCheckRowStateDefault:
self.updateCheckItem.enabled = NO;
break; break;
}
case UpdateCheckRowStateRunning: { case UpdateCheckRowStateRunning: {
self.updateCheckItem.indicatorHidden = NO; self.updateCheckItem.indicatorHidden = NO;
break; break;
...@@ -414,21 +568,49 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -414,21 +568,49 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
self.passwordCheckItem.infoButtonHidden = YES; self.passwordCheckItem.infoButtonHidden = YES;
self.passwordCheckItem.detailText = nil; self.passwordCheckItem.detailText = nil;
self.passwordCheckItem.trailingImage = nil; self.passwordCheckItem.trailingImage = nil;
self.passwordCheckItem.trailingImageTintColor = nil;
self.passwordCheckItem.accessoryType = UITableViewCellAccessoryNone;
switch (self.passwordCheckRowState) { switch (self.passwordCheckRowState) {
case PasswordCheckRowStateDefault: { case PasswordCheckRowStateDefault:
self.passwordCheckItem.enabled = NO;
break; break;
}
case PasswordCheckRowStateRunning: { case PasswordCheckRowStateRunning: {
self.passwordCheckItem.indicatorHidden = NO; self.passwordCheckItem.indicatorHidden = NO;
break; break;
} }
case PasswordCheckRowStateSafe: case PasswordCheckRowStateSafe: {
case PasswordCheckRowStateUnSafe: DCHECK(self.passwordCheckManager->GetCompromisedCredentials().empty());
UIImage* safeIconImage = [[UIImage imageNamed:@"settings_safe_state"]
imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.passwordCheckItem.detailText =
base::SysUTF16ToNSString(l10n_util::GetPluralStringFUTF16(
IDS_IOS_CHECK_PASSWORDS_COMPROMISED_COUNT, 0));
self.passwordCheckItem.trailingImage = safeIconImage;
self.passwordCheckItem.trailingImageTintColor =
[UIColor colorNamed:kGreenColor];
break;
}
case PasswordCheckRowStateUnSafe: {
self.passwordCheckItem.detailText =
base::SysUTF16ToNSString(l10n_util::GetPluralStringFUTF16(
IDS_IOS_CHECK_PASSWORDS_COMPROMISED_COUNT,
self.passwordCheckManager->GetCompromisedCredentials().size()));
UIImage* unSafeIconImage = [[UIImage imageNamed:@"settings_unsafe_state"]
imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.passwordCheckItem.trailingImage = unSafeIconImage;
self.passwordCheckItem.trailingImageTintColor =
[UIColor colorNamed:kRedColor];
self.passwordCheckItem.accessoryType =
UITableViewCellAccessoryDisclosureIndicator;
break;
}
case PasswordCheckRowStateDisabled: case PasswordCheckRowStateDisabled:
case PasswordCheckRowStateError: case PasswordCheckRowStateError: {
self.passwordCheckItem.detailText =
l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECK_ERROR);
self.passwordCheckItem.infoButtonHidden = NO;
break; break;
}
} }
[self.consumer reconfigureCellsForItems:@[ self.passwordCheckItem ]]; [self.consumer reconfigureCellsForItems:@[ self.passwordCheckItem ]];
...@@ -443,12 +625,11 @@ typedef NS_ENUM(NSInteger, CheckStartStates) { ...@@ -443,12 +625,11 @@ typedef NS_ENUM(NSInteger, CheckStartStates) {
self.safeBrowsingCheckItem.infoButtonHidden = YES; self.safeBrowsingCheckItem.infoButtonHidden = YES;
self.safeBrowsingCheckItem.detailText = nil; self.safeBrowsingCheckItem.detailText = nil;
self.safeBrowsingCheckItem.trailingImage = nil; self.safeBrowsingCheckItem.trailingImage = nil;
self.safeBrowsingCheckItem.trailingImageTintColor = nil;
switch (self.safeBrowsingCheckRowState) { switch (self.safeBrowsingCheckRowState) {
case SafeBrowsingCheckRowStateDefault: { case SafeBrowsingCheckRowStateDefault:
self.safeBrowsingCheckItem.enabled = NO;
break; break;
}
case SafeBrowsingCheckRowStateRunning: { case SafeBrowsingCheckRowStateRunning: {
self.safeBrowsingCheckItem.indicatorHidden = NO; self.safeBrowsingCheckItem.indicatorHidden = NO;
break; break;
......
...@@ -9,8 +9,18 @@ ...@@ -9,8 +9,18 @@
// controller. // controller.
@protocol SafetyCheckNavigationCommands @protocol SafetyCheckNavigationCommands
// TODO(crbug.com/1078782): Add navigation commands for updates, passwords, and // Shows password issues page.
// safe browsing. - (void)showPasswordIssuesPage;
// Opens Chrome page in App Store for updates.
- (void)showUpdateOnAppStorePage;
// Shows page with Safe Browsing preference toggle.
- (void)showSafeBrowsingPreferencePage;
// Shows the error popover with the corresponding |text|.
- (void)showErrorInfoFrom:(UIButton*)buttonView
withText:(NSAttributedString*)text;
@end @end
......
...@@ -15,6 +15,13 @@ ...@@ -15,6 +15,13 @@
// Called when item is tapped. // Called when item is tapped.
- (void)didSelectItem:(TableViewItem*)item; - (void)didSelectItem:(TableViewItem*)item;
// Checks if |item| should have an error popover.
- (BOOL)isItemWithErrorInfo:(TableViewItem*)item;
// Notifies the mediator that an info button was tapped for |itemType|.
- (void)infoButtonWasTapped:(UIButton*)buttonView
usingItemType:(NSInteger)itemType;
@end @end
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_SAFETY_CHECK_SAFETY_CHECK_SERVICE_DELEGATE_H_ #endif // IOS_CHROME_BROWSER_UI_SETTINGS_SAFETY_CHECK_SAFETY_CHECK_SERVICE_DELEGATE_H_
...@@ -10,13 +10,10 @@ ...@@ -10,13 +10,10 @@
@protocol SafetyCheckServiceDelegate; @protocol SafetyCheckServiceDelegate;
@class SafetyCheckTableViewController; @class SafetyCheckTableViewController;
@protocol SafetyCheckTableViewControllerModelDelegate;
// The accessibility identifier of the privacy settings collection view. // The accessibility identifier of the privacy settings collection view.
extern NSString* const kSafetyCheckTableViewId; extern NSString* const kSafetyCheckTableViewId;
@protocol SafetyCheckNavigationCommands;
// Delegate for presentation events related to // Delegate for presentation events related to
// SafetyCheckTableViewController. // SafetyCheckTableViewController.
@protocol SafetyCheckTableViewControllerPresentationDelegate @protocol SafetyCheckTableViewControllerPresentationDelegate
...@@ -40,9 +37,6 @@ extern NSString* const kSafetyCheckTableViewId; ...@@ -40,9 +37,6 @@ extern NSString* const kSafetyCheckTableViewId;
// Handler for taps on items on the safety check page. // Handler for taps on items on the safety check page.
@property(nonatomic, weak) id<SafetyCheckServiceDelegate> serviceDelegate; @property(nonatomic, weak) id<SafetyCheckServiceDelegate> serviceDelegate;
// Handler used to navigate inside the safety check.
@property(nonatomic, weak) id<SafetyCheckNavigationCommands> handler;
@end @end
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_SAFETY_CHECK_SAFETY_CHECK_TABLE_VIEW_CONTROLLER_H_ #endif // IOS_CHROME_BROWSER_UI_SETTINGS_SAFETY_CHECK_SAFETY_CHECK_TABLE_VIEW_CONTROLLER_H_
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#import "base/mac/foundation_util.h" #import "base/mac/foundation_util.h"
#include "components/strings/grit/components_strings.h" #include "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/ui/settings/cells/settings_check_cell.h"
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_navigation_commands.h"
#import "ios/chrome/browser/ui/settings/safety_check/safety_check_service_delegate.h" #import "ios/chrome/browser/ui/settings/safety_check/safety_check_service_delegate.h"
#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
#include "ios/chrome/browser/ui/ui_feature_flags.h" #include "ios/chrome/browser/ui/ui_feature_flags.h"
...@@ -97,4 +99,31 @@ typedef NS_ENUM(NSInteger, SectionIdentifier) { ...@@ -97,4 +99,31 @@ typedef NS_ENUM(NSInteger, SectionIdentifier) {
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];
} }
#pragma mark - UITableViewDataSource
- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
UITableViewCell* cell = [super tableView:tableView
cellForRowAtIndexPath:indexPath];
TableViewItem* item = [self.tableViewModel itemAtIndexPath:indexPath];
if ([self.serviceDelegate isItemWithErrorInfo:item]) {
SettingsCheckCell* settingsCheckCell =
base::mac::ObjCCastStrict<SettingsCheckCell>(cell);
settingsCheckCell.infoButton.tag = item.type;
[settingsCheckCell.infoButton addTarget:self
action:@selector(didTapErrorInfoButton:)
forControlEvents:UIControlEventTouchUpInside];
}
return cell;
}
#pragma mark - Private
// Called when user tapped on the information button of an
// item. Shows popover with detailed description of an error if needed.
- (void)didTapErrorInfoButton:(UIButton*)buttonView {
[self.serviceDelegate infoButtonWasTapped:buttonView
usingItemType:buttonView.tag];
}
@end @end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment