Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Unified Diff: ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.mm

Issue 2589583003: Upstream Chrome on iOS source code [7/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.mm
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..d595c8e32aaeea26a038b7870445657f875e4ed7
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.mm
@@ -0,0 +1,900 @@
+// Copyright 2015 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/settings/clear_browsing_data_collection_view_controller.h"
+
+#include <memory>
+#include <string>
+
+#include "base/ios/ios_util.h"
+#include "base/ios/weak_nsobject.h"
+#include "base/logging.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/sys_string_conversions.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/browsing_data/core/browsing_data_utils.h"
+#include "components/browsing_data/core/counters/browsing_data_counter.h"
+#include "components/browsing_data/core/history_notice_utils.h"
+#include "components/browsing_data/core/pref_names.h"
+#include "components/google/core/browser/google_util.h"
+#include "components/history/core/browser/web_history_service.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/application_context.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.h"
+#include "ios/chrome/browser/browsing_data/ios_browsing_data_counter_factory.h"
+#include "ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.h"
+#include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/history/web_history_service_factory.h"
+#include "ios/chrome/browser/signin/signin_manager_factory.h"
+#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
+#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
+#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
+#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
+#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/clear_browsing_data_command.h"
+#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
+#import "ios/chrome/browser/ui/commands/open_url_command.h"
+#import "ios/chrome/browser/ui/icons/chrome_icon.h"
+#import "ios/chrome/browser/ui/settings/time_range_selector_collection_view_controller.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/common/channel_info.h"
+#include "ios/chrome/grit/ios_chromium_strings.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#include "ios/public/provider/chrome/browser/images/branded_image_provider.h"
+#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+#include "url/gurl.h"
+
+NSString* const kClearBrowsingDataCollectionViewId =
+ @"kClearBrowsingDataCollectionViewId";
+NSString* const kClearBrowsingHistoryCellId = @"kClearBrowsingHistoryCellId";
+NSString* const kClearCookiesCellId = @"kClearCookiesCellId";
+NSString* const kClearCacheCellId = @"kClearCacheCellId";
+NSString* const kClearSavedPasswordsCellId = @"kClearSavedPasswordsCellId";
+NSString* const kClearAutofillCellId = @"kClearAutofillCellId";
+
+namespace {
+
+typedef NS_ENUM(NSInteger, SectionIdentifier) {
+ SectionIdentifierDataTypes = kSectionIdentifierEnumZero,
+ SectionIdentifierClearBrowsingDataButton,
+ SectionIdentifierGoogleAccount,
+ SectionIdentifierClearSyncAndSavedSiteData,
+ SectionIdentifierSavedSiteData,
+ SectionIdentifierTimeRange,
+};
+
+typedef NS_ENUM(NSInteger, ItemType) {
+ ItemTypeDataTypeBrowsingHistory = kItemTypeEnumZero,
+ ItemTypeDataTypeCookiesSiteData,
+ ItemTypeDataTypeCache,
+ ItemTypeDataTypeSavedPasswords,
+ ItemTypeDataTypeAutofill,
+ ItemTypeClearBrowsingDataButton,
+ ItemTypeFooterGoogleAccount,
+ ItemTypeFooterGoogleAccountAndMyActivity,
+ ItemTypeFooterSavedSiteData,
+ ItemTypeFooterClearSyncAndSavedSiteData,
+ ItemTypeTimeRange,
+};
+
+const int kMaxTimesHistoryNoticeShown = 1;
+
+} // namespace
+
+// Collection view item identifying a clear browsing data content view.
+@interface ClearDataItem : CollectionViewTextItem {
+ // Data volume counter associated with the item.
+ std::unique_ptr<BrowsingDataCounterWrapper> _counter;
+}
+
+// Mask of the data to be cleared.
+@property(nonatomic, assign) int dataTypeMask;
+
+// Pref name associated with the item.
+@property(nonatomic, assign) const char* prefName;
+
+// Sets the counter associated with the data type represented by the item.
+- (void)setCounter:(std::unique_ptr<BrowsingDataCounterWrapper>)counter;
+
+// Checks if the item has a counter.
+- (BOOL)hasCounter;
+
+// Restarts the counter.
+- (void)restartCounter;
+
+@end
+
+@implementation ClearDataItem
+
+@synthesize dataTypeMask = _dataTypeMask;
+@synthesize prefName = _prefName;
+
+- (void)setCounter:(std::unique_ptr<BrowsingDataCounterWrapper>)counter {
+ _counter = std::move(counter);
+}
+
+- (BOOL)hasCounter {
+ return !!_counter;
+}
+
+- (void)restartCounter {
+ if (_counter)
+ _counter->RestartCounter();
+}
+
+@end
+
+@interface ClearBrowsingDataCollectionViewController ()<
+ TimeRangeSelectorCollectionViewControllerDelegate> {
+ ios::ChromeBrowserState* _browserState; // weak
+
+ browsing_data::TimePeriod _timePeriod;
+
+ IOSChromeBrowsingDataRemover::CallbackSubscription _callbackSubscription;
+}
+
+@property(nonatomic, assign)
+ BOOL shouldShowNoticeAboutOtherFormsOfBrowsingHistory;
+@property(nonatomic, assign)
+ BOOL shouldPopupDialogAboutOtherFormsOfBrowsingHistory;
+
+// Displays an action sheet to the user confirming the clearing of user data. If
+// the clearing is confirmed, clears the data.
+// Always returns YES to ensure that the collection view cell is deselected.
+- (BOOL)alertAndClearData;
+
+// Clears the data stored for |dataTypeMask|.
+- (void)clearDataForDataTypes:(int)dataTypeMask;
+
+// Returns the accessibility identifier for the cell corresponding to
+// |itemType|.
+- (NSString*)getAccessibilityIdentifierFromItemType:(NSInteger)itemType;
+
+// Restarts the counters for data types specified in the mask.
+- (void)restartCounters:(int)data_mask;
+
+@end
+
+@implementation ClearBrowsingDataCollectionViewController
+
+@synthesize shouldShowNoticeAboutOtherFormsOfBrowsingHistory =
+ _shouldShowNoticeAboutOtherFormsOfBrowsingHistory;
+@synthesize shouldPopupDialogAboutOtherFormsOfBrowsingHistory =
+ _shouldPopupDialogAboutOtherFormsOfBrowsingHistory;
+
+#pragma mark Initialization
+
+- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
+ DCHECK(browserState);
+ self = [super initWithStyle:CollectionViewControllerStyleAppBar];
+ if (self) {
+ self.accessibilityTraits |= UIAccessibilityTraitButton;
+
+ _browserState = browserState;
+ if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+ int prefValue = browserState->GetPrefs()->GetInteger(
+ browsing_data::prefs::kDeleteTimePeriod);
+ prefValue = MAX(0, prefValue);
+ if (prefValue > browsing_data::TIME_PERIOD_LAST) {
+ prefValue = browsing_data::TIME_PERIOD_LAST;
+ }
+ _timePeriod = static_cast<browsing_data::TimePeriod>(prefValue);
+ } else {
+ _timePeriod = browsing_data::ALL_TIME;
+ }
+
+ self.title = l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_TITLE);
+ self.collectionViewAccessibilityIdentifier =
+ kClearBrowsingDataCollectionViewId;
+
+ if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+ base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(
+ self);
+ void (^dataClearedCallback)(
+ const IOSChromeBrowsingDataRemover::NotificationDetails&) =
+ ^(const IOSChromeBrowsingDataRemover::NotificationDetails& details) {
+ base::scoped_nsobject<ClearBrowsingDataCollectionViewController>
+ strongSelf([weakSelf retain]);
+ [strongSelf restartCounters:details.removal_mask];
+ };
+ _callbackSubscription =
+ IOSChromeBrowsingDataRemover::RegisterOnBrowsingDataRemovedCallback(
+ base::BindBlock(dataClearedCallback));
+ }
+
+ [self loadModel];
+ [self restartCounters:IOSChromeBrowsingDataRemover::REMOVE_ALL];
+ }
+ return self;
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ SigninManager* signinManager =
+ ios::SigninManagerFactory::GetForBrowserState(_browserState);
+ if (!signinManager->IsAuthenticated()) {
+ return;
+ }
+
+ browser_sync::ProfileSyncService* syncService =
+ IOSChromeProfileSyncServiceFactory::GetForBrowserState(_browserState);
+ history::WebHistoryService* historyService =
+ ios::WebHistoryServiceFactory::GetForBrowserState(_browserState);
+
+ base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(self);
+ browsing_data::ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
+ syncService, historyService, base::BindBlock(^(bool shouldShowNotice) {
+ base::scoped_nsobject<ClearBrowsingDataCollectionViewController>
+ strongSelf([weakSelf retain]);
+ [strongSelf setShouldShowNoticeAboutOtherFormsOfBrowsingHistory:
+ shouldShowNotice];
+ }));
+
+ browsing_data::ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
+ syncService, historyService, GetChannel(),
+ base::BindBlock(^(bool shouldShowPopup) {
+ base::scoped_nsobject<ClearBrowsingDataCollectionViewController>
+ strongSelf([weakSelf retain]);
+ [strongSelf setShouldPopupDialogAboutOtherFormsOfBrowsingHistory:
+ shouldShowPopup];
+ }));
+}
+
+#pragma mark CollectionViewController
+
+- (void)loadModel {
+ [super loadModel];
+ CollectionViewModel* model = self.collectionViewModel;
+
+ // Time range section.
+ if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+ [model addSectionWithIdentifier:SectionIdentifierTimeRange];
+ [model addItem:[self timeRangeItem]
+ toSectionWithIdentifier:SectionIdentifierTimeRange];
+ }
+
+ // Data types section.
+ [model addSectionWithIdentifier:SectionIdentifierDataTypes];
+ int clearBrowsingHistoryMask =
+ IOSChromeBrowsingDataRemover::REMOVE_HISTORY |
+ IOSChromeBrowsingDataRemover::REMOVE_GOOGLE_APP_LAUNCHER_DATA;
+ CollectionViewItem* browsingHistoryItem =
+ [self clearDataItemWithType:ItemTypeDataTypeBrowsingHistory
+ titleID:IDS_IOS_CLEAR_BROWSING_HISTORY
+ mask:clearBrowsingHistoryMask
+ prefName:browsing_data::prefs::kDeleteBrowsingHistory];
+ [model addItem:browsingHistoryItem
+ toSectionWithIdentifier:SectionIdentifierDataTypes];
+
+ // This data type doesn't currently have an associated counter, but displays
+ // an explanatory text instead, when the new UI is enabled.
+ ClearDataItem* cookiesSiteDataItem =
+ [self clearDataItemWithType:ItemTypeDataTypeCookiesSiteData
+ titleID:IDS_IOS_CLEAR_COOKIES
+ mask:IOSChromeBrowsingDataRemover::REMOVE_SITE_DATA
+ prefName:browsing_data::prefs::kDeleteCookies];
+ if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+ if (_browserState->GetPrefs()->GetBoolean(
+ browsing_data::prefs::kDeleteCookies)) {
+ cookiesSiteDataItem.detailText =
+ l10n_util::GetNSString(IDS_DEL_COOKIES_COUNTER);
+ }
+ }
+ [model addItem:cookiesSiteDataItem
+ toSectionWithIdentifier:SectionIdentifierDataTypes];
+
+ ClearDataItem* cacheItem =
+ [self clearDataItemWithType:ItemTypeDataTypeCache
+ titleID:IDS_IOS_CLEAR_CACHE
+ mask:IOSChromeBrowsingDataRemover::REMOVE_CACHE
+ prefName:browsing_data::prefs::kDeleteCache];
+ [model addItem:cacheItem toSectionWithIdentifier:SectionIdentifierDataTypes];
+
+ ClearDataItem* savedPasswordsItem =
+ [self clearDataItemWithType:ItemTypeDataTypeSavedPasswords
+ titleID:IDS_IOS_CLEAR_SAVED_PASSWORDS
+ mask:IOSChromeBrowsingDataRemover::REMOVE_PASSWORDS
+ prefName:browsing_data::prefs::kDeletePasswords];
+ [model addItem:savedPasswordsItem
+ toSectionWithIdentifier:SectionIdentifierDataTypes];
+
+ ClearDataItem* autofillItem =
+ [self clearDataItemWithType:ItemTypeDataTypeAutofill
+ titleID:IDS_IOS_CLEAR_AUTOFILL
+ mask:IOSChromeBrowsingDataRemover::REMOVE_FORM_DATA
+ prefName:browsing_data::prefs::kDeleteFormData];
+ [model addItem:autofillItem
+ toSectionWithIdentifier:SectionIdentifierDataTypes];
+
+ // Clear Browsing Data button.
+ [model addSectionWithIdentifier:SectionIdentifierClearBrowsingDataButton];
+ CollectionViewTextItem* clearButtonItem = [[[CollectionViewTextItem alloc]
+ initWithType:ItemTypeClearBrowsingDataButton] autorelease];
+ clearButtonItem.text = l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON);
+ clearButtonItem.accessibilityTraits |= UIAccessibilityTraitButton;
+ [model addItem:clearButtonItem
+ toSectionWithIdentifier:SectionIdentifierClearBrowsingDataButton];
+
+ // Google Account footer.
+ SigninManager* signinManager =
+ ios::SigninManagerFactory::GetForBrowserState(_browserState);
+ if (signinManager->IsAuthenticated()) {
+ // TODO(crbug.com/650424): Footer items must currently go into a separate
+ // section, to work around a drawing bug in MDC.
+ [model addSectionWithIdentifier:SectionIdentifierGoogleAccount];
+ [model addItem:[self footerForGoogleAccountSectionItem]
+ toSectionWithIdentifier:SectionIdentifierGoogleAccount];
+ }
+
+ browser_sync::ProfileSyncService* syncService =
+ IOSChromeProfileSyncServiceFactory::GetForBrowserState(_browserState);
+ if (syncService && syncService->IsSyncActive()) {
+ // TODO(crbug.com/650424): Footer items must currently go into a separate
+ // section, to work around a drawing bug in MDC.
+ [model addSectionWithIdentifier:SectionIdentifierClearSyncAndSavedSiteData];
+ [model addItem:[self footerClearSyncAndSavedSiteDataItem]
+ toSectionWithIdentifier:SectionIdentifierClearSyncAndSavedSiteData];
+ } else {
+ // TODO(crbug.com/650424): Footer items must currently go into a separate
+ // section, to work around a drawing bug in MDC.
+ [model addSectionWithIdentifier:SectionIdentifierSavedSiteData];
+ [model addItem:[self footerSavedSiteDataItem]
+ toSectionWithIdentifier:SectionIdentifierSavedSiteData];
+ }
+}
+
+#pragma mark Items
+
+- (ClearDataItem*)clearDataItemWithType:(ItemType)itemType
+ titleID:(int)titleMessageID
+ mask:(int)mask
+ prefName:(const char*)prefName {
+ PrefService* prefs = _browserState->GetPrefs();
+ ClearDataItem* clearDataItem =
+ [[[ClearDataItem alloc] initWithType:itemType] autorelease];
+ clearDataItem.text = l10n_util::GetNSString(titleMessageID);
+ if (prefs->GetBoolean(prefName)) {
+ clearDataItem.accessoryType = MDCCollectionViewCellAccessoryCheckmark;
+ }
+ clearDataItem.dataTypeMask = mask;
+ clearDataItem.prefName = prefName;
+ clearDataItem.accessibilityIdentifier =
+ [self getAccessibilityIdentifierFromItemType:itemType];
+
+ base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(self);
+ void (^updateUICallback)(const browsing_data::BrowsingDataCounter::Result&) =
+ ^(const browsing_data::BrowsingDataCounter::Result& result) {
+ base::scoped_nsobject<ClearBrowsingDataCollectionViewController>
+ strongSelf([weakSelf retain]);
+ NSString* counterText = [strongSelf getCounterTextFromResult:result];
+ [strongSelf updateCounter:itemType detailText:counterText];
+ };
+
+ [clearDataItem setCounter:BrowsingDataCounterWrapper::CreateCounterWrapper(
+ prefName, _browserState, prefs,
+ base::BindBlock(updateUICallback))];
+ return clearDataItem;
+}
+
+- (void)updateCounter:(NSInteger)itemType detailText:(NSString*)detailText {
+ NSIndexPath* indexPath = [self.collectionViewModel
+ indexPathForItemType:itemType
+ sectionIdentifier:SectionIdentifierDataTypes];
+
+ CollectionViewModel* model = self.collectionViewModel;
+ if (!model) {
+ return;
+ }
+ ClearDataItem* clearDataItem = base::mac::ObjCCastStrict<ClearDataItem>(
+ [model itemAtIndexPath:indexPath]);
+ // Because there is no counter for cookies, an explanatory text is displayed.
+ if (![clearDataItem hasCounter] &&
+ itemType != ItemTypeDataTypeCookiesSiteData) {
+ return;
+ }
+ clearDataItem.detailText = detailText;
+ [self reconfigureCellsForItems:@[ clearDataItem ]
+ inSectionWithIdentifier:SectionIdentifierDataTypes];
+ [self.collectionView.collectionViewLayout invalidateLayout];
+}
+
+- (CollectionViewItem*)footerForGoogleAccountSectionItem {
+ return _shouldShowNoticeAboutOtherFormsOfBrowsingHistory
+ ? [self footerGoogleAccountAndMyActivityItem]
+ : [self footerGoogleAccountItem];
+}
+
+- (CollectionViewItem*)footerGoogleAccountItem {
+ CollectionViewFooterItem* footerItem = [[[CollectionViewFooterItem alloc]
+ initWithType:ItemTypeFooterGoogleAccount] autorelease];
+ footerItem.text =
+ l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_FOOTER_ACCOUNT);
+ UIImage* image = ios::GetChromeBrowserProvider()
+ ->GetBrandedImageProvider()
+ ->GetClearBrowsingDataAccountActivityImage();
+ footerItem.image = image;
+ return footerItem;
+}
+
+- (CollectionViewItem*)footerGoogleAccountAndMyActivityItem {
+ UIImage* image = ios::GetChromeBrowserProvider()
+ ->GetBrandedImageProvider()
+ ->GetClearBrowsingDataAccountActivityImage();
+ return [self
+ footerItemWithType:ItemTypeFooterGoogleAccountAndMyActivity
+ titleID:IDS_IOS_CLEAR_BROWSING_DATA_FOOTER_ACCOUNT_AND_HISTORY
+ URL:kClearBrowsingDataMyActivityUrlInFooterURL
+ image:image];
+}
+
+- (CollectionViewItem*)footerSavedSiteDataItem {
+ UIImage* image = ios::GetChromeBrowserProvider()
+ ->GetBrandedImageProvider()
+ ->GetClearBrowsingDataSiteDataImage();
+ return [self
+ footerItemWithType:ItemTypeFooterSavedSiteData
+ titleID:IDS_IOS_CLEAR_BROWSING_DATA_FOOTER_SAVED_SITE_DATA
+ URL:kClearBrowsingDataLearnMoreURL
+ image:image];
+}
+
+- (CollectionViewItem*)footerClearSyncAndSavedSiteDataItem {
+ UIImage* infoIcon = [ChromeIcon infoIcon];
+ UIImage* image = TintImage(infoIcon, [[MDCPalette greyPalette] tint500]);
+ return [self
+ footerItemWithType:ItemTypeFooterClearSyncAndSavedSiteData
+ titleID:
+ IDS_IOS_CLEAR_BROWSING_DATA_FOOTER_CLEAR_SYNC_AND_SAVED_SITE_DATA
+ URL:kClearBrowsingDataLearnMoreURL
+ image:image];
+}
+
+- (CollectionViewItem*)footerItemWithType:(ItemType)itemType
+ titleID:(int)titleMessageID
+ URL:(const char[])URL
+ image:(UIImage*)image {
+ CollectionViewFooterItem* footerItem =
+ [[[CollectionViewFooterItem alloc] initWithType:itemType] autorelease];
+ footerItem.text = l10n_util::GetNSString(titleMessageID);
+ footerItem.linkURL = google_util::AppendGoogleLocaleParam(
+ GURL(URL), GetApplicationContext()->GetApplicationLocale());
+ footerItem.linkDelegate = self;
+ footerItem.image = image;
+ return footerItem;
+}
+
+- (CollectionViewItem*)timeRangeItem {
+ CollectionViewDetailItem* timeRangeItem = [[[CollectionViewDetailItem alloc]
+ initWithType:ItemTypeTimeRange] autorelease];
+ timeRangeItem.text = l10n_util::GetNSString(
+ IDS_IOS_CLEAR_BROWSING_DATA_TIME_RANGE_SELECTOR_TITLE);
+ NSString* detailText = [TimeRangeSelectorCollectionViewController
+ timePeriodLabelForPrefs:_browserState->GetPrefs()];
+ DCHECK(detailText);
+ timeRangeItem.detailText = detailText;
+ timeRangeItem.accessoryType =
+ MDCCollectionViewCellAccessoryDisclosureIndicator;
+ timeRangeItem.accessibilityTraits |= UIAccessibilityTraitButton;
+ return timeRangeItem;
+}
+
+#pragma mark UICollectionViewDataSource
+
+- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
+ cellForItemAtIndexPath:(NSIndexPath*)indexPath {
+ UICollectionViewCell* cell =
+ [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
+
+ NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
+ if (type == ItemTypeClearBrowsingDataButton) {
+ MDCCollectionViewTextCell* textCell =
+ base::mac::ObjCCastStrict<MDCCollectionViewTextCell>(cell);
+ textCell.textLabel.textColor = [[MDCPalette cr_redPalette] tint500];
+ }
+
+ return cell;
+}
+
+#pragma mark UICollectionViewDelegate
+
+- (void)collectionView:(UICollectionView*)collectionView
+ didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
+ [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
+ NSInteger itemType =
+ [self.collectionViewModel itemTypeForIndexPath:indexPath];
+
+ switch (itemType) {
+ case ItemTypeTimeRange: {
+ base::scoped_nsobject<UIViewController> controller(
+ [[TimeRangeSelectorCollectionViewController alloc]
+ initWithPrefs:_browserState->GetPrefs()
+ delegate:self]);
+ [self.navigationController pushViewController:controller animated:YES];
+ break;
+ }
+ case ItemTypeDataTypeBrowsingHistory:
+ case ItemTypeDataTypeCookiesSiteData:
+ case ItemTypeDataTypeCache:
+ case ItemTypeDataTypeSavedPasswords:
+ case ItemTypeDataTypeAutofill: {
+ // Toggle the checkmark.
+ // TODO(crbug.com/631486): Custom checkmark animation to be implemented.
+ ClearDataItem* clearDataItem = base::mac::ObjCCastStrict<ClearDataItem>(
+ [self.collectionViewModel itemAtIndexPath:indexPath]);
+ if (clearDataItem.accessoryType == MDCCollectionViewCellAccessoryNone) {
+ clearDataItem.accessoryType = MDCCollectionViewCellAccessoryCheckmark;
+ if (experimental_flags::IsNewClearBrowsingDataUIEnabled() &&
+ itemType == ItemTypeDataTypeCookiesSiteData) {
+ [self updateCounter:itemType
+ detailText:l10n_util::GetNSString(IDS_DEL_COOKIES_COUNTER)];
+ }
+ _browserState->GetPrefs()->SetBoolean(clearDataItem.prefName, true);
+ } else {
+ clearDataItem.accessoryType = MDCCollectionViewCellAccessoryNone;
+ _browserState->GetPrefs()->SetBoolean(clearDataItem.prefName, false);
+ if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+ // Hide counter text.
+ [self updateCounter:itemType detailText:nil];
+ }
+ }
+ [self reconfigureCellsForItems:@[ clearDataItem ]
+ inSectionWithIdentifier:SectionIdentifierDataTypes];
+ break;
+ }
+ case ItemTypeClearBrowsingDataButton:
+ [self alertAndClearData];
+ break;
+ default:
+ break;
+ }
+}
+
+#pragma mark Properties
+
+- (void)setShouldShowNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)showNotice {
+ _shouldShowNoticeAboutOtherFormsOfBrowsingHistory = showNotice;
+ UMA_HISTOGRAM_BOOLEAN(
+ "History.ClearBrowsingData.HistoryNoticeShownInFooterWhenUpdated",
+ _shouldShowNoticeAboutOtherFormsOfBrowsingHistory);
+
+ // Update the account footer if the model was already loaded.
+ CollectionViewModel* model = self.collectionViewModel;
+ if (!model) {
+ return;
+ }
+ SigninManager* signinManager =
+ ios::SigninManagerFactory::GetForBrowserState(_browserState);
+ if (!signinManager->IsAuthenticated()) {
+ return;
+ }
+
+ CollectionViewItem* footerItem = [self footerForGoogleAccountSectionItem];
+ // TODO(crbug.com/650424): Simplify with setFooter:inSection: when the bug in
+ // MDC is fixed.
+ // Remove the footer if there is one in that section.
+ if ([model hasSectionForSectionIdentifier:SectionIdentifierGoogleAccount]) {
+ if ([model hasItemForItemType:ItemTypeFooterGoogleAccount
+ sectionIdentifier:SectionIdentifierGoogleAccount]) {
+ [model removeItemWithType:ItemTypeFooterGoogleAccount
+ fromSectionWithIdentifier:SectionIdentifierGoogleAccount];
+ } else {
+ [model removeItemWithType:ItemTypeFooterGoogleAccountAndMyActivity
+ fromSectionWithIdentifier:SectionIdentifierGoogleAccount];
+ }
+ }
+ // Add the new footer.
+ [model addItem:footerItem
+ toSectionWithIdentifier:SectionIdentifierGoogleAccount];
+ [self reconfigureCellsForItems:@[ footerItem ]
+ inSectionWithIdentifier:SectionIdentifierGoogleAccount];
+
+ // Relayout the cells to adapt to the new contents height.
+ [self.collectionView.collectionViewLayout invalidateLayout];
+}
+
+#pragma mark Clear browsing data
+
+- (BOOL)alertAndClearData {
+ int dataTypeMaskToRemove = 0;
+ NSArray* dataTypeItems = [self.collectionViewModel
+ itemsInSectionWithIdentifier:SectionIdentifierDataTypes];
+ for (ClearDataItem* dataTypeItem in dataTypeItems) {
+ DCHECK([dataTypeItem isKindOfClass:[ClearDataItem class]]);
+ if (dataTypeItem.accessoryType == MDCCollectionViewCellAccessoryCheckmark) {
+ dataTypeMaskToRemove |= dataTypeItem.dataTypeMask;
+ }
+ }
+ if (dataTypeMaskToRemove == 0) {
+ // Nothing to clear (no data types selected).
+ return YES;
+ }
+ base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(self);
+ UIAlertController* alertController = [UIAlertController
+ alertControllerWithTitle:nil
+ message:nil
+ preferredStyle:UIAlertControllerStyleActionSheet];
+
+ UIAlertAction* clearDataAction = [UIAlertAction
+ actionWithTitle:l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON)
+ style:UIAlertActionStyleDestructive
+ handler:^(UIAlertAction* action) {
+ [weakSelf clearDataForDataTypes:dataTypeMaskToRemove];
+ }];
+ UIAlertAction* cancelAction =
+ [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_CANCEL)
+ style:UIAlertActionStyleCancel
+ handler:nil];
+ [alertController addAction:clearDataAction];
+ [alertController addAction:cancelAction];
+ [self presentViewController:alertController animated:YES completion:nil];
+ return YES;
+}
+
+- (void)clearDataForDataTypes:(int)dataTypeMask {
+ DCHECK(dataTypeMask);
+ base::scoped_nsobject<ClearBrowsingDataCommand> command(
+ [[ClearBrowsingDataCommand alloc] initWithBrowserState:_browserState
+ mask:dataTypeMask
+ timePeriod:_timePeriod]);
+ [self chromeExecuteCommand:command];
+
+ if (!!(dataTypeMask && IOSChromeBrowsingDataRemover::REMOVE_HISTORY)) {
+ [self showBrowsingHistoryRemovedDialog];
+ }
+}
+
+- (void)showBrowsingHistoryRemovedDialog {
+ PrefService* prefs = _browserState->GetPrefs();
+ int noticeShownTimes = prefs->GetInteger(
+ browsing_data::prefs::kClearBrowsingDataHistoryNoticeShownTimes);
+
+ // When the deletion is complete, we might show an additional dialog with
+ // a notice about other forms of browsing history. This is the case if
+ const bool showDialog =
+ // 1. The dialog is relevant for the user.
+ _shouldPopupDialogAboutOtherFormsOfBrowsingHistory &&
+ // 2. The notice has been shown less than |kMaxTimesHistoryNoticeShown|.
+ noticeShownTimes < kMaxTimesHistoryNoticeShown;
+ UMA_HISTOGRAM_BOOLEAN(
+ "History.ClearBrowsingData.ShownHistoryNoticeAfterClearing", showDialog);
+ if (!showDialog) {
+ return;
+ }
+
+ // Increment the preference.
+ prefs->SetInteger(
+ browsing_data::prefs::kClearBrowsingDataHistoryNoticeShownTimes,
+ noticeShownTimes + 1);
+
+ 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);
+
+ UIAlertController* alertController =
+ [UIAlertController alertControllerWithTitle:title
+ message:message
+ preferredStyle:UIAlertControllerStyleAlert];
+
+ base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(self);
+ UIAlertAction* openMyActivityAction = [UIAlertAction
+ actionWithTitle:
+ l10n_util::GetNSString(
+ IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_OPEN_HISTORY_BUTTON)
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction* action) {
+ [weakSelf openMyActivityLink];
+ }];
+
+ UIAlertAction* okAction = [UIAlertAction
+ actionWithTitle:l10n_util::GetNSString(
+ IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_OK_BUTTON)
+ style:UIAlertActionStyleCancel
+ handler:nil];
+ [alertController addAction:openMyActivityAction];
+ [alertController addAction:okAction];
+ [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)openMyActivityLink {
+ base::scoped_nsobject<OpenUrlCommand> openMyActivityCommand(
+ [[OpenUrlCommand alloc] initWithURLFromChrome:GURL(kGoogleMyAccountURL)]);
+ openMyActivityCommand.get().tag = IDC_CLOSE_SETTINGS_AND_OPEN_URL;
+ [self chromeExecuteCommand:openMyActivityCommand];
+}
+
+- (NSString*)getAccessibilityIdentifierFromItemType:(NSInteger)itemType {
+ switch (itemType) {
+ case ItemTypeDataTypeBrowsingHistory:
+ return kClearBrowsingHistoryCellId;
+ case ItemTypeDataTypeCookiesSiteData:
+ return kClearCookiesCellId;
+ case ItemTypeDataTypeCache:
+ return kClearCacheCellId;
+ case ItemTypeDataTypeSavedPasswords:
+ return kClearSavedPasswordsCellId;
+ case ItemTypeDataTypeAutofill:
+ return kClearAutofillCellId;
+ default: {
+ NOTREACHED();
+ return nil;
+ }
+ }
+}
+
+- (void)restartCounters:(int)data_mask {
+ CollectionViewModel* model = self.collectionViewModel;
+ if (!model)
+ return;
+
+ if (data_mask &
+ (IOSChromeBrowsingDataRemover::REMOVE_HISTORY |
+ IOSChromeBrowsingDataRemover::REMOVE_GOOGLE_APP_LAUNCHER_DATA)) {
+ NSIndexPath* indexPath = [self.collectionViewModel
+ indexPathForItemType:ItemTypeDataTypeBrowsingHistory
+ sectionIdentifier:SectionIdentifierDataTypes];
+ ClearDataItem* historyItem = base::mac::ObjCCastStrict<ClearDataItem>(
+ [model itemAtIndexPath:indexPath]);
+ [historyItem restartCounter];
+ }
+
+ if (data_mask & IOSChromeBrowsingDataRemover::REMOVE_PASSWORDS) {
+ NSIndexPath* indexPath = [self.collectionViewModel
+ indexPathForItemType:ItemTypeDataTypeSavedPasswords
+ sectionIdentifier:SectionIdentifierDataTypes];
+ ClearDataItem* passwordsItem = base::mac::ObjCCastStrict<ClearDataItem>(
+ [model itemAtIndexPath:indexPath]);
+ [passwordsItem restartCounter];
+ }
+
+ if (data_mask & IOSChromeBrowsingDataRemover::REMOVE_FORM_DATA) {
+ NSIndexPath* indexPath = [self.collectionViewModel
+ indexPathForItemType:ItemTypeDataTypeAutofill
+ sectionIdentifier:SectionIdentifierDataTypes];
+ ClearDataItem* autofillItem = base::mac::ObjCCastStrict<ClearDataItem>(
+ [model itemAtIndexPath:indexPath]);
+ [autofillItem restartCounter];
+ }
+}
+
+- (NSString*)getCounterTextFromResult:
+ (const browsing_data::BrowsingDataCounter::Result&)result {
+ std::string prefName = result.source()->GetPrefName();
+ if (!result.Finished()) {
+ // The counter is still counting.
+ return l10n_util::GetNSString(IDS_CLEAR_BROWSING_DATA_CALCULATING);
+ }
+
+ if (prefName == browsing_data::prefs::kDeleteCache) {
+ browsing_data::BrowsingDataCounter::ResultInt cacheSizeBytes =
+ static_cast<const browsing_data::BrowsingDataCounter::FinishedResult*>(
+ &result)
+ ->Value();
+
+ // Three cases: Nonzero result for the entire cache, nonzero result for
+ // a subset of cache (i.e. a finite time interval), and almost zero (less
+ // than 1 MB). There is no exact information that the cache is empty so that
+ // falls into the almost zero case, which is displayed as less than 1 MB.
+ // Because of this, the lowest unit that can be used is MB.
+ static const int kBytesInAMegabyte = 1 << 20;
+ if (cacheSizeBytes >= kBytesInAMegabyte) {
+ base::scoped_nsobject<NSByteCountFormatter> formatter(
+ [[NSByteCountFormatter alloc] init]);
+ formatter.get().allowedUnits = NSByteCountFormatterUseAll &
+ (~NSByteCountFormatterUseBytes) &
+ (~NSByteCountFormatterUseKB);
+ formatter.get().countStyle = NSByteCountFormatterCountStyleMemory;
+ NSString* formattedSize = [formatter stringFromByteCount:cacheSizeBytes];
+ return (_timePeriod == browsing_data::ALL_TIME)
+ ? formattedSize
+ : l10n_util::GetNSStringF(
+ IDS_DEL_CACHE_COUNTER_UPPER_ESTIMATE,
+ base::SysNSStringToUTF16(formattedSize));
+ }
+ return l10n_util::GetNSString(IDS_DEL_CACHE_COUNTER_ALMOST_EMPTY);
+ }
+ return base::SysUTF16ToNSString(
+ browsing_data::GetCounterTextFromResult(&result));
+}
+
+#pragma mark MDCCollectionViewStylingDelegate
+
+- (BOOL)collectionView:(UICollectionView*)collectionView
+ hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
+ NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
+ switch (type) {
+ case ItemTypeFooterSavedSiteData:
+ case ItemTypeFooterGoogleAccount:
+ case ItemTypeFooterGoogleAccountAndMyActivity:
+ case ItemTypeFooterClearSyncAndSavedSiteData:
+ return YES;
+ default:
+ return NO;
+ }
+}
+
+- (MDCCollectionViewCellStyle)collectionView:(UICollectionView*)collectionView
+ cellStyleForSection:(NSInteger)section {
+ NSInteger sectionIdentifier =
+ [self.collectionViewModel sectionIdentifierForSection:section];
+ switch (sectionIdentifier) {
+ case SectionIdentifierGoogleAccount:
+ case SectionIdentifierClearSyncAndSavedSiteData:
+ case SectionIdentifierSavedSiteData:
+ // Display the footer in the default style with no "card" UI and no
+ // section padding.
+ return MDCCollectionViewCellStyleDefault;
+ default:
+ return self.styler.cellStyle;
+ }
+}
+
+- (BOOL)collectionView:(UICollectionView*)collectionView
+ shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath {
+ NSInteger sectionIdentifier =
+ [self.collectionViewModel sectionIdentifierForSection:indexPath.section];
+ switch (sectionIdentifier) {
+ case SectionIdentifierGoogleAccount:
+ case SectionIdentifierClearSyncAndSavedSiteData:
+ case SectionIdentifierSavedSiteData:
+ // Display the Learn More footer without any background image or
+ // shadowing.
+ return YES;
+ default:
+ return NO;
+ }
+}
+
+- (CGFloat)collectionView:(UICollectionView*)collectionView
+ cellHeightAtIndexPath:(NSIndexPath*)indexPath {
+ NSInteger sectionIdentifier =
+ [self.collectionViewModel sectionIdentifierForSection:indexPath.section];
+ switch (sectionIdentifier) {
+ case SectionIdentifierGoogleAccount:
+ case SectionIdentifierClearSyncAndSavedSiteData:
+ case SectionIdentifierSavedSiteData: {
+ CollectionViewItem* item =
+ [self.collectionViewModel itemAtIndexPath:indexPath];
+ return [MDCCollectionViewCell
+ cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
+ forItem:item];
+ }
+ case SectionIdentifierDataTypes: {
+ ClearDataItem* clearDataItem = base::mac::ObjCCastStrict<ClearDataItem>(
+ [self.collectionViewModel itemAtIndexPath:indexPath]);
+ return (clearDataItem.detailText.length > 0)
+ ? MDCCellDefaultTwoLineHeight
+ : MDCCellDefaultOneLineHeight;
+ }
+ default:
+ return MDCCellDefaultOneLineHeight;
+ }
+}
+
+#pragma mark TimeRangeSelectorCollectionViewControllerDelegate
+
+- (void)timeRangeSelectorViewController:
+ (TimeRangeSelectorCollectionViewController*)collectionViewController
+ didSelectTimePeriod:(browsing_data::TimePeriod)timePeriod {
+ _timePeriod = timePeriod;
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698