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

Side by Side Diff: ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm

Issue 2587023002: Upstream Chrome on iOS source code [8/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/save_passwords_collection_view_controlle r.h"
6
7 #include <memory>
8
9 #include "base/ios/ios_util.h"
10 #include "base/ios/weak_nsobject.h"
11 #include "base/logging.h"
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/objc_property_releaser.h"
14 #include "base/mac/scoped_nsobject.h"
15 #include "base/memory/scoped_vector.h"
16 #include "base/numerics/safe_conversions.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "components/autofill/core/common/password_form.h"
20 #include "components/browser_sync/profile_sync_service.h"
21 #include "components/google/core/browser/google_util.h"
22 #include "components/keyed_service/core/service_access_type.h"
23 #include "components/password_manager/core/browser/affiliation_utils.h"
24 #include "components/password_manager/core/browser/password_bubble_experiment.h"
25 #include "components/password_manager/core/browser/password_manager_constants.h"
26 #include "components/password_manager/core/browser/password_store.h"
27 #include "components/password_manager/core/browser/password_store_consumer.h"
28 #include "components/password_manager/core/common/password_manager_pref_names.h"
29 #include "components/prefs/pref_member.h"
30 #include "components/prefs/pref_service.h"
31 #include "components/strings/grit/components_strings.h"
32 #include "components/url_formatter/url_formatter.h"
33 #include "ios/chrome/browser/application_context.h"
34 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
35 #include "ios/chrome/browser/experimental_flags.h"
36 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
37 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
38 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrom e.h"
39 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item .h"
40 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
41 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item .h"
42 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h "
43 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
44 #import "ios/chrome/browser/ui/settings/password_details_collection_view_control ler.h"
45 #import "ios/chrome/browser/ui/settings/reauthentication_module.h"
46 #import "ios/chrome/browser/ui/settings/settings_utils.h"
47 #import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h"
48 #include "ios/chrome/grit/ios_strings.h"
49 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h"
50 #include "ui/base/l10n/l10n_util_mac.h"
51 #include "url/gurl.h"
52
53 namespace {
54
55 typedef NS_ENUM(NSInteger, SectionIdentifier) {
56 SectionIdentifierMessage = kSectionIdentifierEnumZero,
57 SectionIdentifierSavePasswordsSwitch,
58 SectionIdentifierSavedPasswords,
59 SectionIdentifierBlacklist,
60 };
61
62 typedef NS_ENUM(NSInteger, ItemType) {
63 ItemTypeManageAccount = kItemTypeEnumZero,
64 ItemTypeHeader,
65 ItemTypeSavePasswordsSwitch,
66 ItemTypeSavedPassword, // This is a repeated item type.
67 ItemTypeBlacklisted, // This is a repeated item type.
68 };
69
70 // TODO(crbug.com/669538): This function should be removed after original
71 // version of GetHumanReadableOrigin will be moved to affiliation_utils.
72 std::string GetHumanReadableOriginCopy(
73 const autofill::PasswordForm& password_form) {
74 password_manager::FacetURI facet_uri =
75 password_manager::FacetURI::FromPotentiallyInvalidSpec(
76 password_form.signon_realm);
77 if (facet_uri.IsValidAndroidFacetURI())
78 return facet_uri.scheme() + "://" + facet_uri.android_package_name();
79 return base::UTF16ToUTF8(url_formatter::FormatUrl(password_form.origin));
80 }
81
82 } // namespace
83
84 @interface SavePasswordsCollectionViewController (UsedBySavePasswordsConsumer)
85 // Callback called when the async request launched from
86 // |getLoginsFromPasswordStore| finishes.
87 - (void)onGetPasswordStoreResults:
88 (const std::vector<std::unique_ptr<autofill::PasswordForm>>&)result;
89 @end
90
91 namespace password_manager {
92 // A bridge C++ class passing notification about finished password store
93 // requests to owning Obj-C class SavePasswordsCollectionViewController.
94 class SavePasswordsConsumer : public PasswordStoreConsumer {
95 public:
96 explicit SavePasswordsConsumer(
97 SavePasswordsCollectionViewController* delegate);
98 ~SavePasswordsConsumer() override;
99 void OnGetPasswordStoreResults(
100 std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
101
102 private:
103 __unsafe_unretained SavePasswordsCollectionViewController* delegate_; // weak
104 DISALLOW_COPY_AND_ASSIGN(SavePasswordsConsumer);
105 };
106
107 SavePasswordsConsumer::SavePasswordsConsumer(
108 SavePasswordsCollectionViewController* delegate)
109 : delegate_(delegate) {}
110
111 SavePasswordsConsumer::~SavePasswordsConsumer() {}
112
113 void SavePasswordsConsumer::OnGetPasswordStoreResults(
114 std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
115 if (!results.empty())
116 [delegate_ onGetPasswordStoreResults:results];
117 }
118 } // namespace password_manager
119
120 // Use the type of the items to convey the Saved/Blacklisted status.
121 @interface SavedFormContentItem : CollectionViewTextItem
122 @end
123 @implementation SavedFormContentItem
124 @end
125 @interface BlacklistedFormContentItem : CollectionViewTextItem
126 @end
127 @implementation BlacklistedFormContentItem
128 @end
129
130 @interface SavePasswordsCollectionViewController ()<
131 BooleanObserver,
132 PasswordDetailsCollectionViewControllerDelegate,
133 SuccessfulReauthTimeAccessor> {
134 // The observable boolean that binds to the password manager setting state.
135 // Saved passwords are only on if the password manager is enabled.
136 base::scoped_nsobject<PrefBackedBoolean> passwordManagerEnabled_;
137 // The item related to the switch for the password manager setting.
138 base::scoped_nsobject<CollectionViewSwitchItem> savePasswordsItem_;
139 // The interface for getting and manipulating a user's saved passwords.
140 scoped_refptr<password_manager::PasswordStore> passwordStore_;
141 // A helper object for passing data about saved passwords from a finished
142 // password store request to the SavePasswordsCollectionViewController.
143 std::unique_ptr<password_manager::SavePasswordsConsumer>
144 savedPasswordsConsumer_;
145 // A helper object for passing data about blacklisted sites from a finished
146 // password store request to the SavePasswordsCollectionViewController.
147 std::unique_ptr<password_manager::SavePasswordsConsumer>
148 blacklistPasswordsConsumer_;
149 // The list of the user's saved passwords.
150 ScopedVector<autofill::PasswordForm> savedForms_;
151 // The list of the user's blacklisted sites.
152 ScopedVector<autofill::PasswordForm> blacklistedForms_;
153 // Deletion of password being asynchronous, and the method taking a reference
154 // to the PasswordForm, the PasswordForm must outlive the calls to
155 // RemoveLogin. This vector will ensure this.
156 ScopedVector<autofill::PasswordForm> deletedForms_;
157 // The current Chrome browser state.
158 ios::ChromeBrowserState* browserState_;
159 // Object storing the time of the previous successful re-authentication.
160 // This is meant to be used by the |ReauthenticationModule| for keeping
161 // re-authentications valid for a certain time interval within the scope
162 // of the Save Passwords Settings.
163 base::scoped_nsobject<NSDate> successfulReauthTime_;
164 // Module containing the reauthentication mechanism for viewing and copying
165 // passwords.
166 base::scoped_nsobject<ReauthenticationModule> reauthenticationModule_;
167
168 base::mac::ObjCPropertyReleaser
169 propertyReleaser_SavePasswordsCollectionViewController_;
170 }
171 // Kick off async request to get logins from password store.
172 - (void)getLoginsFromPasswordStore;
173 @end
174
175 @implementation SavePasswordsCollectionViewController
176
177 #pragma mark - Initialization
178
179 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
180 DCHECK(browserState);
181 self = [super initWithStyle:CollectionViewControllerStyleAppBar];
182 if (self) {
183 browserState_ = browserState;
184 reauthenticationModule_.reset([[ReauthenticationModule alloc]
185 initWithSuccessfulReauthTimeAccessor:self]);
186 int titleId = IDS_IOS_SAVE_PASSWORDS;
187 syncer::SyncService* syncService =
188 IOSChromeProfileSyncServiceFactory::GetForBrowserState(browserState_);
189 if (password_bubble_experiment::IsSmartLockBrandingEnabled(syncService)) {
190 titleId = IDS_IOS_SAVE_PASSWORDS_SMART_LOCK;
191 }
192 self.title = l10n_util::GetNSString(titleId);
193 self.shouldHideDoneButton = YES;
194 passwordStore_ = IOSChromePasswordStoreFactory::GetForBrowserState(
195 browserState_, ServiceAccessType::EXPLICIT_ACCESS);
196 DCHECK(passwordStore_);
197 passwordManagerEnabled_.reset([[PrefBackedBoolean alloc]
198 initWithPrefService:browserState_->GetPrefs()
199 prefName:password_manager::prefs::
200 kPasswordManagerSavingEnabled]);
201 [passwordManagerEnabled_ setObserver:self];
202 [self getLoginsFromPasswordStore];
203 [self updateEditButton];
204 [self loadModel];
205
206 propertyReleaser_SavePasswordsCollectionViewController_.Init(
207 self, [SavePasswordsCollectionViewController class]);
208 }
209 return self;
210 }
211
212 - (void)dealloc {
213 [passwordManagerEnabled_ setObserver:nil];
214 [super dealloc];
215 }
216
217 #pragma mark - SettingsRootCollectionViewController
218
219 - (void)loadModel {
220 [super loadModel];
221 CollectionViewModel* model = self.collectionViewModel;
222
223 // Manage account message.
224 CollectionViewItem* manageAccountLinkItem = [self manageAccountLinkItem];
225 if (manageAccountLinkItem) {
226 [model addSectionWithIdentifier:SectionIdentifierMessage];
227 [model addItem:manageAccountLinkItem
228 toSectionWithIdentifier:SectionIdentifierMessage];
229 }
230
231 // Save passwords switch.
232 [model addSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
233 savePasswordsItem_.reset([[self savePasswordsItem] retain]);
234 [model addItem:savePasswordsItem_
235 toSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
236
237 // Saved passwords.
238 if ([passwordManagerEnabled_ value]) {
239 if (!savedForms_.empty()) {
240 [model addSectionWithIdentifier:SectionIdentifierSavedPasswords];
241 CollectionViewTextItem* headerItem = [[[CollectionViewTextItem alloc]
242 initWithType:ItemTypeHeader] autorelease];
243 headerItem.text =
244 l10n_util::GetNSString(IDS_PASSWORD_MANAGER_SHOW_PASSWORDS_TAB_TITLE);
245 [model setHeader:headerItem
246 forSectionWithIdentifier:SectionIdentifierSavedPasswords];
247 for (size_t i = 0; i < savedForms_.size(); ++i) {
248 autofill::PasswordForm* form = savedForms_[i];
249 [model addItem:[self savedFormItemWithForm:form]
250 toSectionWithIdentifier:SectionIdentifierSavedPasswords];
251 }
252 }
253 if (!blacklistedForms_.empty()) {
254 [model addSectionWithIdentifier:SectionIdentifierBlacklist];
255 CollectionViewTextItem* headerItem = [[[CollectionViewTextItem alloc]
256 initWithType:ItemTypeHeader] autorelease];
257 headerItem.text =
258 l10n_util::GetNSString(IDS_PASSWORD_MANAGER_EXCEPTIONS_TAB_TITLE);
259 [model setHeader:headerItem
260 forSectionWithIdentifier:SectionIdentifierBlacklist];
261 for (size_t i = 0; i < blacklistedForms_.size(); ++i) {
262 autofill::PasswordForm* form = blacklistedForms_[i];
263 [model addItem:[self blacklistedFormItemWithForm:form]
264 toSectionWithIdentifier:SectionIdentifierBlacklist];
265 }
266 }
267 }
268 }
269
270 #pragma mark - Items
271
272 - (CollectionViewItem*)manageAccountLinkItem {
273 CollectionViewFooterItem* footerItem = [[[CollectionViewFooterItem alloc]
274 initWithType:ItemTypeManageAccount] autorelease];
275 footerItem.text =
276 l10n_util::GetNSString(IDS_IOS_SAVE_PASSWORDS_MANAGE_ACCOUNT);
277 footerItem.linkURL = google_util::AppendGoogleLocaleParam(
278 GURL(password_manager::kPasswordManagerAccountDashboardURL),
279 GetApplicationContext()->GetApplicationLocale());
280 footerItem.linkDelegate = self;
281 return footerItem;
282 }
283
284 - (CollectionViewSwitchItem*)savePasswordsItem {
285 CollectionViewSwitchItem* savePasswordsItem =
286 [[[CollectionViewSwitchItem alloc]
287 initWithType:ItemTypeSavePasswordsSwitch] autorelease];
288 savePasswordsItem.text = l10n_util::GetNSString(IDS_IOS_SAVE_PASSWORDS);
289 savePasswordsItem.on = [passwordManagerEnabled_ value];
290 return savePasswordsItem;
291 }
292
293 - (SavedFormContentItem*)savedFormItemWithForm:(autofill::PasswordForm*)form {
294 SavedFormContentItem* passwordItem = [[[SavedFormContentItem alloc]
295 initWithType:ItemTypeSavedPassword] autorelease];
296 passwordItem.text =
297 base::SysUTF8ToNSString(GetHumanReadableOriginCopy(*form));
298 passwordItem.detailText = base::SysUTF16ToNSString(form->username_value);
299 if (experimental_flags::IsViewCopyPasswordsEnabled()) {
300 passwordItem.accessibilityTraits |= UIAccessibilityTraitButton;
301 passwordItem.accessoryType =
302 MDCCollectionViewCellAccessoryDisclosureIndicator;
303 }
304 return passwordItem;
305 }
306
307 - (BlacklistedFormContentItem*)blacklistedFormItemWithForm:
308 (autofill::PasswordForm*)form {
309 BlacklistedFormContentItem* passwordItem =
310 [[[BlacklistedFormContentItem alloc] initWithType:ItemTypeBlacklisted]
311 autorelease];
312 passwordItem.text =
313 base::SysUTF8ToNSString(GetHumanReadableOriginCopy(*form));
314 return passwordItem;
315 }
316
317 #pragma mark - MDCCollectionViewEditingDelegate
318
319 - (BOOL)collectionViewAllowsEditing:(UICollectionView*)collectionView {
320 return YES;
321 }
322
323 #pragma mark - MDCCollectionViewStylingDelegate
324
325 - (MDCCollectionViewCellStyle)collectionView:(UICollectionView*)collectionView
326 cellStyleForSection:(NSInteger)section {
327 NSInteger sectionIdentifier =
328 [self.collectionViewModel sectionIdentifierForSection:section];
329 switch (sectionIdentifier) {
330 case SectionIdentifierMessage:
331 // Display the message in the default style with no "card" UI and no
332 // section padding.
333 return MDCCollectionViewCellStyleDefault;
334 default:
335 return self.styler.cellStyle;
336 }
337 }
338
339 - (BOOL)collectionView:(UICollectionView*)collectionView
340 shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath {
341 NSInteger sectionIdentifier =
342 [self.collectionViewModel sectionIdentifierForSection:indexPath.section];
343 switch (sectionIdentifier) {
344 case SectionIdentifierMessage:
345 // Display the message without any background image or shadowing.
346 return YES;
347 default:
348 return NO;
349 }
350 }
351
352 - (CGFloat)collectionView:(UICollectionView*)collectionView
353 cellHeightAtIndexPath:(NSIndexPath*)indexPath {
354 CollectionViewItem* item =
355 [self.collectionViewModel itemAtIndexPath:indexPath];
356 switch (item.type) {
357 case ItemTypeManageAccount:
358 return [MDCCollectionViewCell
359 cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
360 forItem:item];
361 case ItemTypeSavedPassword:
362 return MDCCellDefaultTwoLineHeight;
363 default:
364 return MDCCellDefaultOneLineHeight;
365 }
366 }
367
368 - (BOOL)collectionView:(UICollectionView*)collectionView
369 hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
370 NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath];
371 switch (type) {
372 case ItemTypeSavePasswordsSwitch:
373 return YES;
374 default:
375 return NO;
376 }
377 }
378
379 #pragma mark - UICollectionViewDataSource
380
381 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
382 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
383 UICollectionViewCell* cell =
384 [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
385
386 if ([self.collectionViewModel itemTypeForIndexPath:indexPath] ==
387 ItemTypeSavePasswordsSwitch) {
388 CollectionViewSwitchCell* switchCell =
389 base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell);
390 [switchCell.switchView addTarget:self
391 action:@selector(savePasswordsSwitchChanged:)
392 forControlEvents:UIControlEventValueChanged];
393 }
394 return cell;
395 }
396
397 - (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView
398 viewForSupplementaryElementOfKind:(NSString*)kind
399 atIndexPath:(NSIndexPath*)indexPath {
400 UICollectionReusableView* view = [super collectionView:collectionView
401 viewForSupplementaryElementOfKind:kind
402 atIndexPath:indexPath];
403 MDCCollectionViewTextCell* textCell =
404 base::mac::ObjCCast<MDCCollectionViewTextCell>(view);
405 if (textCell) {
406 textCell.textLabel.textColor = [[MDCPalette greyPalette] tint500];
407 }
408 return view;
409 };
410
411 #pragma mark - BooleanObserver
412
413 - (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean {
414 DCHECK_EQ(observableBoolean, passwordManagerEnabled_.get());
415
416 // Update the item.
417 savePasswordsItem_.get().on = [passwordManagerEnabled_ value];
418
419 // Update the cell.
420 [self reconfigureCellsForItems:@[ savePasswordsItem_ ]
421 inSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
422
423 // Update the rest of the UI.
424 [self.editor setEditing:NO];
425 [self updateEditButton];
426 [self reloadData];
427 }
428
429 #pragma mark - Actions
430
431 - (void)savePasswordsSwitchChanged:(UISwitch*)switchView {
432 // Update the setting.
433 [passwordManagerEnabled_ setValue:switchView.on];
434
435 // Update the item.
436 savePasswordsItem_.get().on = [passwordManagerEnabled_ value];
437
438 // Update the rest of the UI.
439 [self.editor setEditing:NO];
440 [self updateEditButton];
441 [self reloadData];
442 }
443
444 #pragma mark - Private methods
445
446 - (void)getLoginsFromPasswordStore {
447 savedPasswordsConsumer_.reset(
448 new password_manager::SavePasswordsConsumer(self));
449 passwordStore_->GetAutofillableLogins(savedPasswordsConsumer_.get());
450 blacklistPasswordsConsumer_.reset(
451 new password_manager::SavePasswordsConsumer(self));
452 passwordStore_->GetBlacklistLogins(blacklistPasswordsConsumer_.get());
453 }
454
455 - (void)onGetPasswordStoreResults:
456 (const std::vector<std::unique_ptr<autofill::PasswordForm>>&)result {
457 for (auto it = result.begin(); it != result.end(); ++it) {
458 // PasswordForm is needed when user wants to delete the site/password.
459 autofill::PasswordForm* form = new autofill::PasswordForm(**it);
460 if (form->blacklisted_by_user)
461 blacklistedForms_.push_back(form);
462 else
463 savedForms_.push_back(form);
464 }
465
466 [self updateEditButton];
467 [self reloadData];
468 }
469
470 - (BOOL)shouldShowEditButton {
471 return [passwordManagerEnabled_ value];
472 }
473
474 - (BOOL)editButtonEnabled {
475 DCHECK([self shouldShowEditButton]);
476 return !savedForms_.empty() || !blacklistedForms_.empty();
477 }
478
479 #pragma mark UICollectionViewDelegate
480
481 - (void)collectionView:(UICollectionView*)collectionView
482 didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
483 [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
484
485 // Actions should only take effect when not in editing mode.
486 if (self.editing) {
487 return;
488 }
489
490 CollectionViewModel* model = self.collectionViewModel;
491 if ([model itemTypeForIndexPath:indexPath] == ItemTypeSavedPassword) {
492 DCHECK_EQ([model sectionIdentifierForSection:indexPath.section],
493 SectionIdentifierSavedPasswords);
494 if (experimental_flags::IsViewCopyPasswordsEnabled()) {
495 DCHECK_LT(base::checked_cast<size_t>(indexPath.item), savedForms_.size());
496 autofill::PasswordForm* form = savedForms_[indexPath.item];
497 NSString* username = base::SysUTF16ToNSString(form->username_value);
498 NSString* password = base::SysUTF16ToNSString(form->password_value);
499 NSString* origin =
500 base::SysUTF8ToNSString(GetHumanReadableOriginCopy(*form));
501 base::scoped_nsobject<UIViewController> controller(
502 [[PasswordDetailsCollectionViewController alloc]
503 initWithPasswordForm:*form
504 delegate:self
505 reauthenticationModule:reauthenticationModule_
506 username:username
507 password:password
508 origin:origin]);
509 [self.navigationController pushViewController:controller animated:YES];
510 }
511 }
512 }
513
514 #pragma mark MDCCollectionViewEditingDelegate
515
516 - (BOOL)collectionView:(UICollectionView*)collectionView
517 canEditItemAtIndexPath:(NSIndexPath*)indexPath {
518 // Only password cells are editable.
519 CollectionViewItem* item =
520 [self.collectionViewModel itemAtIndexPath:indexPath];
521 return [item isKindOfClass:[SavedFormContentItem class]] ||
522 [item isKindOfClass:[BlacklistedFormContentItem class]];
523 }
524
525 - (void)collectionView:(UICollectionView*)collectionView
526 willDeleteItemsAtIndexPaths:(NSArray*)indexPaths {
527 // Ensure indexPaths are sorted to maintain delete logic, and keep track of
528 // number of items deleted to adjust index for accessing elements in the
529 // forms vectors.
530 NSArray* sortedIndexPaths =
531 [indexPaths sortedArrayUsingSelector:@selector(compare:)];
532 int passwordsDeleted = 0;
533 int blacklistedDeleted = 0;
534 for (NSIndexPath* indexPath in sortedIndexPaths) {
535 // Only form items are editable.
536 CollectionViewTextItem* item =
537 base::mac::ObjCCastStrict<CollectionViewTextItem>(
538 [self.collectionViewModel itemAtIndexPath:indexPath]);
539 BOOL blacklisted = [item isKindOfClass:[BlacklistedFormContentItem class]];
540 unsigned int formIndex = (unsigned int)indexPath.item;
541 // Adjust index to account for deleted items.
542 formIndex -= blacklisted ? blacklistedDeleted : passwordsDeleted;
543 ScopedVector<autofill::PasswordForm>& forms =
544 blacklisted ? blacklistedForms_ : savedForms_;
545 DCHECK_LT(formIndex, forms.size());
546 auto formIterator = forms.begin() + formIndex;
547 passwordStore_->RemoveLogin(**formIterator);
548 deletedForms_.push_back(*formIterator);
549 forms.weak_erase(formIterator);
550 if (blacklisted) {
551 ++blacklistedDeleted;
552 } else {
553 ++passwordsDeleted;
554 }
555 }
556
557 // Must call super at the end of the child implementation.
558 [super collectionView:collectionView willDeleteItemsAtIndexPaths:indexPaths];
559 }
560
561 - (void)collectionView:(UICollectionView*)collectionView
562 didDeleteItemsAtIndexPaths:(NSArray*)indexPaths {
563 // Remove empty sections.
564 // TODO(crbug.com/593786): Move this logic in CollectionViewController.
565 NSMutableOrderedSet* sectionsToRemove = [NSMutableOrderedSet orderedSet];
566 // Sort and enumerate in reverse order to delete the items from the collection
567 // view model.
568 NSArray* sortedIndexPaths =
569 [indexPaths sortedArrayUsingSelector:@selector(compare:)];
570 for (NSIndexPath* indexPath in [sortedIndexPaths reverseObjectEnumerator]) {
571 if ([collectionView numberOfItemsInSection:indexPath.section] == 0) {
572 [sectionsToRemove addObject:@(indexPath.section)];
573 }
574 }
575 base::WeakNSObject<SavePasswordsCollectionViewController> weakSelf(self);
576 [self.collectionView performBatchUpdates:^{
577 base::scoped_nsobject<SavePasswordsCollectionViewController> strongSelf(
578 [weakSelf retain]);
579 if (!strongSelf)
580 return;
581 for (NSNumber* sectionNumber in sectionsToRemove) {
582 NSInteger section = [sectionNumber integerValue];
583 NSInteger sectionIdentifier = [[strongSelf collectionViewModel]
584 sectionIdentifierForSection:section];
585 [[strongSelf collectionViewModel]
586 removeSectionWithIdentifier:sectionIdentifier];
587 [[strongSelf collectionView]
588 deleteSections:[NSIndexSet indexSetWithIndex:section]];
589 }
590 }
591 completion:^(BOOL finished) {
592 base::scoped_nsobject<SavePasswordsCollectionViewController> strongSelf(
593 [weakSelf retain]);
594 if (!strongSelf)
595 return;
596 if (![strongSelf editButtonEnabled]) {
597 [strongSelf setEditing:NO];
598 }
599 [strongSelf updateEditButton];
600 }];
601 }
602
603 #pragma mark PasswordDetailsCollectionViewControllerDelegate
604
605 - (void)deletePassword:(const autofill::PasswordForm&)form {
606 passwordStore_->RemoveLogin(form);
607 for (auto it = savedForms_.begin(); it != savedForms_.end(); ++it) {
608 if (**it == form) {
609 savedForms_.weak_erase(it);
610 return;
611 }
612 }
613 [self.navigationController popViewControllerAnimated:YES];
614 }
615
616 #pragma mark SuccessfulReauthTimeAccessor
617
618 - (void)updateSuccessfulReauthTime {
619 successfulReauthTime_.reset([[NSDate alloc] init]);
620 }
621
622 - (NSDate*)lastSuccessfulReauthTime {
623 return successfulReauthTime_.get();
624 }
625
626 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698