| // Copyright 2018 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/clear_browsing_data/clear_browsing_data_table_view_controller.h" |
| |
| #import "base/apple/foundation_util.h" |
| #import "base/metrics/histogram_functions.h" |
| #import "base/metrics/user_metrics.h" |
| #import "base/metrics/user_metrics_action.h" |
| #import "components/browsing_data/core/pref_names.h" |
| #import "components/prefs/pref_service.h" |
| #import "components/signin/public/base/signin_metrics.h" |
| #import "components/signin/public/identity_manager/objc/identity_manager_observer_bridge.h" |
| #import "ios/chrome/browser/browsing_data/browsing_data_features.h" |
| #import "ios/chrome/browser/browsing_data/browsing_data_remove_mask.h" |
| #import "ios/chrome/browser/discover_feed/discover_feed_service.h" |
| #import "ios/chrome/browser/discover_feed/discover_feed_service_factory.h" |
| #import "ios/chrome/browser/net/crurl.h" |
| #import "ios/chrome/browser/shared/coordinator/alert/action_sheet_coordinator.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/url/chrome_url_constants.h" |
| #import "ios/chrome/browser/shared/public/commands/application_commands.h" |
| #import "ios/chrome/browser/shared/public/commands/browsing_data_commands.h" |
| #import "ios/chrome/browser/shared/ui/elements/chrome_activity_overlay_coordinator.h" |
| #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_button_item.h" |
| #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_link_item.h" |
| #import "ios/chrome/browser/shared/ui/table_view/chrome_table_view_styler.h" |
| #import "ios/chrome/browser/shared/ui/table_view/table_view_utils.h" |
| #import "ios/chrome/browser/signin/identity_manager_factory.h" |
| #import "ios/chrome/browser/ui/authentication/signout_action_sheet_coordinator.h" |
| #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h" |
| #import "ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h" |
| #import "ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.h" |
| #import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_consumer.h" |
| #import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.h" |
| #import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_ui_constants.h" |
| #import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_ui_delegate.h" |
| #import "ios/chrome/browser/ui/settings/clear_browsing_data/time_range_selector_table_view_controller.h" |
| #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" |
| #import "ios/chrome/common/ui/colors/semantic_color_names.h" |
| #import "ios/chrome/common/ui/table_view/table_view_cells_constants.h" |
| #import "ios/chrome/grit/ios_chromium_strings.h" |
| #import "ios/chrome/grit/ios_strings.h" |
| #import "ui/base/l10n/l10n_util.h" |
| #import "ui/strings/grit/ui_strings.h" |
| |
| @interface ClearBrowsingDataTableViewController () < |
| ClearBrowsingDataConsumer, |
| IdentityManagerObserverBridgeDelegate, |
| SignoutActionSheetCoordinatorDelegate, |
| TableViewLinkHeaderFooterItemDelegate, |
| UIGestureRecognizerDelegate> |
| |
| // TODO(crbug.com/850699): remove direct dependency and replace with |
| // delegate. |
| @property(nonatomic, readonly, strong) ClearBrowsingDataManager* dataManager; |
| |
| // Browser state. |
| @property(nonatomic, readonly) ChromeBrowserState* browserState; |
| |
| // Browser. |
| @property(nonatomic, readonly) Browser* browser; |
| |
| // Coordinator that managers a UIAlertController to clear browsing data. |
| @property(nonatomic, strong) ActionSheetCoordinator* actionSheetCoordinator; |
| |
| // Coordinator for displaying a modal overlay with native activity indicator to |
| // prevent the user from interacting with the page. |
| @property(nonatomic, strong) |
| ChromeActivityOverlayCoordinator* overlayCoordinator; |
| |
| @property(nonatomic, readonly, strong) |
| UIBarButtonItem* clearBrowsingDataBarButton; |
| |
| // Modal alert for Browsing history removed dialog. |
| @property(nonatomic, strong) AlertCoordinator* alertCoordinator; |
| |
| // The data manager might want to reload tableView cells before the tableView |
| // has loaded, we need to prevent this kind of updates until the tableView |
| // loads. |
| @property(nonatomic, assign) BOOL suppressTableViewUpdates; |
| |
| @end |
| |
| @implementation ClearBrowsingDataTableViewController { |
| // Modal alert for sign out. |
| SignoutActionSheetCoordinator* _signoutCoordinator; |
| std::unique_ptr<signin::IdentityManagerObserverBridge> |
| _identityManagerObserverBridge; |
| } |
| @synthesize dispatcher = _dispatcher; |
| @synthesize delegate = _delegate; |
| @synthesize clearBrowsingDataBarButton = _clearBrowsingDataBarButton; |
| #pragma mark - ViewController Lifecycle. |
| |
| - (instancetype)initWithBrowser:(Browser*)browser { |
| UITableViewStyle style = ChromeTableViewStyle(); |
| self = [super initWithStyle:style]; |
| if (self) { |
| _browser = browser; |
| _browserState = browser->GetBrowserState(); |
| _dataManager = [[ClearBrowsingDataManager alloc] |
| initWithBrowserState:browser->GetBrowserState()]; |
| _dataManager.consumer = self; |
| _identityManagerObserverBridge.reset( |
| new signin::IdentityManagerObserverBridge( |
| IdentityManagerFactory::GetForBrowserState(_browserState), self)); |
| } |
| return self; |
| } |
| |
| - (void)stop { |
| [self prepareForDismissal]; |
| _identityManagerObserverBridge.reset(); |
| [_dataManager disconnect]; |
| _dataManager.consumer = nil; |
| _dataManager = nil; |
| _browser = nil; |
| _browserState = nil; |
| } |
| |
| - (void)didMoveToParentViewController:(UIViewController*)parent { |
| [super didMoveToParentViewController:parent]; |
| if (!parent) { |
| [self.delegate clearBrowsingDataTableViewControllerWasRemoved:self]; |
| } |
| } |
| |
| #pragma mark - Property |
| |
| - (UIBarButtonItem*)clearBrowsingDataBarButton { |
| if (!_clearBrowsingDataBarButton) { |
| _clearBrowsingDataBarButton = [[UIBarButtonItem alloc] |
| initWithTitle:l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON) |
| style:UIBarButtonItemStylePlain |
| target:self |
| action:@selector(showClearBrowsingDataAlertController:)]; |
| _clearBrowsingDataBarButton.accessibilityIdentifier = |
| kClearBrowsingDataButtonIdentifier; |
| _clearBrowsingDataBarButton.tintColor = [UIColor colorNamed:kRedColor]; |
| } |
| return _clearBrowsingDataBarButton; |
| } |
| |
| #pragma mark - IdentityManagerObserverBridgeDelegate |
| |
| // Update footer to take into account whether the user is signed-in or not. |
| - (void)onPrimaryAccountChanged: |
| (const signin::PrimaryAccountChangeEvent&)event { |
| [self.dataManager updateModel:self.tableViewModel |
| withTableView:self.tableView]; |
| } |
| |
| #pragma mark - UIViewController |
| |
| - (void)viewDidLoad { |
| [super viewDidLoad]; |
| |
| UIBarButtonItem* flexibleSpace = [[UIBarButtonItem alloc] |
| initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace |
| target:nil |
| action:nil]; |
| [self setToolbarItems:@[ |
| flexibleSpace, self.clearBrowsingDataBarButton, flexibleSpace |
| ] |
| animated:YES]; |
| |
| self.tableView.accessibilityIdentifier = |
| kClearBrowsingDataViewAccessibilityIdentifier; |
| |
| // Navigation controller configuration. |
| self.title = l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_TITLE); |
| // Adds the "Done" button and hooks it up to `dismiss`. |
| UIBarButtonItem* dismissButton = [[UIBarButtonItem alloc] |
| initWithBarButtonSystemItem:UIBarButtonSystemItemDone |
| target:self |
| action:@selector(dismiss)]; |
| dismissButton.accessibilityIdentifier = kSettingsDoneButtonId; |
| self.navigationItem.rightBarButtonItem = dismissButton; |
| |
| // Do not allow any TableView updates until the model is fully loaded. The |
| // model might try re-loading some cells and the TableView might not be loaded |
| // at this point (https://crbug.com/873929). |
| self.suppressTableViewUpdates = YES; |
| [self loadModel]; |
| self.suppressTableViewUpdates = NO; |
| [self.dataManager prepare]; |
| } |
| |
| - (void)viewWillAppear:(BOOL)animated { |
| [super viewWillAppear:animated]; |
| [self.dataManager restartCounters:BrowsingDataRemoveMask::REMOVE_ALL]; |
| |
| [self updateToolbarButtons]; |
| // Showing toolbar here because parent class hides toolbar in |
| // viewWillDisappear:. |
| self.navigationController.toolbarHidden = NO; |
| } |
| |
| - (void)loadModel { |
| [super loadModel]; |
| [self.dataManager loadModel:self.tableViewModel]; |
| } |
| |
| - (void)dismiss { |
| base::RecordAction(base::UserMetricsAction("MobileClearBrowsingDataClose")); |
| [self prepareForDismissal]; |
| [self.delegate clearBrowsingDataTableViewControllerWantsDismissal:self]; |
| } |
| |
| #pragma mark - Public Methods |
| |
| - (void)prepareForDismissal { |
| if (self.actionSheetCoordinator) { |
| [self.actionSheetCoordinator stop]; |
| self.actionSheetCoordinator = nil; |
| } |
| [self dismissAlertCoordinator]; |
| if (self.overlayCoordinator.started) { |
| [self.overlayCoordinator stop]; |
| self.navigationController.interactivePopGestureRecognizer.delegate = nil; |
| self.overlayCoordinator = nil; |
| } |
| _identityManagerObserverBridge.reset(); |
| [self.dataManager disconnect]; |
| } |
| |
| #pragma mark - UIGestureRecognizerDelegate |
| |
| - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { |
| if (gestureRecognizer == |
| self.navigationController.interactivePopGestureRecognizer) { |
| // This view controller should only be observing gestures when the activity |
| // overlay is showing (e.g. when Clear Browsing Data is in progress and the |
| // user should not be able to swipe away from this view). |
| return NO; |
| } |
| return YES; |
| } |
| |
| #pragma mark - UITableViewDataSource |
| |
| - (UITableViewCell*)tableView:(UITableView*)tableView |
| cellForRowAtIndexPath:(NSIndexPath*)indexPath { |
| UITableViewCell* cellToReturn = [super tableView:tableView |
| cellForRowAtIndexPath:indexPath]; |
| TableViewItem* item = [self.tableViewModel itemAtIndexPath:indexPath]; |
| switch (item.type) { |
| case ItemTypeDataTypeBrowsingHistory: |
| case ItemTypeDataTypeCookiesSiteData: |
| case ItemTypeDataTypeCache: |
| case ItemTypeDataTypeSavedPasswords: |
| case ItemTypeDataTypeAutofill: |
| // For these cells the selection style application is specified in the |
| // corresponding item definition. |
| cellToReturn.selectionStyle = UITableViewCellSelectionStyleNone; |
| break; |
| default: |
| break; |
| } |
| return cellToReturn; |
| } |
| |
| #pragma mark - UITableViewDelegate |
| |
| - (UIView*)tableView:(UITableView*)tableView |
| viewForFooterInSection:(NSInteger)section { |
| UIView* view = [super tableView:tableView viewForFooterInSection:section]; |
| NSInteger sectionIdentifier = |
| [self.tableViewModel sectionIdentifierForSectionIndex:section]; |
| switch (sectionIdentifier) { |
| case SectionIdentifierSavedSiteData: |
| case SectionIdentifierGoogleAccount: { |
| TableViewLinkHeaderFooterView* linkView = |
| base::apple::ObjCCastStrict<TableViewLinkHeaderFooterView>(view); |
| linkView.delegate = self; |
| } break; |
| default: |
| break; |
| } |
| return view; |
| } |
| |
| - (CGFloat)tableView:(UITableView*)tableView |
| heightForHeaderInSection:(NSInteger)section { |
| NSInteger sectionIdentifier = |
| [self.tableViewModel sectionIdentifierForSectionIndex:section]; |
| switch (sectionIdentifier) { |
| case SectionIdentifierGoogleAccount: |
| case SectionIdentifierSavedSiteData: |
| return 5; |
| default: |
| return [super tableView:tableView heightForHeaderInSection:section]; |
| } |
| } |
| |
| - (void)tableView:(UITableView*)tableView |
| didSelectRowAtIndexPath:(NSIndexPath*)indexPath { |
| TableViewItem* item = [self.tableViewModel itemAtIndexPath:indexPath]; |
| DCHECK(item); |
| switch (item.type) { |
| case ItemTypeTimeRange: { |
| UIViewController* controller = |
| [[TimeRangeSelectorTableViewController alloc] |
| initWithPrefs:self.browserState->GetPrefs()]; |
| [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; |
| [self.navigationController pushViewController:controller animated:YES]; |
| break; |
| } |
| case ItemTypeDataTypeBrowsingHistory: |
| case ItemTypeDataTypeCookiesSiteData: |
| case ItemTypeDataTypeCache: |
| case ItemTypeDataTypeSavedPasswords: |
| case ItemTypeDataTypeAutofill: { |
| DCHECK([item isKindOfClass:[TableViewClearBrowsingDataItem class]]); |
| TableViewClearBrowsingDataItem* clearBrowsingDataItem = |
| base::apple::ObjCCastStrict<TableViewClearBrowsingDataItem>(item); |
| |
| self.browserState->GetPrefs()->SetBoolean(clearBrowsingDataItem.prefName, |
| !clearBrowsingDataItem.checked); |
| // UI update will be trigerred by data manager. |
| break; |
| } |
| default: |
| break; |
| } |
| [self updateToolbarButtons]; |
| } |
| |
| #pragma mark - UIResponder |
| |
| // To always be able to register key commands via -keyCommands, the VC must be |
| // able to become first responder. |
| - (BOOL)canBecomeFirstResponder { |
| return YES; |
| } |
| |
| - (NSArray*)keyCommands { |
| return @[ UIKeyCommand.cr_close ]; |
| } |
| |
| - (void)keyCommand_close { |
| base::RecordAction(base::UserMetricsAction("MobileKeyCommandClose")); |
| [self dismiss]; |
| } |
| |
| #pragma mark - TableViewLinkHeaderFooterItemDelegate |
| |
| - (void)view:(TableViewLinkHeaderFooterView*)view didTapLinkURL:(CrURL*)url { |
| if (url.gurl == GURL(kCBDSignOutOfChromeURL)) { |
| [self showSignOutWithItemView:[view contentView]]; |
| return; |
| } |
| NSString* baseURL = |
| [NSString stringWithCString:(url.gurl.host() + url.gurl.path()).c_str() |
| encoding:[NSString defaultCStringEncoding]]; |
| if ([[NSString stringWithCString:(kClearBrowsingDataDSESearchUrlInFooterURL) |
| encoding:[NSString defaultCStringEncoding]] |
| rangeOfString:baseURL] |
| .length > 0) { |
| base::UmaHistogramEnumeration("Settings.ClearBrowsingData.OpenMyActivity", |
| MyActivityNavigation::kSearchHistory); |
| } else if ([[NSString stringWithCString: |
| (kClearBrowsingDataDSEMyActivityUrlInFooterURL) |
| encoding:[NSString defaultCStringEncoding]] |
| rangeOfString:baseURL] |
| .length > 0) { |
| base::UmaHistogramEnumeration("Settings.ClearBrowsingData.OpenMyActivity", |
| MyActivityNavigation::kTopLevel); |
| } |
| [self.delegate clearBrowsingDataTableViewController:self |
| wantsToOpenURL:url.gurl]; |
| } |
| |
| #pragma mark - ClearBrowsingDataConsumer |
| |
| - (void)dismissAlertCoordinator { |
| [self.alertCoordinator stop]; |
| self.alertCoordinator = nil; |
| } |
| |
| - (void)updateCellsForItem:(TableViewItem*)item reload:(BOOL)reload { |
| if (self.suppressTableViewUpdates) |
| return; |
| |
| if (!reload) { |
| [self reconfigureCellsForItems:@[ item ]]; |
| NSIndexPath* indexPath = [self.tableViewModel |
| indexPathForItem:static_cast<TableViewItem*>(item)]; |
| [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; |
| } else { |
| // Reload the item instead of reconfiguring it. This might update |
| // TableViewLinkHeaderFooterView which which can have different number of |
| // lines, thus the cell height needs to adapt accordingly. |
| [self reloadCellsForItems:@[ item ] |
| withRowAnimation:UITableViewRowAnimationAutomatic]; |
| } |
| } |
| |
| - (void)removeBrowsingDataForBrowserState:(ChromeBrowserState*)browserState |
| timePeriod:(browsing_data::TimePeriod)timePeriod |
| removeMask:(BrowsingDataRemoveMask)removeMask |
| completionBlock:(ProceduralBlock)completionBlock { |
| base::RecordAction( |
| base::UserMetricsAction("MobileClearBrowsingDataTriggeredFromUIRefresh")); |
| |
| // Show activity indicator modal while removal is happening. |
| self.overlayCoordinator = [[ChromeActivityOverlayCoordinator alloc] |
| initWithBaseViewController:self.navigationController |
| browser:_browser]; |
| |
| self.overlayCoordinator.messageText = l10n_util::GetNSStringWithFixup( |
| IDS_IOS_CLEAR_BROWSING_DATA_ACTIVITY_MODAL); |
| |
| self.overlayCoordinator.blockAllWindows = YES; |
| |
| // Observe Gestures while overlay is visible to prevent user from swiping away |
| // from this view during the process of clear browsing data. |
| self.navigationController.interactivePopGestureRecognizer.delegate = self; |
| [self.overlayCoordinator start]; |
| |
| __weak ClearBrowsingDataTableViewController* weakSelf = self; |
| dispatch_time_t timeOneSecondLater = |
| dispatch_time(DISPATCH_TIME_NOW, (1 * NSEC_PER_SEC)); |
| void (^removeBrowsingDidFinishCompletionBlock)(void) = ^void() { |
| ClearBrowsingDataTableViewController* strongSelf = weakSelf; |
| if (!strongSelf) { |
| return; |
| } |
| // Sometimes clear browsing data is really short |
| // (<1sec), so ensure that overlay displays for at |
| // least 1 second instead of looking like a glitch. |
| dispatch_after(timeOneSecondLater, dispatch_get_main_queue(), ^{ |
| [self.overlayCoordinator stop]; |
| self.navigationController.interactivePopGestureRecognizer.delegate = nil; |
| |
| // Inform Voiceover users that their browsing data has |
| // been cleared. Otherwise, users only hear that the clear browsing data |
| // process was initiated, but not completed. |
| UIAccessibilityPostNotification( |
| UIAccessibilityAnnouncementNotification, |
| l10n_util::GetNSString( |
| IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_TITLE)); |
| |
| if (completionBlock) |
| completionBlock(); |
| }); |
| }; |
| |
| // If browsing History will be cleared set the kLastClearBrowsingDataTime. |
| // TODO(crbug.com/1085419): This pref is used by the Feed to prevent the |
| // showing of customized content after history has been cleared. We might want |
| // to create a specific Pref for this. |
| if (IsRemoveDataMaskSet(removeMask, BrowsingDataRemoveMask::REMOVE_HISTORY)) { |
| browserState->GetPrefs()->SetInt64( |
| browsing_data::prefs::kLastClearBrowsingDataTime, |
| base::Time::Now().ToTimeT()); |
| |
| DiscoverFeedServiceFactory::GetForBrowserState(browserState) |
| ->BrowsingHistoryCleared(); |
| } |
| |
| [self.dispatcher |
| removeBrowsingDataForBrowserState:browserState |
| timePeriod:timePeriod |
| removeMask:removeMask |
| completionBlock:removeBrowsingDidFinishCompletionBlock]; |
| } |
| |
| - (void)showBrowsingHistoryRemovedDialog { |
| NSString* title = |
| l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_TITLE); |
| NSString* message = l10n_util::GetNSString( |
| IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_DESCRIPTION); |
| |
| self.alertCoordinator = |
| [[AlertCoordinator alloc] initWithBaseViewController:self |
| browser:_browser |
| title:title |
| message:message]; |
| |
| __weak ClearBrowsingDataTableViewController* weakSelf = self; |
| [self.alertCoordinator |
| addItemWithTitle: |
| l10n_util::GetNSString( |
| IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_OPEN_HISTORY_BUTTON) |
| action:^{ |
| [weakSelf.delegate |
| clearBrowsingDataTableViewController:weakSelf |
| wantsToOpenURL: |
| GURL(kGoogleMyAccountURL)]; |
| [weakSelf dismissAlertCoordinator]; |
| } |
| style:UIAlertActionStyleDefault]; |
| |
| [self.alertCoordinator |
| addItemWithTitle:l10n_util::GetNSString( |
| IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_OK_BUTTON) |
| action:^{ |
| [weakSelf dismissAlertCoordinator]; |
| } |
| style:UIAlertActionStyleCancel]; |
| |
| [self.alertCoordinator start]; |
| } |
| |
| #pragma mark - UIAdaptivePresentationControllerDelegate |
| |
| - (void)presentationControllerDidDismiss: |
| (UIPresentationController*)presentationController { |
| base::RecordAction( |
| base::UserMetricsAction("IOSClearBrowsingDataCloseWithSwipe")); |
| // Call prepareForDismissal to clean up state and stop the Coordinators the |
| // current class own. |
| [self prepareForDismissal]; |
| [self.delegate clearBrowsingDataTableViewControllerWasRemoved:self]; |
| } |
| |
| - (BOOL)presentationControllerShouldDismiss: |
| (UIPresentationController*)presentationController { |
| return !self.overlayCoordinator.started; |
| } |
| |
| #pragma mark - SignoutActionSheetCoordinatorDelegate |
| |
| - (void)signoutActionSheetCoordinatorPreventUserInteraction: |
| (SignoutActionSheetCoordinator*)coordinator { |
| [self preventUserInteraction]; |
| } |
| |
| - (void)signoutActionSheetCoordinatorAllowUserInteraction: |
| (SignoutActionSheetCoordinator*)coordinator { |
| [self allowUserInteraction]; |
| } |
| |
| #pragma mark - Private Helpers |
| |
| - (void)showClearBrowsingDataAlertController:(id)sender { |
| BrowsingDataRemoveMask dataTypeMaskToRemove = |
| BrowsingDataRemoveMask::REMOVE_NOTHING; |
| NSArray* dataTypeItems = [self.tableViewModel |
| itemsInSectionWithIdentifier:SectionIdentifierDataTypes]; |
| for (TableViewClearBrowsingDataItem* dataTypeItem in dataTypeItems) { |
| DCHECK([dataTypeItem isKindOfClass:[TableViewClearBrowsingDataItem class]]); |
| if (dataTypeItem.checked) { |
| dataTypeMaskToRemove = dataTypeMaskToRemove | dataTypeItem.dataTypeMask; |
| } |
| } |
| self.actionSheetCoordinator = [self.dataManager |
| actionSheetCoordinatorWithDataTypesToRemove:dataTypeMaskToRemove |
| baseViewController:self |
| browser:_browser |
| sourceBarButtonItem:sender]; |
| __weak ClearBrowsingDataTableViewController* weakSelf = self; |
| [self.actionSheetCoordinator |
| addItemWithTitle:l10n_util::GetNSString(IDS_APP_CANCEL) |
| action:^{ |
| [weakSelf dismissAlertCoordinator]; |
| } |
| style:UIAlertActionStyleCancel]; |
| [self.actionSheetCoordinator start]; |
| } |
| |
| - (void)updateToolbarButtons { |
| self.clearBrowsingDataBarButton.enabled = [self hasDataTypeItemsSelected]; |
| } |
| |
| - (BOOL)hasDataTypeItemsSelected { |
| // Returns YES iff at least 1 data type cell is selected. |
| NSArray* dataTypeItems = [self.tableViewModel |
| itemsInSectionWithIdentifier:SectionIdentifierDataTypes]; |
| for (TableViewClearBrowsingDataItem* dataTypeItem in dataTypeItems) { |
| DCHECK([dataTypeItem isKindOfClass:[TableViewClearBrowsingDataItem class]]); |
| if (dataTypeItem.checked) { |
| return YES; |
| } |
| } |
| return NO; |
| } |
| |
| // Offer the user to sign-out near itemView |
| // If they sync, they can keep or delete their data. |
| // TODO(crbug.com/1385791) Test that correct histogram is registered. |
| - (void)showSignOutWithItemView:(UIView*)itemView { |
| if (_signoutCoordinator) { |
| // An action is already in progress, ignore user's request. |
| return; |
| } |
| signin_metrics::ProfileSignout signout_source_metric = signin_metrics:: |
| ProfileSignout::kUserClickedSignoutFromClearBrowsingDataPage; |
| _signoutCoordinator = [[SignoutActionSheetCoordinator alloc] |
| initWithBaseViewController:self |
| browser:_browser |
| rect:itemView.frame |
| view:itemView |
| withSource:signout_source_metric]; |
| _signoutCoordinator.showUnavailableFeatureDialogHeader = YES; |
| __weak ClearBrowsingDataTableViewController* weakSelf = self; |
| _signoutCoordinator.completion = ^(BOOL success) { |
| [weakSelf handleAuthenticationOperationDidFinish]; |
| }; |
| _signoutCoordinator.delegate = self; |
| [_signoutCoordinator start]; |
| } |
| |
| // Stops the signout coordinator. |
| - (void)handleAuthenticationOperationDidFinish { |
| DCHECK(_signoutCoordinator); |
| [_signoutCoordinator stop]; |
| _signoutCoordinator = nil; |
| } |
| |
| @end |