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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_cont roller.h"
6
7 #include <memory>
8 #include <string>
9
10 #include "base/ios/ios_util.h"
11 #include "base/ios/weak_nsobject.h"
12 #include "base/logging.h"
13 #include "base/mac/bind_objc_block.h"
14 #include "base/mac/foundation_util.h"
15 #include "base/mac/scoped_nsobject.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/strings/string_piece.h"
19 #include "base/strings/sys_string_conversions.h"
20 #include "components/browser_sync/profile_sync_service.h"
21 #include "components/browsing_data/core/browsing_data_utils.h"
22 #include "components/browsing_data/core/counters/browsing_data_counter.h"
23 #include "components/browsing_data/core/history_notice_utils.h"
24 #include "components/browsing_data/core/pref_names.h"
25 #include "components/google/core/browser/google_util.h"
26 #include "components/history/core/browser/web_history_service.h"
27 #include "components/prefs/pref_service.h"
28 #include "components/signin/core/browser/signin_manager.h"
29 #include "components/strings/grit/components_strings.h"
30 #include "ios/chrome/browser/application_context.h"
31 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
32 #include "ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.h"
33 #include "ios/chrome/browser/browsing_data/ios_browsing_data_counter_factory.h"
34 #include "ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.h"
35 #include "ios/chrome/browser/chrome_url_constants.h"
36 #include "ios/chrome/browser/experimental_flags.h"
37 #include "ios/chrome/browser/history/web_history_service_factory.h"
38 #include "ios/chrome/browser/signin/signin_manager_factory.h"
39 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
40 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrom e.h"
41 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item .h"
42 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item .h"
43 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
44 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h "
45 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
46 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
47 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
48 #import "ios/chrome/browser/ui/commands/clear_browsing_data_command.h"
49 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
50 #import "ios/chrome/browser/ui/commands/open_url_command.h"
51 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
52 #import "ios/chrome/browser/ui/settings/time_range_selector_collection_view_cont roller.h"
53 #include "ios/chrome/browser/ui/ui_util.h"
54 #import "ios/chrome/browser/ui/uikit_ui_util.h"
55 #include "ios/chrome/common/channel_info.h"
56 #include "ios/chrome/grit/ios_chromium_strings.h"
57 #include "ios/chrome/grit/ios_strings.h"
58 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
59 #include "ios/public/provider/chrome/browser/images/branded_image_provider.h"
60 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h"
61 #include "ui/base/l10n/l10n_util_mac.h"
62 #include "url/gurl.h"
63
64 NSString* const kClearBrowsingDataCollectionViewId =
65 @"kClearBrowsingDataCollectionViewId";
66 NSString* const kClearBrowsingHistoryCellId = @"kClearBrowsingHistoryCellId";
67 NSString* const kClearCookiesCellId = @"kClearCookiesCellId";
68 NSString* const kClearCacheCellId = @"kClearCacheCellId";
69 NSString* const kClearSavedPasswordsCellId = @"kClearSavedPasswordsCellId";
70 NSString* const kClearAutofillCellId = @"kClearAutofillCellId";
71
72 namespace {
73
74 typedef NS_ENUM(NSInteger, SectionIdentifier) {
75 SectionIdentifierDataTypes = kSectionIdentifierEnumZero,
76 SectionIdentifierClearBrowsingDataButton,
77 SectionIdentifierGoogleAccount,
78 SectionIdentifierClearSyncAndSavedSiteData,
79 SectionIdentifierSavedSiteData,
80 SectionIdentifierTimeRange,
81 };
82
83 typedef NS_ENUM(NSInteger, ItemType) {
84 ItemTypeDataTypeBrowsingHistory = kItemTypeEnumZero,
85 ItemTypeDataTypeCookiesSiteData,
86 ItemTypeDataTypeCache,
87 ItemTypeDataTypeSavedPasswords,
88 ItemTypeDataTypeAutofill,
89 ItemTypeClearBrowsingDataButton,
90 ItemTypeFooterGoogleAccount,
91 ItemTypeFooterGoogleAccountAndMyActivity,
92 ItemTypeFooterSavedSiteData,
93 ItemTypeFooterClearSyncAndSavedSiteData,
94 ItemTypeTimeRange,
95 };
96
97 const int kMaxTimesHistoryNoticeShown = 1;
98
99 } // namespace
100
101 // Collection view item identifying a clear browsing data content view.
102 @interface ClearDataItem : CollectionViewTextItem {
103 // Data volume counter associated with the item.
104 std::unique_ptr<BrowsingDataCounterWrapper> _counter;
105 }
106
107 // Mask of the data to be cleared.
108 @property(nonatomic, assign) int dataTypeMask;
109
110 // Pref name associated with the item.
111 @property(nonatomic, assign) const char* prefName;
112
113 // Sets the counter associated with the data type represented by the item.
114 - (void)setCounter:(std::unique_ptr<BrowsingDataCounterWrapper>)counter;
115
116 // Checks if the item has a counter.
117 - (BOOL)hasCounter;
118
119 // Restarts the counter.
120 - (void)restartCounter;
121
122 @end
123
124 @implementation ClearDataItem
125
126 @synthesize dataTypeMask = _dataTypeMask;
127 @synthesize prefName = _prefName;
128
129 - (void)setCounter:(std::unique_ptr<BrowsingDataCounterWrapper>)counter {
130 _counter = std::move(counter);
131 }
132
133 - (BOOL)hasCounter {
134 return !!_counter;
135 }
136
137 - (void)restartCounter {
138 if (_counter)
139 _counter->RestartCounter();
140 }
141
142 @end
143
144 @interface ClearBrowsingDataCollectionViewController ()<
145 TimeRangeSelectorCollectionViewControllerDelegate> {
146 ios::ChromeBrowserState* _browserState; // weak
147
148 browsing_data::TimePeriod _timePeriod;
149
150 IOSChromeBrowsingDataRemover::CallbackSubscription _callbackSubscription;
151 }
152
153 @property(nonatomic, assign)
154 BOOL shouldShowNoticeAboutOtherFormsOfBrowsingHistory;
155 @property(nonatomic, assign)
156 BOOL shouldPopupDialogAboutOtherFormsOfBrowsingHistory;
157
158 // Displays an action sheet to the user confirming the clearing of user data. If
159 // the clearing is confirmed, clears the data.
160 // Always returns YES to ensure that the collection view cell is deselected.
161 - (BOOL)alertAndClearData;
162
163 // Clears the data stored for |dataTypeMask|.
164 - (void)clearDataForDataTypes:(int)dataTypeMask;
165
166 // Returns the accessibility identifier for the cell corresponding to
167 // |itemType|.
168 - (NSString*)getAccessibilityIdentifierFromItemType:(NSInteger)itemType;
169
170 // Restarts the counters for data types specified in the mask.
171 - (void)restartCounters:(int)data_mask;
172
173 @end
174
175 @implementation ClearBrowsingDataCollectionViewController
176
177 @synthesize shouldShowNoticeAboutOtherFormsOfBrowsingHistory =
178 _shouldShowNoticeAboutOtherFormsOfBrowsingHistory;
179 @synthesize shouldPopupDialogAboutOtherFormsOfBrowsingHistory =
180 _shouldPopupDialogAboutOtherFormsOfBrowsingHistory;
181
182 #pragma mark Initialization
183
184 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
185 DCHECK(browserState);
186 self = [super initWithStyle:CollectionViewControllerStyleAppBar];
187 if (self) {
188 self.accessibilityTraits |= UIAccessibilityTraitButton;
189
190 _browserState = browserState;
191 if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
192 int prefValue = browserState->GetPrefs()->GetInteger(
193 browsing_data::prefs::kDeleteTimePeriod);
194 prefValue = MAX(0, prefValue);
195 if (prefValue > browsing_data::TIME_PERIOD_LAST) {
196 prefValue = browsing_data::TIME_PERIOD_LAST;
197 }
198 _timePeriod = static_cast<browsing_data::TimePeriod>(prefValue);
199 } else {
200 _timePeriod = browsing_data::ALL_TIME;
201 }
202
203 self.title = l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_TITLE);
204 self.collectionViewAccessibilityIdentifier =
205 kClearBrowsingDataCollectionViewId;
206
207 if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
208 base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(
209 self);
210 void (^dataClearedCallback)(
211 const IOSChromeBrowsingDataRemover::NotificationDetails&) =
212 ^(const IOSChromeBrowsingDataRemover::NotificationDetails& details) {
213 base::scoped_nsobject<ClearBrowsingDataCollectionViewController>
214 strongSelf([weakSelf retain]);
215 [strongSelf restartCounters:details.removal_mask];
216 };
217 _callbackSubscription =
218 IOSChromeBrowsingDataRemover::RegisterOnBrowsingDataRemovedCallback(
219 base::BindBlock(dataClearedCallback));
220 }
221
222 [self loadModel];
223 [self restartCounters:IOSChromeBrowsingDataRemover::REMOVE_ALL];
224 }
225 return self;
226 }
227
228 - (void)viewDidLoad {
229 [super viewDidLoad];
230
231 SigninManager* signinManager =
232 ios::SigninManagerFactory::GetForBrowserState(_browserState);
233 if (!signinManager->IsAuthenticated()) {
234 return;
235 }
236
237 browser_sync::ProfileSyncService* syncService =
238 IOSChromeProfileSyncServiceFactory::GetForBrowserState(_browserState);
239 history::WebHistoryService* historyService =
240 ios::WebHistoryServiceFactory::GetForBrowserState(_browserState);
241
242 base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(self);
243 browsing_data::ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
244 syncService, historyService, base::BindBlock(^(bool shouldShowNotice) {
245 base::scoped_nsobject<ClearBrowsingDataCollectionViewController>
246 strongSelf([weakSelf retain]);
247 [strongSelf setShouldShowNoticeAboutOtherFormsOfBrowsingHistory:
248 shouldShowNotice];
249 }));
250
251 browsing_data::ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
252 syncService, historyService, GetChannel(),
253 base::BindBlock(^(bool shouldShowPopup) {
254 base::scoped_nsobject<ClearBrowsingDataCollectionViewController>
255 strongSelf([weakSelf retain]);
256 [strongSelf setShouldPopupDialogAboutOtherFormsOfBrowsingHistory:
257 shouldShowPopup];
258 }));
259 }
260
261 #pragma mark CollectionViewController
262
263 - (void)loadModel {
264 [super loadModel];
265 CollectionViewModel* model = self.collectionViewModel;
266
267 // Time range section.
268 if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
269 [model addSectionWithIdentifier:SectionIdentifierTimeRange];
270 [model addItem:[self timeRangeItem]
271 toSectionWithIdentifier:SectionIdentifierTimeRange];
272 }
273
274 // Data types section.
275 [model addSectionWithIdentifier:SectionIdentifierDataTypes];
276 int clearBrowsingHistoryMask =
277 IOSChromeBrowsingDataRemover::REMOVE_HISTORY |
278 IOSChromeBrowsingDataRemover::REMOVE_GOOGLE_APP_LAUNCHER_DATA;
279 CollectionViewItem* browsingHistoryItem =
280 [self clearDataItemWithType:ItemTypeDataTypeBrowsingHistory
281 titleID:IDS_IOS_CLEAR_BROWSING_HISTORY
282 mask:clearBrowsingHistoryMask
283 prefName:browsing_data::prefs::kDeleteBrowsingHistory];
284 [model addItem:browsingHistoryItem
285 toSectionWithIdentifier:SectionIdentifierDataTypes];
286
287 // This data type doesn't currently have an associated counter, but displays
288 // an explanatory text instead, when the new UI is enabled.
289 ClearDataItem* cookiesSiteDataItem =
290 [self clearDataItemWithType:ItemTypeDataTypeCookiesSiteData
291 titleID:IDS_IOS_CLEAR_COOKIES
292 mask:IOSChromeBrowsingDataRemover::REMOVE_SITE_DATA
293 prefName:browsing_data::prefs::kDeleteCookies];
294 if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
295 if (_browserState->GetPrefs()->GetBoolean(
296 browsing_data::prefs::kDeleteCookies)) {
297 cookiesSiteDataItem.detailText =
298 l10n_util::GetNSString(IDS_DEL_COOKIES_COUNTER);
299 }
300 }
301 [model addItem:cookiesSiteDataItem
302 toSectionWithIdentifier:SectionIdentifierDataTypes];
303
304 ClearDataItem* cacheItem =
305 [self clearDataItemWithType:ItemTypeDataTypeCache
306 titleID:IDS_IOS_CLEAR_CACHE
307 mask:IOSChromeBrowsingDataRemover::REMOVE_CACHE
308 prefName:browsing_data::prefs::kDeleteCache];
309 [model addItem:cacheItem toSectionWithIdentifier:SectionIdentifierDataTypes];
310
311 ClearDataItem* savedPasswordsItem =
312 [self clearDataItemWithType:ItemTypeDataTypeSavedPasswords
313 titleID:IDS_IOS_CLEAR_SAVED_PASSWORDS
314 mask:IOSChromeBrowsingDataRemover::REMOVE_PASSWORDS
315 prefName:browsing_data::prefs::kDeletePasswords];
316 [model addItem:savedPasswordsItem
317 toSectionWithIdentifier:SectionIdentifierDataTypes];
318
319 ClearDataItem* autofillItem =
320 [self clearDataItemWithType:ItemTypeDataTypeAutofill
321 titleID:IDS_IOS_CLEAR_AUTOFILL
322 mask:IOSChromeBrowsingDataRemover::REMOVE_FORM_DATA
323 prefName:browsing_data::prefs::kDeleteFormData];
324 [model addItem:autofillItem
325 toSectionWithIdentifier:SectionIdentifierDataTypes];
326
327 // Clear Browsing Data button.
328 [model addSectionWithIdentifier:SectionIdentifierClearBrowsingDataButton];
329 CollectionViewTextItem* clearButtonItem = [[[CollectionViewTextItem alloc]
330 initWithType:ItemTypeClearBrowsingDataButton] autorelease];
331 clearButtonItem.text = l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON);
332 clearButtonItem.accessibilityTraits |= UIAccessibilityTraitButton;
333 [model addItem:clearButtonItem
334 toSectionWithIdentifier:SectionIdentifierClearBrowsingDataButton];
335
336 // Google Account footer.
337 SigninManager* signinManager =
338 ios::SigninManagerFactory::GetForBrowserState(_browserState);
339 if (signinManager->IsAuthenticated()) {
340 // TODO(crbug.com/650424): Footer items must currently go into a separate
341 // section, to work around a drawing bug in MDC.
342 [model addSectionWithIdentifier:SectionIdentifierGoogleAccount];
343 [model addItem:[self footerForGoogleAccountSectionItem]
344 toSectionWithIdentifier:SectionIdentifierGoogleAccount];
345 }
346
347 browser_sync::ProfileSyncService* syncService =
348 IOSChromeProfileSyncServiceFactory::GetForBrowserState(_browserState);
349 if (syncService && syncService->IsSyncActive()) {
350 // TODO(crbug.com/650424): Footer items must currently go into a separate
351 // section, to work around a drawing bug in MDC.
352 [model addSectionWithIdentifier:SectionIdentifierClearSyncAndSavedSiteData];
353 [model addItem:[self footerClearSyncAndSavedSiteDataItem]
354 toSectionWithIdentifier:SectionIdentifierClearSyncAndSavedSiteData];
355 } else {
356 // TODO(crbug.com/650424): Footer items must currently go into a separate
357 // section, to work around a drawing bug in MDC.
358 [model addSectionWithIdentifier:SectionIdentifierSavedSiteData];
359 [model addItem:[self footerSavedSiteDataItem]
360 toSectionWithIdentifier:SectionIdentifierSavedSiteData];
361 }
362 }
363
364 #pragma mark Items
365
366 - (ClearDataItem*)clearDataItemWithType:(ItemType)itemType
367 titleID:(int)titleMessageID
368 mask:(int)mask
369 prefName:(const char*)prefName {
370 PrefService* prefs = _browserState->GetPrefs();
371 ClearDataItem* clearDataItem =
372 [[[ClearDataItem alloc] initWithType:itemType] autorelease];
373 clearDataItem.text = l10n_util::GetNSString(titleMessageID);
374 if (prefs->GetBoolean(prefName)) {
375 clearDataItem.accessoryType = MDCCollectionViewCellAccessoryCheckmark;
376 }
377 clearDataItem.dataTypeMask = mask;
378 clearDataItem.prefName = prefName;
379 clearDataItem.accessibilityIdentifier =
380 [self getAccessibilityIdentifierFromItemType:itemType];
381
382 base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(self);
383 void (^updateUICallback)(const browsing_data::BrowsingDataCounter::Result&) =
384 ^(const browsing_data::BrowsingDataCounter::Result& result) {
385 base::scoped_nsobject<ClearBrowsingDataCollectionViewController>
386 strongSelf([weakSelf retain]);
387 NSString* counterText = [strongSelf getCounterTextFromResult:result];
388 [strongSelf updateCounter:itemType detailText:counterText];
389 };
390
391 [clearDataItem setCounter:BrowsingDataCounterWrapper::CreateCounterWrapper(
392 prefName, _browserState, prefs,
393 base::BindBlock(updateUICallback))];
394 return clearDataItem;
395 }
396
397 - (void)updateCounter:(NSInteger)itemType detailText:(NSString*)detailText {
398 NSIndexPath* indexPath = [self.collectionViewModel
399 indexPathForItemType:itemType
400 sectionIdentifier:SectionIdentifierDataTypes];
401
402 CollectionViewModel* model = self.collectionViewModel;
403 if (!model) {
404 return;
405 }
406 ClearDataItem* clearDataItem = base::mac::ObjCCastStrict<ClearDataItem>(
407 [model itemAtIndexPath:indexPath]);
408 // Because there is no counter for cookies, an explanatory text is displayed.
409 if (![clearDataItem hasCounter] &&
410 itemType != ItemTypeDataTypeCookiesSiteData) {
411 return;
412 }
413 clearDataItem.detailText = detailText;
414 [self reconfigureCellsForItems:@[ clearDataItem ]
415 inSectionWithIdentifier:SectionIdentifierDataTypes];
416 [self.collectionView.collectionViewLayout invalidateLayout];
417 }
418
419 - (CollectionViewItem*)footerForGoogleAccountSectionItem {
420 return _shouldShowNoticeAboutOtherFormsOfBrowsingHistory
421 ? [self footerGoogleAccountAndMyActivityItem]
422 : [self footerGoogleAccountItem];
423 }
424
425 - (CollectionViewItem*)footerGoogleAccountItem {
426 CollectionViewFooterItem* footerItem = [[[CollectionViewFooterItem alloc]
427 initWithType:ItemTypeFooterGoogleAccount] autorelease];
428 footerItem.text =
429 l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_FOOTER_ACCOUNT);
430 UIImage* image = ios::GetChromeBrowserProvider()
431 ->GetBrandedImageProvider()
432 ->GetClearBrowsingDataAccountActivityImage();
433 footerItem.image = image;
434 return footerItem;
435 }
436
437 - (CollectionViewItem*)footerGoogleAccountAndMyActivityItem {
438 UIImage* image = ios::GetChromeBrowserProvider()
439 ->GetBrandedImageProvider()
440 ->GetClearBrowsingDataAccountActivityImage();
441 return [self
442 footerItemWithType:ItemTypeFooterGoogleAccountAndMyActivity
443 titleID:IDS_IOS_CLEAR_BROWSING_DATA_FOOTER_ACCOUNT_AND_HISTORY
444 URL:kClearBrowsingDataMyActivityUrlInFooterURL
445 image:image];
446 }
447
448 - (CollectionViewItem*)footerSavedSiteDataItem {
449 UIImage* image = ios::GetChromeBrowserProvider()
450 ->GetBrandedImageProvider()
451 ->GetClearBrowsingDataSiteDataImage();
452 return [self
453 footerItemWithType:ItemTypeFooterSavedSiteData
454 titleID:IDS_IOS_CLEAR_BROWSING_DATA_FOOTER_SAVED_SITE_DATA
455 URL:kClearBrowsingDataLearnMoreURL
456 image:image];
457 }
458
459 - (CollectionViewItem*)footerClearSyncAndSavedSiteDataItem {
460 UIImage* infoIcon = [ChromeIcon infoIcon];
461 UIImage* image = TintImage(infoIcon, [[MDCPalette greyPalette] tint500]);
462 return [self
463 footerItemWithType:ItemTypeFooterClearSyncAndSavedSiteData
464 titleID:
465 IDS_IOS_CLEAR_BROWSING_DATA_FOOTER_CLEAR_SYNC_AND_SAVED_SIT E_DATA
466 URL:kClearBrowsingDataLearnMoreURL
467 image:image];
468 }
469
470 - (CollectionViewItem*)footerItemWithType:(ItemType)itemType
471 titleID:(int)titleMessageID
472 URL:(const char[])URL
473 image:(UIImage*)image {
474 CollectionViewFooterItem* footerItem =
475 [[[CollectionViewFooterItem alloc] initWithType:itemType] autorelease];
476 footerItem.text = l10n_util::GetNSString(titleMessageID);
477 footerItem.linkURL = google_util::AppendGoogleLocaleParam(
478 GURL(URL), GetApplicationContext()->GetApplicationLocale());
479 footerItem.linkDelegate = self;
480 footerItem.image = image;
481 return footerItem;
482 }
483
484 - (CollectionViewItem*)timeRangeItem {
485 CollectionViewDetailItem* timeRangeItem = [[[CollectionViewDetailItem alloc]
486 initWithType:ItemTypeTimeRange] autorelease];
487 timeRangeItem.text = l10n_util::GetNSString(
488 IDS_IOS_CLEAR_BROWSING_DATA_TIME_RANGE_SELECTOR_TITLE);
489 NSString* detailText = [TimeRangeSelectorCollectionViewController
490 timePeriodLabelForPrefs:_browserState->GetPrefs()];
491 DCHECK(detailText);
492 timeRangeItem.detailText = detailText;
493 timeRangeItem.accessoryType =
494 MDCCollectionViewCellAccessoryDisclosureIndicator;
495 timeRangeItem.accessibilityTraits |= UIAccessibilityTraitButton;
496 return timeRangeItem;
497 }
498
499 #pragma mark UICollectionViewDataSource
500
501 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
502 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
503 UICollectionViewCell* cell =
504 [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
505
506 NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
507 if (type == ItemTypeClearBrowsingDataButton) {
508 MDCCollectionViewTextCell* textCell =
509 base::mac::ObjCCastStrict<MDCCollectionViewTextCell>(cell);
510 textCell.textLabel.textColor = [[MDCPalette cr_redPalette] tint500];
511 }
512
513 return cell;
514 }
515
516 #pragma mark UICollectionViewDelegate
517
518 - (void)collectionView:(UICollectionView*)collectionView
519 didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
520 [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
521 NSInteger itemType =
522 [self.collectionViewModel itemTypeForIndexPath:indexPath];
523
524 switch (itemType) {
525 case ItemTypeTimeRange: {
526 base::scoped_nsobject<UIViewController> controller(
527 [[TimeRangeSelectorCollectionViewController alloc]
528 initWithPrefs:_browserState->GetPrefs()
529 delegate:self]);
530 [self.navigationController pushViewController:controller animated:YES];
531 break;
532 }
533 case ItemTypeDataTypeBrowsingHistory:
534 case ItemTypeDataTypeCookiesSiteData:
535 case ItemTypeDataTypeCache:
536 case ItemTypeDataTypeSavedPasswords:
537 case ItemTypeDataTypeAutofill: {
538 // Toggle the checkmark.
539 // TODO(crbug.com/631486): Custom checkmark animation to be implemented.
540 ClearDataItem* clearDataItem = base::mac::ObjCCastStrict<ClearDataItem>(
541 [self.collectionViewModel itemAtIndexPath:indexPath]);
542 if (clearDataItem.accessoryType == MDCCollectionViewCellAccessoryNone) {
543 clearDataItem.accessoryType = MDCCollectionViewCellAccessoryCheckmark;
544 if (experimental_flags::IsNewClearBrowsingDataUIEnabled() &&
545 itemType == ItemTypeDataTypeCookiesSiteData) {
546 [self updateCounter:itemType
547 detailText:l10n_util::GetNSString(IDS_DEL_COOKIES_COUNTER)];
548 }
549 _browserState->GetPrefs()->SetBoolean(clearDataItem.prefName, true);
550 } else {
551 clearDataItem.accessoryType = MDCCollectionViewCellAccessoryNone;
552 _browserState->GetPrefs()->SetBoolean(clearDataItem.prefName, false);
553 if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
554 // Hide counter text.
555 [self updateCounter:itemType detailText:nil];
556 }
557 }
558 [self reconfigureCellsForItems:@[ clearDataItem ]
559 inSectionWithIdentifier:SectionIdentifierDataTypes];
560 break;
561 }
562 case ItemTypeClearBrowsingDataButton:
563 [self alertAndClearData];
564 break;
565 default:
566 break;
567 }
568 }
569
570 #pragma mark Properties
571
572 - (void)setShouldShowNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)showNotice {
573 _shouldShowNoticeAboutOtherFormsOfBrowsingHistory = showNotice;
574 UMA_HISTOGRAM_BOOLEAN(
575 "History.ClearBrowsingData.HistoryNoticeShownInFooterWhenUpdated",
576 _shouldShowNoticeAboutOtherFormsOfBrowsingHistory);
577
578 // Update the account footer if the model was already loaded.
579 CollectionViewModel* model = self.collectionViewModel;
580 if (!model) {
581 return;
582 }
583 SigninManager* signinManager =
584 ios::SigninManagerFactory::GetForBrowserState(_browserState);
585 if (!signinManager->IsAuthenticated()) {
586 return;
587 }
588
589 CollectionViewItem* footerItem = [self footerForGoogleAccountSectionItem];
590 // TODO(crbug.com/650424): Simplify with setFooter:inSection: when the bug in
591 // MDC is fixed.
592 // Remove the footer if there is one in that section.
593 if ([model hasSectionForSectionIdentifier:SectionIdentifierGoogleAccount]) {
594 if ([model hasItemForItemType:ItemTypeFooterGoogleAccount
595 sectionIdentifier:SectionIdentifierGoogleAccount]) {
596 [model removeItemWithType:ItemTypeFooterGoogleAccount
597 fromSectionWithIdentifier:SectionIdentifierGoogleAccount];
598 } else {
599 [model removeItemWithType:ItemTypeFooterGoogleAccountAndMyActivity
600 fromSectionWithIdentifier:SectionIdentifierGoogleAccount];
601 }
602 }
603 // Add the new footer.
604 [model addItem:footerItem
605 toSectionWithIdentifier:SectionIdentifierGoogleAccount];
606 [self reconfigureCellsForItems:@[ footerItem ]
607 inSectionWithIdentifier:SectionIdentifierGoogleAccount];
608
609 // Relayout the cells to adapt to the new contents height.
610 [self.collectionView.collectionViewLayout invalidateLayout];
611 }
612
613 #pragma mark Clear browsing data
614
615 - (BOOL)alertAndClearData {
616 int dataTypeMaskToRemove = 0;
617 NSArray* dataTypeItems = [self.collectionViewModel
618 itemsInSectionWithIdentifier:SectionIdentifierDataTypes];
619 for (ClearDataItem* dataTypeItem in dataTypeItems) {
620 DCHECK([dataTypeItem isKindOfClass:[ClearDataItem class]]);
621 if (dataTypeItem.accessoryType == MDCCollectionViewCellAccessoryCheckmark) {
622 dataTypeMaskToRemove |= dataTypeItem.dataTypeMask;
623 }
624 }
625 if (dataTypeMaskToRemove == 0) {
626 // Nothing to clear (no data types selected).
627 return YES;
628 }
629 base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(self);
630 UIAlertController* alertController = [UIAlertController
631 alertControllerWithTitle:nil
632 message:nil
633 preferredStyle:UIAlertControllerStyleActionSheet];
634
635 UIAlertAction* clearDataAction = [UIAlertAction
636 actionWithTitle:l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON)
637 style:UIAlertActionStyleDestructive
638 handler:^(UIAlertAction* action) {
639 [weakSelf clearDataForDataTypes:dataTypeMaskToRemove];
640 }];
641 UIAlertAction* cancelAction =
642 [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_CANCEL)
643 style:UIAlertActionStyleCancel
644 handler:nil];
645 [alertController addAction:clearDataAction];
646 [alertController addAction:cancelAction];
647 [self presentViewController:alertController animated:YES completion:nil];
648 return YES;
649 }
650
651 - (void)clearDataForDataTypes:(int)dataTypeMask {
652 DCHECK(dataTypeMask);
653 base::scoped_nsobject<ClearBrowsingDataCommand> command(
654 [[ClearBrowsingDataCommand alloc] initWithBrowserState:_browserState
655 mask:dataTypeMask
656 timePeriod:_timePeriod]);
657 [self chromeExecuteCommand:command];
658
659 if (!!(dataTypeMask && IOSChromeBrowsingDataRemover::REMOVE_HISTORY)) {
660 [self showBrowsingHistoryRemovedDialog];
661 }
662 }
663
664 - (void)showBrowsingHistoryRemovedDialog {
665 PrefService* prefs = _browserState->GetPrefs();
666 int noticeShownTimes = prefs->GetInteger(
667 browsing_data::prefs::kClearBrowsingDataHistoryNoticeShownTimes);
668
669 // When the deletion is complete, we might show an additional dialog with
670 // a notice about other forms of browsing history. This is the case if
671 const bool showDialog =
672 // 1. The dialog is relevant for the user.
673 _shouldPopupDialogAboutOtherFormsOfBrowsingHistory &&
674 // 2. The notice has been shown less than |kMaxTimesHistoryNoticeShown|.
675 noticeShownTimes < kMaxTimesHistoryNoticeShown;
676 UMA_HISTOGRAM_BOOLEAN(
677 "History.ClearBrowsingData.ShownHistoryNoticeAfterClearing", showDialog);
678 if (!showDialog) {
679 return;
680 }
681
682 // Increment the preference.
683 prefs->SetInteger(
684 browsing_data::prefs::kClearBrowsingDataHistoryNoticeShownTimes,
685 noticeShownTimes + 1);
686
687 NSString* title =
688 l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_TITLE);
689 NSString* message = l10n_util::GetNSString(
690 IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_DESCRIPTION);
691
692 UIAlertController* alertController =
693 [UIAlertController alertControllerWithTitle:title
694 message:message
695 preferredStyle:UIAlertControllerStyleAlert];
696
697 base::WeakNSObject<ClearBrowsingDataCollectionViewController> weakSelf(self);
698 UIAlertAction* openMyActivityAction = [UIAlertAction
699 actionWithTitle:
700 l10n_util::GetNSString(
701 IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_OPEN_HISTORY_BUTTON)
702 style:UIAlertActionStyleDefault
703 handler:^(UIAlertAction* action) {
704 [weakSelf openMyActivityLink];
705 }];
706
707 UIAlertAction* okAction = [UIAlertAction
708 actionWithTitle:l10n_util::GetNSString(
709 IDS_IOS_CLEAR_BROWSING_DATA_HISTORY_NOTICE_OK_BUTTON)
710 style:UIAlertActionStyleCancel
711 handler:nil];
712 [alertController addAction:openMyActivityAction];
713 [alertController addAction:okAction];
714 [self presentViewController:alertController animated:YES completion:nil];
715 }
716
717 - (void)openMyActivityLink {
718 base::scoped_nsobject<OpenUrlCommand> openMyActivityCommand(
719 [[OpenUrlCommand alloc] initWithURLFromChrome:GURL(kGoogleMyAccountURL)]);
720 openMyActivityCommand.get().tag = IDC_CLOSE_SETTINGS_AND_OPEN_URL;
721 [self chromeExecuteCommand:openMyActivityCommand];
722 }
723
724 - (NSString*)getAccessibilityIdentifierFromItemType:(NSInteger)itemType {
725 switch (itemType) {
726 case ItemTypeDataTypeBrowsingHistory:
727 return kClearBrowsingHistoryCellId;
728 case ItemTypeDataTypeCookiesSiteData:
729 return kClearCookiesCellId;
730 case ItemTypeDataTypeCache:
731 return kClearCacheCellId;
732 case ItemTypeDataTypeSavedPasswords:
733 return kClearSavedPasswordsCellId;
734 case ItemTypeDataTypeAutofill:
735 return kClearAutofillCellId;
736 default: {
737 NOTREACHED();
738 return nil;
739 }
740 }
741 }
742
743 - (void)restartCounters:(int)data_mask {
744 CollectionViewModel* model = self.collectionViewModel;
745 if (!model)
746 return;
747
748 if (data_mask &
749 (IOSChromeBrowsingDataRemover::REMOVE_HISTORY |
750 IOSChromeBrowsingDataRemover::REMOVE_GOOGLE_APP_LAUNCHER_DATA)) {
751 NSIndexPath* indexPath = [self.collectionViewModel
752 indexPathForItemType:ItemTypeDataTypeBrowsingHistory
753 sectionIdentifier:SectionIdentifierDataTypes];
754 ClearDataItem* historyItem = base::mac::ObjCCastStrict<ClearDataItem>(
755 [model itemAtIndexPath:indexPath]);
756 [historyItem restartCounter];
757 }
758
759 if (data_mask & IOSChromeBrowsingDataRemover::REMOVE_PASSWORDS) {
760 NSIndexPath* indexPath = [self.collectionViewModel
761 indexPathForItemType:ItemTypeDataTypeSavedPasswords
762 sectionIdentifier:SectionIdentifierDataTypes];
763 ClearDataItem* passwordsItem = base::mac::ObjCCastStrict<ClearDataItem>(
764 [model itemAtIndexPath:indexPath]);
765 [passwordsItem restartCounter];
766 }
767
768 if (data_mask & IOSChromeBrowsingDataRemover::REMOVE_FORM_DATA) {
769 NSIndexPath* indexPath = [self.collectionViewModel
770 indexPathForItemType:ItemTypeDataTypeAutofill
771 sectionIdentifier:SectionIdentifierDataTypes];
772 ClearDataItem* autofillItem = base::mac::ObjCCastStrict<ClearDataItem>(
773 [model itemAtIndexPath:indexPath]);
774 [autofillItem restartCounter];
775 }
776 }
777
778 - (NSString*)getCounterTextFromResult:
779 (const browsing_data::BrowsingDataCounter::Result&)result {
780 std::string prefName = result.source()->GetPrefName();
781 if (!result.Finished()) {
782 // The counter is still counting.
783 return l10n_util::GetNSString(IDS_CLEAR_BROWSING_DATA_CALCULATING);
784 }
785
786 if (prefName == browsing_data::prefs::kDeleteCache) {
787 browsing_data::BrowsingDataCounter::ResultInt cacheSizeBytes =
788 static_cast<const browsing_data::BrowsingDataCounter::FinishedResult*>(
789 &result)
790 ->Value();
791
792 // Three cases: Nonzero result for the entire cache, nonzero result for
793 // a subset of cache (i.e. a finite time interval), and almost zero (less
794 // than 1 MB). There is no exact information that the cache is empty so that
795 // falls into the almost zero case, which is displayed as less than 1 MB.
796 // Because of this, the lowest unit that can be used is MB.
797 static const int kBytesInAMegabyte = 1 << 20;
798 if (cacheSizeBytes >= kBytesInAMegabyte) {
799 base::scoped_nsobject<NSByteCountFormatter> formatter(
800 [[NSByteCountFormatter alloc] init]);
801 formatter.get().allowedUnits = NSByteCountFormatterUseAll &
802 (~NSByteCountFormatterUseBytes) &
803 (~NSByteCountFormatterUseKB);
804 formatter.get().countStyle = NSByteCountFormatterCountStyleMemory;
805 NSString* formattedSize = [formatter stringFromByteCount:cacheSizeBytes];
806 return (_timePeriod == browsing_data::ALL_TIME)
807 ? formattedSize
808 : l10n_util::GetNSStringF(
809 IDS_DEL_CACHE_COUNTER_UPPER_ESTIMATE,
810 base::SysNSStringToUTF16(formattedSize));
811 }
812 return l10n_util::GetNSString(IDS_DEL_CACHE_COUNTER_ALMOST_EMPTY);
813 }
814 return base::SysUTF16ToNSString(
815 browsing_data::GetCounterTextFromResult(&result));
816 }
817
818 #pragma mark MDCCollectionViewStylingDelegate
819
820 - (BOOL)collectionView:(UICollectionView*)collectionView
821 hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
822 NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
823 switch (type) {
824 case ItemTypeFooterSavedSiteData:
825 case ItemTypeFooterGoogleAccount:
826 case ItemTypeFooterGoogleAccountAndMyActivity:
827 case ItemTypeFooterClearSyncAndSavedSiteData:
828 return YES;
829 default:
830 return NO;
831 }
832 }
833
834 - (MDCCollectionViewCellStyle)collectionView:(UICollectionView*)collectionView
835 cellStyleForSection:(NSInteger)section {
836 NSInteger sectionIdentifier =
837 [self.collectionViewModel sectionIdentifierForSection:section];
838 switch (sectionIdentifier) {
839 case SectionIdentifierGoogleAccount:
840 case SectionIdentifierClearSyncAndSavedSiteData:
841 case SectionIdentifierSavedSiteData:
842 // Display the footer in the default style with no "card" UI and no
843 // section padding.
844 return MDCCollectionViewCellStyleDefault;
845 default:
846 return self.styler.cellStyle;
847 }
848 }
849
850 - (BOOL)collectionView:(UICollectionView*)collectionView
851 shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath {
852 NSInteger sectionIdentifier =
853 [self.collectionViewModel sectionIdentifierForSection:indexPath.section];
854 switch (sectionIdentifier) {
855 case SectionIdentifierGoogleAccount:
856 case SectionIdentifierClearSyncAndSavedSiteData:
857 case SectionIdentifierSavedSiteData:
858 // Display the Learn More footer without any background image or
859 // shadowing.
860 return YES;
861 default:
862 return NO;
863 }
864 }
865
866 - (CGFloat)collectionView:(UICollectionView*)collectionView
867 cellHeightAtIndexPath:(NSIndexPath*)indexPath {
868 NSInteger sectionIdentifier =
869 [self.collectionViewModel sectionIdentifierForSection:indexPath.section];
870 switch (sectionIdentifier) {
871 case SectionIdentifierGoogleAccount:
872 case SectionIdentifierClearSyncAndSavedSiteData:
873 case SectionIdentifierSavedSiteData: {
874 CollectionViewItem* item =
875 [self.collectionViewModel itemAtIndexPath:indexPath];
876 return [MDCCollectionViewCell
877 cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
878 forItem:item];
879 }
880 case SectionIdentifierDataTypes: {
881 ClearDataItem* clearDataItem = base::mac::ObjCCastStrict<ClearDataItem>(
882 [self.collectionViewModel itemAtIndexPath:indexPath]);
883 return (clearDataItem.detailText.length > 0)
884 ? MDCCellDefaultTwoLineHeight
885 : MDCCellDefaultOneLineHeight;
886 }
887 default:
888 return MDCCellDefaultOneLineHeight;
889 }
890 }
891
892 #pragma mark TimeRangeSelectorCollectionViewControllerDelegate
893
894 - (void)timeRangeSelectorViewController:
895 (TimeRangeSelectorCollectionViewController*)collectionViewController
896 didSelectTimePeriod:(browsing_data::TimePeriod)timePeriod {
897 _timePeriod = timePeriod;
898 }
899
900 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698