Commit b6a95ca7 authored by Gauthier Ambard's avatar Gauthier Ambard Committed by Commit Bot

[iOS] Move AutofilProfileCollectionVC to TableVC

This Moves the AutofilProfileCollectionViewController to use a
UITableView instead of an MDCCollectionVC.
It also reset _deletionInProgress to NO after doing an update, because
it seems that it wasn't reset before (removing one entry ignored all
model updates).

Bug: 894791
Change-Id: I96b61cb71d25aae1d6974a7ae2612659803b6404
Reviewed-on: https://chromium-review.googlesource.com/c/1350956Reviewed-by: default avatarSergio Collazos <sczs@chromium.org>
Reviewed-by: default avatarMoe Ahmadi <mahmadi@chromium.org>
Commit-Queue: Gauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#613054}
parent d0105907
......@@ -293,6 +293,7 @@ source_set("eg_tests") {
"//ios/chrome/browser/ui/autofill:bridges",
"//ios/chrome/browser/ui/payments/cells",
"//ios/chrome/browser/ui/popup_menu:constants",
"//ios/chrome/browser/ui/settings",
"//ios/chrome/test/app:test_support",
"//ios/chrome/test/earl_grey:test_support",
"//ios/testing/earl_grey:earl_grey_support",
......
......@@ -11,6 +11,7 @@
#include "components/strings/grit/components_strings.h"
#include "ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.h"
#import "ios/chrome/browser/ui/payments/payment_request_egtest_base.h"
#import "ios/chrome/browser/ui/settings/autofill_profile_table_view_controller.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
......@@ -154,7 +155,7 @@ const char kNoShippingPage[] =
// Confirm that the Autofill Settings UI is showing.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
@"kAutofillCollectionViewId")]
kAutofillProfileTableViewID)]
assertWithMatcher:grey_notNil()];
[self waitForWebViewContainingTexts:{"AbortError", "Request cancelled"}];
......
......@@ -18,10 +18,10 @@ source_set("settings") {
"autofill_edit_table_view_controller+protected.h",
"autofill_edit_table_view_controller.h",
"autofill_edit_table_view_controller.mm",
"autofill_profile_collection_view_controller.h",
"autofill_profile_collection_view_controller.mm",
"autofill_profile_edit_table_view_controller.h",
"autofill_profile_edit_table_view_controller.mm",
"autofill_profile_table_view_controller.h",
"autofill_profile_table_view_controller.mm",
"bandwidth_management_table_view_controller.h",
"bandwidth_management_table_view_controller.mm",
"bar_button_activity_indicator.h",
......@@ -272,8 +272,8 @@ source_set("unit_tests") {
sources = [
"about_chrome_table_view_controller_unittest.mm",
"autofill_credit_card_collection_view_controller_unittest.mm",
"autofill_profile_collection_view_controller_unittest.mm",
"autofill_profile_edit_table_view_controller_unittest.mm",
"autofill_profile_table_view_controller_unittest.mm",
"bandwidth_management_table_view_controller_unittest.mm",
"block_popups_table_view_controller_unittest.mm",
"clear_browsing_data_collection_view_controller_unittest.mm",
......
......@@ -265,9 +265,8 @@ NSString* GetTextFieldForID(int categoryId) {
performAction:grey_tap()];
// Check the Autofill profile switch is disabled.
[[EarlGrey
selectElementWithMatcher:chrome_test_util::LegacySettingsSwitchCell(
@"addressItem_switch", YES, NO)]
[[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
@"addressItem_switch", YES, NO)]
assertWithMatcher:grey_notNil()];
[self exitSettingsMenu];
......@@ -280,20 +279,18 @@ NSString* GetTextFieldForID(int categoryId) {
[self openAutofillProfilesSettings];
// Toggle the Autofill profiles switch off.
[[EarlGrey
selectElementWithMatcher:chrome_test_util::LegacySettingsSwitchCell(
@"addressItem_switch", YES, YES)]
performAction:chrome_test_util::TurnLegacySettingsSwitchOn(NO)];
[[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
@"addressItem_switch", YES, YES)]
performAction:chrome_test_util::TurnSettingsSwitchOn(NO)];
// Expect Autofill profiles to remain visible.
[[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(kProfileLabel)]
assertWithMatcher:grey_notNil()];
// Toggle the Autofill profiles switch back on.
[[EarlGrey
selectElementWithMatcher:chrome_test_util::LegacySettingsSwitchCell(
@"addressItem_switch", NO, YES)]
performAction:chrome_test_util::TurnLegacySettingsSwitchOn(YES)];
[[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
@"addressItem_switch", NO, YES)]
performAction:chrome_test_util::TurnSettingsSwitchOn(YES)];
// Expect Autofill profiles to remain visible.
[[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(kProfileLabel)]
......
......@@ -2,26 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_PROFILE_COLLECTION_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_PROFILE_COLLECTION_VIEW_CONTROLLER_H_
#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_PROFILE_TABLE_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_PROFILE_TABLE_VIEW_CONTROLLER_H_
#import "ios/chrome/browser/ui/settings/settings_root_collection_view_controller.h"
#import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h"
namespace ios {
class ChromeBrowserState;
} // namespace ios
// The collection view for the Autofill settings.
@interface AutofillProfileCollectionViewController
: SettingsRootCollectionViewController
extern NSString* const kAutofillProfileTableViewID;
// The TableView for the Autofill settings.
@interface AutofillProfileTableViewController : SettingsRootTableViewController
// The designated initializer. |browserState| must not be nil.
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithLayout:(UICollectionViewLayout*)layout
style:(CollectionViewControllerStyle)style
- (instancetype)initWithTableViewStyle:(UITableViewStyle)style
appBarStyle:
(ChromeTableViewControllerStyle)appBarStyle
NS_UNAVAILABLE;
@end
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_PROFILE_COLLECTION_VIEW_CONTROLLER_H_
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_PROFILE_TABLE_VIEW_CONTROLLER_H_
......@@ -2,7 +2,7 @@
// 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/autofill_profile_collection_view_controller.h"
#import "ios/chrome/browser/ui/settings/autofill_profile_table_view_controller.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
......@@ -15,45 +15,44 @@
#include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
#include "ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.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/settings/autofill_profile_edit_table_view_controller.h"
#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_autofill_data_item.h"
#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_switch_item.h"
#import "ios/chrome/browser/ui/settings/cells/autofill_data_item.h"
#import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h"
#import "ios/chrome/browser/ui/settings/cells/settings_text_item.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_detail_text_item.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h"
#import "ios/chrome/browser/ui/table_view/table_view_model.h"
#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
#include "ios/chrome/grit/ios_strings.h"
#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
#include "ui/base/l10n/l10n_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
NSString* const kAutofillProfileTableViewID = @"kAutofillProfileTableViewID";
namespace {
typedef NS_ENUM(NSInteger, SectionIdentifier) {
SectionIdentifierSwitches = kSectionIdentifierEnumZero,
SectionIdentifierSubtitle,
SectionIdentifierProfiles,
};
typedef NS_ENUM(NSInteger, ItemType) {
ItemTypeAutofillAddressSwitch = kItemTypeEnumZero,
ItemTypeAutofillAddressSwitchSubtitle,
ItemTypeAddress,
ItemTypeHeader,
ItemTypeFooter,
};
} // namespace
#pragma mark - AutofillProfileCollectionViewController
#pragma mark - AutofillProfileTableViewController
@interface AutofillProfileCollectionViewController ()<
PersonalDataManagerObserver> {
@interface AutofillProfileTableViewController () <PersonalDataManagerObserver> {
autofill::PersonalDataManager* _personalDataManager;
ios::ChromeBrowserState* _browserState;
......@@ -72,15 +71,14 @@ typedef NS_ENUM(NSInteger, ItemType) {
@end
@implementation AutofillProfileCollectionViewController
@implementation AutofillProfileTableViewController
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
DCHECK(browserState);
UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init];
self =
[super initWithLayout:layout style:CollectionViewControllerStyleAppBar];
[super initWithTableViewStyle:UITableViewStyleGrouped
appBarStyle:ChromeTableViewControllerStyleWithAppBar];
if (self) {
self.collectionViewAccessibilityIdentifier = @"kAutofillCollectionViewId";
self.title = l10n_util::GetNSString(IDS_AUTOFILL_ADDRESSES_SETTINGS_TITLE);
self.shouldHideDoneButton = YES;
_browserState = browserState;
......@@ -88,11 +86,6 @@ typedef NS_ENUM(NSInteger, ItemType) {
autofill::PersonalDataManagerFactory::GetForBrowserState(_browserState);
_observer.reset(new autofill::PersonalDataManagerObserverBridge(self));
_personalDataManager->AddObserver(_observer.get());
// TODO(crbug.com/764578): -updateEditButton and -loadModel should not be
// called from initializer.
[self updateEditButton];
[self loadModel];
}
return self;
}
......@@ -101,19 +94,25 @@ typedef NS_ENUM(NSInteger, ItemType) {
_personalDataManager->RemoveObserver(_observer.get());
}
#pragma mark - CollectionViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.allowsMultipleSelectionDuringEditing = YES;
self.tableView.accessibilityIdentifier = kAutofillProfileTableViewID;
self.tableView.estimatedSectionFooterHeight =
kTableViewHeaderFooterViewHeight;
[self updateEditButton];
[self loadModel];
}
- (void)loadModel {
[super loadModel];
CollectionViewModel* model = self.collectionViewModel;
TableViewModel* model = self.tableViewModel;
[model addSectionWithIdentifier:SectionIdentifierSwitches];
[model addItem:[self addressSwitchItem]
toSectionWithIdentifier:SectionIdentifierSwitches];
[model addSectionWithIdentifier:SectionIdentifierSubtitle];
[model addItem:[self addressSwitchSubtitleItem]
toSectionWithIdentifier:SectionIdentifierSubtitle];
[model setFooter:[self addressSwitchFooter]
forSectionWithIdentifier:SectionIdentifierSwitches];
[self populateProfileSection];
}
......@@ -122,7 +121,7 @@ typedef NS_ENUM(NSInteger, ItemType) {
// Populates profile section using personalDataManager.
- (void)populateProfileSection {
CollectionViewModel* model = self.collectionViewModel;
TableViewModel* model = self.tableViewModel;
const std::vector<autofill::AutofillProfile*> autofillProfiles =
_personalDataManager->GetProfiles();
if (!autofillProfiles.empty()) {
......@@ -137,9 +136,9 @@ typedef NS_ENUM(NSInteger, ItemType) {
}
}
- (CollectionViewItem*)addressSwitchItem {
LegacySettingsSwitchItem* switchItem = [[LegacySettingsSwitchItem alloc]
initWithType:ItemTypeAutofillAddressSwitch];
- (TableViewItem*)addressSwitchItem {
SettingsSwitchItem* switchItem =
[[SettingsSwitchItem alloc] initWithType:ItemTypeAutofillAddressSwitch];
switchItem.text =
l10n_util::GetNSString(IDS_AUTOFILL_ENABLE_PROFILES_TOGGLE_LABEL);
switchItem.on = [self isAutofillProfileEnabled];
......@@ -147,31 +146,22 @@ typedef NS_ENUM(NSInteger, ItemType) {
return switchItem;
}
- (CollectionViewItem*)addressSwitchSubtitleItem {
CollectionViewTextItem* textItem = [[CollectionViewTextItem alloc]
initWithType:ItemTypeAutofillAddressSwitchSubtitle];
textItem.text =
- (TableViewHeaderFooterItem*)addressSwitchFooter {
TableViewLinkHeaderFooterItem* footer =
[[TableViewLinkHeaderFooterItem alloc] initWithType:ItemTypeFooter];
footer.text =
l10n_util::GetNSString(IDS_AUTOFILL_ENABLE_PROFILES_TOGGLE_SUBLABEL);
textItem.textFont = [UIFont systemFontOfSize:kUIKitMultilineDetailFontSize];
textItem.textColor = UIColorFromRGB(kUIKitMultilineDetailTextColor);
textItem.numberOfTextLines = 0;
return textItem;
return footer;
}
- (CollectionViewItem*)profileSectionHeader {
SettingsTextItem* header = [self genericHeader];
- (TableViewHeaderFooterItem*)profileSectionHeader {
TableViewTextHeaderFooterItem* header =
[[TableViewTextHeaderFooterItem alloc] initWithType:ItemTypeHeader];
header.text = l10n_util::GetNSString(IDS_AUTOFILL_ADDRESSES);
return header;
}
- (SettingsTextItem*)genericHeader {
SettingsTextItem* header =
[[SettingsTextItem alloc] initWithType:ItemTypeHeader];
header.textColor = [[MDCPalette greyPalette] tint500];
return header;
}
- (CollectionViewItem*)itemForProfile:
- (TableViewItem*)itemForProfile:
(const autofill::AutofillProfile&)autofillProfile {
std::string guid(autofillProfile.guid());
NSString* title = base::SysUTF16ToNSString(
......@@ -183,11 +173,11 @@ typedef NS_ENUM(NSInteger, ItemType) {
bool isServerProfile = autofillProfile.record_type() ==
autofill::AutofillProfile::SERVER_PROFILE;
LegacyAutofillDataItem* item =
[[LegacyAutofillDataItem alloc] initWithType:ItemTypeAddress];
AutofillDataItem* item =
[[AutofillDataItem alloc] initWithType:ItemTypeAddress];
item.text = title;
item.leadingDetailText = subTitle;
item.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
item.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
item.accessibilityIdentifier = title;
item.GUID = guid;
item.deletable = !isServerProfile;
......@@ -202,7 +192,7 @@ typedef NS_ENUM(NSInteger, ItemType) {
return !_personalDataManager->GetProfiles().empty();
}
#pragma mark - SettingsRootCollectionViewController
#pragma mark - SettingsRootTableViewController
- (BOOL)shouldShowEditButton {
return YES;
......@@ -212,18 +202,88 @@ typedef NS_ENUM(NSInteger, ItemType) {
return [self localProfilesExist];
}
#pragma mark - UICollectionViewDataSource
- (void)editButtonPressed {
[super editButtonPressed];
[self setSwitchItemEnabled:!self.tableView.editing
itemType:ItemTypeAutofillAddressSwitch];
}
// Override.
- (void)deleteItems:(NSArray<NSIndexPath*>*)indexPaths {
// If there are no index paths, return early. This can happen if the user
// presses the Delete button twice in quick succession.
if (![indexPaths count])
return;
_deletionInProgress = YES;
[self willDeleteItemsAtIndexPaths:indexPaths];
// Call super to delete the items in the table view.
[super deleteItems:indexPaths];
// TODO(crbug.com/650390) Generalize removing empty sections
[self removeSectionIfEmptyForSectionWithIdentifier:SectionIdentifierProfiles];
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView*)tableView
didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
// Edit mode is the state where the user can select and delete entries. In
// edit mode, selection is handled by the superclass. When not in edit mode
// selection presents the editing controller for the selected entry.
if ([self.tableView isEditing]) {
return;
}
TableViewModel* model = self.tableViewModel;
if ([model itemTypeForIndexPath:indexPath] != ItemTypeAddress)
return;
const std::vector<autofill::AutofillProfile*> autofillProfiles =
_personalDataManager->GetProfiles();
AutofillProfileEditTableViewController* controller =
[AutofillProfileEditTableViewController
controllerWithProfile:*autofillProfiles[indexPath.item]
personalDataManager:_personalDataManager];
controller.dispatcher = self.dispatcher;
[self.navigationController pushViewController:controller animated:YES];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - UITableViewDataSource
- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
cellForItemAtIndexPath:(NSIndexPath*)indexPath {
UICollectionViewCell* cell =
[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
- (BOOL)tableView:(UITableView*)tableView
canEditRowAtIndexPath:(NSIndexPath*)indexPath {
// Only autofill data cells are editable.
TableViewItem* item = [self.tableViewModel itemAtIndexPath:indexPath];
if ([item isKindOfClass:[AutofillDataItem class]]) {
AutofillDataItem* autofillItem =
base::mac::ObjCCastStrict<AutofillDataItem>(item);
return [autofillItem isDeletable];
}
return NO;
}
- (void)tableView:(UITableView*)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath*)indexPath {
if (editingStyle != UITableViewCellEditingStyleDelete)
return;
[self deleteItems:@[ indexPath ]];
}
- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
UITableViewCell* cell = [super tableView:tableView
cellForRowAtIndexPath:indexPath];
ItemType itemType = static_cast<ItemType>(
[self.collectionViewModel itemTypeForIndexPath:indexPath]);
[self.tableViewModel itemTypeForIndexPath:indexPath]);
if (itemType == ItemTypeAutofillAddressSwitch) {
LegacySettingsSwitchCell* switchCell =
base::mac::ObjCCastStrict<LegacySettingsSwitchCell>(cell);
SettingsSwitchCell* switchCell =
base::mac::ObjCCastStrict<SettingsSwitchCell>(cell);
[switchCell.switchView addTarget:self
action:@selector(autofillAddressSwitchChanged:)
forControlEvents:UIControlEventValueChanged];
......@@ -246,11 +306,11 @@ typedef NS_ENUM(NSInteger, ItemType) {
// of |switchItemType| in SectionIdentifierSwitches.
- (void)setSwitchItemOn:(BOOL)on itemType:(ItemType)switchItemType {
NSIndexPath* switchPath =
[self.collectionViewModel indexPathForItemType:switchItemType
sectionIdentifier:SectionIdentifierSwitches];
LegacySettingsSwitchItem* switchItem =
base::mac::ObjCCastStrict<LegacySettingsSwitchItem>(
[self.collectionViewModel itemAtIndexPath:switchPath]);
[self.tableViewModel indexPathForItemType:switchItemType
sectionIdentifier:SectionIdentifierSwitches];
SettingsSwitchItem* switchItem =
base::mac::ObjCCastStrict<SettingsSwitchItem>(
[self.tableViewModel itemAtIndexPath:switchPath]);
switchItem.on = on;
}
......@@ -258,7 +318,7 @@ typedef NS_ENUM(NSInteger, ItemType) {
// corresponding cell. It is important that there is no more than one item of
// |switchItemType| in SectionIdentifierSwitches.
- (void)setSwitchItemEnabled:(BOOL)enabled itemType:(ItemType)switchItemType {
CollectionViewModel* model = self.collectionViewModel;
TableViewModel* model = self.tableViewModel;
if (![model hasItemForItemType:switchItemType
sectionIdentifier:SectionIdentifierSwitches]) {
......@@ -267,189 +327,96 @@ typedef NS_ENUM(NSInteger, ItemType) {
NSIndexPath* switchPath =
[model indexPathForItemType:switchItemType
sectionIdentifier:SectionIdentifierSwitches];
LegacySettingsSwitchItem* switchItem =
base::mac::ObjCCastStrict<LegacySettingsSwitchItem>(
SettingsSwitchItem* switchItem =
base::mac::ObjCCastStrict<SettingsSwitchItem>(
[model itemAtIndexPath:switchPath]);
[switchItem setEnabled:enabled];
[self reconfigureCellsForItems:@[ switchItem ]];
}
#pragma mark - MDCCollectionViewStylingDelegate
- (CGFloat)collectionView:(UICollectionView*)collectionView
cellHeightAtIndexPath:(NSIndexPath*)indexPath {
CollectionViewItem* item =
[self.collectionViewModel itemAtIndexPath:indexPath];
return [MDCCollectionViewCell
cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
forItem:item];
}
- (BOOL)collectionView:(UICollectionView*)collectionView
hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
NSInteger sectionIdentifier =
[self.collectionViewModel sectionIdentifierForSection:indexPath.section];
return sectionIdentifier == SectionIdentifierSwitches ||
sectionIdentifier == SectionIdentifierSubtitle;
}
- (BOOL)collectionView:(UICollectionView*)collectionView
shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath {
NSInteger sectionIdentifier =
[self.collectionViewModel sectionIdentifierForSection:indexPath.section];
return sectionIdentifier == SectionIdentifierSubtitle;
}
#pragma mark - UICollectionViewDelegate
#pragma mark - PersonalDataManagerObserver
- (void)collectionView:(UICollectionView*)collectionView
didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
[super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
// Edit mode is the state where the user can select and delete entries. In
// edit mode, selection is handled by the superclass. When not in edit mode
// selection presents the editing controller for the selected entry.
if ([self.editor isEditing]) {
return;
}
CollectionViewModel* model = self.collectionViewModel;
if ([model itemTypeForIndexPath:indexPath] != ItemTypeAddress)
- (void)onPersonalDataChanged {
if (_deletionInProgress)
return;
const std::vector<autofill::AutofillProfile*> autofillProfiles =
_personalDataManager->GetProfiles();
AutofillProfileEditTableViewController* controller =
[AutofillProfileEditTableViewController
controllerWithProfile:*autofillProfiles[indexPath.item]
personalDataManager:_personalDataManager];
controller.dispatcher = self.dispatcher;
[self.navigationController pushViewController:controller animated:YES];
}
#pragma mark - MDCCollectionViewEditingDelegate
if ([self.tableView isEditing]) {
// Turn off edit mode.
[self setEditing:NO animated:NO];
}
- (BOOL)collectionViewAllowsEditing:(UICollectionView*)collectionView {
return YES;
[self updateEditButton];
[self reloadData];
}
- (void)collectionViewWillBeginEditing:(UICollectionView*)collectionView {
[super collectionViewWillBeginEditing:collectionView];
#pragma mark - Getters and Setter
[self setSwitchItemEnabled:NO itemType:ItemTypeAutofillAddressSwitch];
- (BOOL)isAutofillProfileEnabled {
return autofill::prefs::IsProfileAutofillEnabled(_browserState->GetPrefs());
}
- (void)collectionViewWillEndEditing:(UICollectionView*)collectionView {
[super collectionViewWillEndEditing:collectionView];
[self setSwitchItemEnabled:YES itemType:ItemTypeAutofillAddressSwitch];
- (void)setAutofillProfileEnabled:(BOOL)isEnabled {
return autofill::prefs::SetProfileAutofillEnabled(_browserState->GetPrefs(),
isEnabled);
}
- (BOOL)collectionView:(UICollectionView*)collectionView
canEditItemAtIndexPath:(NSIndexPath*)indexPath {
// Only autofill data cells are editable.
CollectionViewItem* item =
[self.collectionViewModel itemAtIndexPath:indexPath];
if ([item isKindOfClass:[LegacyAutofillDataItem class]]) {
LegacyAutofillDataItem* autofillItem =
base::mac::ObjCCastStrict<LegacyAutofillDataItem>(item);
return [autofillItem isDeletable];
}
return NO;
}
#pragma mark - Private
- (void)collectionView:(UICollectionView*)collectionView
willDeleteItemsAtIndexPaths:(NSArray*)indexPaths {
_deletionInProgress = YES;
// Removes the item from the personal data manager model.
- (void)willDeleteItemsAtIndexPaths:(NSArray*)indexPaths {
for (NSIndexPath* indexPath in indexPaths) {
LegacyAutofillDataItem* item =
base::mac::ObjCCastStrict<LegacyAutofillDataItem>(
[self.collectionViewModel itemAtIndexPath:indexPath]);
AutofillDataItem* item = base::mac::ObjCCastStrict<AutofillDataItem>(
[self.tableViewModel itemAtIndexPath:indexPath]);
_personalDataManager->RemoveByGUID([item GUID]);
}
// Must call super at the end of the child implementation.
[super collectionView:collectionView willDeleteItemsAtIndexPaths:indexPaths];
}
- (void)collectionView:(UICollectionView*)collectionView
didDeleteItemsAtIndexPaths:(NSArray*)indexPaths {
// If there are no index paths, return early. This can happen if the user
// presses the Delete button twice in quick succession.
if (![indexPaths count])
return;
// TODO(crbug.com/650390) Generalize removing empty sections
[self removeSectionIfEmptyForSectionWithIdentifier:SectionIdentifierProfiles];
}
// Remove the section from the model and collectionView if there are no more
// items in the section.
- (void)removeSectionIfEmptyForSectionWithIdentifier:
(SectionIdentifier)sectionIdentifier {
if (![self.collectionViewModel
hasSectionForSectionIdentifier:sectionIdentifier]) {
if (![self.tableViewModel hasSectionForSectionIdentifier:sectionIdentifier]) {
_deletionInProgress = NO;
return;
}
NSInteger section =
[self.collectionViewModel sectionForSectionIdentifier:sectionIdentifier];
if ([self.collectionView numberOfItemsInSection:section] == 0) {
[self.tableViewModel sectionForSectionIdentifier:sectionIdentifier];
if ([self.tableView numberOfRowsInSection:section] == 0) {
// Avoid reference cycle in block.
__weak AutofillProfileCollectionViewController* weakSelf = self;
[self.collectionView performBatchUpdates:^{
// Obtain strong reference again.
AutofillProfileCollectionViewController* strongSelf = weakSelf;
if (!strongSelf) {
return;
}
// Remove section from model and collectionView.
[[strongSelf collectionViewModel]
removeSectionWithIdentifier:sectionIdentifier];
[[strongSelf collectionView]
deleteSections:[NSIndexSet indexSetWithIndex:section]];
}
__weak AutofillProfileTableViewController* weakSelf = self;
[self.tableView
performBatchUpdates:^{
// Obtain strong reference again.
AutofillProfileTableViewController* strongSelf = weakSelf;
if (!strongSelf) {
return;
}
// Remove section from model and collectionView.
[[strongSelf tableViewModel]
removeSectionWithIdentifier:sectionIdentifier];
[[strongSelf tableView]
deleteSections:[NSIndexSet indexSetWithIndex:section]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
completion:^(BOOL finished) {
// Obtain strong reference again.
AutofillProfileCollectionViewController* strongSelf = weakSelf;
AutofillProfileTableViewController* strongSelf = weakSelf;
if (!strongSelf) {
return;
}
// Turn off edit mode if there is nothing to edit.
if (![strongSelf localProfilesExist] &&
[strongSelf.editor isEditing]) {
[[strongSelf editor] setEditing:NO];
[strongSelf.tableView isEditing]) {
[strongSelf setEditing:NO animated:YES];
}
[strongSelf updateEditButton];
strongSelf->_deletionInProgress = NO;
}];
} else {
_deletionInProgress = NO;
}
}
#pragma mark PersonalDataManagerObserver
- (void)onPersonalDataChanged {
if (_deletionInProgress)
return;
if (![self localProfilesExist] && [self.editor isEditing]) {
// Turn off edit mode if there exists nothing to edit.
[self.editor setEditing:NO];
}
[self updateEditButton];
[self reloadData];
}
#pragma mark - Getters and Setter
- (BOOL)isAutofillProfileEnabled {
return autofill::prefs::IsProfileAutofillEnabled(_browserState->GetPrefs());
}
- (void)setAutofillProfileEnabled:(BOOL)isEnabled {
return autofill::prefs::SetProfileAutofillEnabled(_browserState->GetPrefs(),
isEnabled);
}
@end
......@@ -2,7 +2,7 @@
// 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/autofill_profile_collection_view_controller.h"
#import "ios/chrome/browser/ui/settings/autofill_profile_table_view_controller.h"
#include "base/guid.h"
#include "base/mac/foundation_util.h"
......@@ -10,10 +10,12 @@
#import "base/test/ios/wait_util.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/strings/grit/components_strings.h"
#include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h"
#include "ios/chrome/browser/ui/settings/personal_data_manager_data_changed_observer.h"
#import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h"
#import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h"
#include "ios/web/public/test/test_web_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -21,16 +23,12 @@
#error "This file requires ARC support."
#endif
@interface SettingsRootCollectionViewController (ExposedForTesting)
- (void)editButtonPressed;
@end
namespace {
class AutofillProfileCollectionViewControllerTest
: public CollectionViewControllerTest {
class AutofillProfileTableViewControllerTest
: public ChromeTableViewControllerTest {
protected:
AutofillProfileCollectionViewControllerTest() {
AutofillProfileTableViewControllerTest() {
TestChromeBrowserState::Builder test_cbs_builder;
chrome_browser_state_ = test_cbs_builder.Build();
// Profile import requires a PersonalDataManager which itself needs the
......@@ -39,8 +37,8 @@ class AutofillProfileCollectionViewControllerTest
chrome_browser_state_->CreateWebDataService();
}
CollectionViewController* InstantiateController() override {
return [[AutofillProfileCollectionViewController alloc]
ChromeTableViewController* InstantiateController() override {
return [[AutofillProfileTableViewController alloc]
initWithBrowserState:chrome_browser_state_.get()];
}
......@@ -65,76 +63,73 @@ class AutofillProfileCollectionViewControllerTest
};
// Default test case of no addresses.
TEST_F(AutofillProfileCollectionViewControllerTest, TestInitialization) {
CreateController();
TEST_F(AutofillProfileTableViewControllerTest, TestInitialization) {
ChromeTableViewController* controller =
ChromeTableViewControllerTest::controller();
CheckController();
// Expect one header section and one subtitle section.
EXPECT_EQ(2, NumberOfSections());
// Expect only the header section.
EXPECT_EQ(1, NumberOfSections());
// Expect header section to contain one row (the address Autofill toggle).
EXPECT_EQ(1, NumberOfItemsInSection(0));
// Expect subtitle section to contain one row (the address Autofill toggle
// subtitle).
EXPECT_EQ(1, NumberOfItemsInSection(1));
EXPECT_NE(nil, [controller.tableViewModel footerForSection:0]);
// Check the footer of the first section.
CheckSectionFooterWithId(IDS_AUTOFILL_ENABLE_PROFILES_TOGGLE_SUBLABEL, 0);
}
// Adding a single address results in an address section.
TEST_F(AutofillProfileCollectionViewControllerTest, TestOneProfile) {
TEST_F(AutofillProfileTableViewControllerTest, TestOneProfile) {
AddProfile("https://www.example.com/", "John Doe", "1 Main Street");
CreateController();
CheckController();
// Expect three sections (header, subtitle, and addresses section).
EXPECT_EQ(3, NumberOfSections());
// Expect two sections (header, and addresses section).
EXPECT_EQ(2, NumberOfSections());
// Expect address section to contain one row (the address itself).
EXPECT_EQ(1, NumberOfItemsInSection(2));
EXPECT_EQ(1, NumberOfItemsInSection(1));
}
// Deleting the only profile results in item deletion and section deletion.
TEST_F(AutofillProfileCollectionViewControllerTest, TestOneProfileItemDeleted) {
TEST_F(AutofillProfileTableViewControllerTest, TestOneProfileItemDeleted) {
AddProfile("https://www.example.com/", "John Doe", "1 Main Street");
CreateController();
CheckController();
// Expect three sections (header, subtitle, and addresses section).
EXPECT_EQ(3, NumberOfSections());
// Expect two sections (header and addresses section).
EXPECT_EQ(2, NumberOfSections());
// Expect address section to contain one row (the address itself).
EXPECT_EQ(1, NumberOfItemsInSection(2));
EXPECT_EQ(1, NumberOfItemsInSection(1));
AutofillProfileCollectionViewController* view_controller =
base::mac::ObjCCastStrict<AutofillProfileCollectionViewController>(
AutofillProfileTableViewController* view_controller =
base::mac::ObjCCastStrict<AutofillProfileTableViewController>(
controller());
// Put the collectionView in 'edit' mode.
// Put the tableView in 'edit' mode.
[view_controller editButtonPressed];
// This is a bit of a shortcut, since actually clicking on the 'delete'
// button would be tough.
void (^delete_item_with_wait)(int, int) = ^(int i, int j) {
__block BOOL completion_called = NO;
this->DeleteItem(i, j, ^{
completion_called = YES;
});
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool() {
return completion_called;
}));
};
autofill::PersonalDataManager* personal_data_manager =
autofill::PersonalDataManagerFactory::GetForBrowserState(
chrome_browser_state_.get());
PersonalDataManagerDataChangedObserver observer(personal_data_manager);
// This call cause a modification of the PersonalDataManager, so wait until
// the asynchronous task complete in addition to waiting for the UI update.
delete_item_with_wait(2, 0);
observer.Wait(); // Wait for completion of the asynchronous operation.
AutofillProfileTableViewController* autofill_controller =
static_cast<AutofillProfileTableViewController*>(controller());
[autofill_controller deleteItems:@[ [NSIndexPath indexPathForRow:0
inSection:1] ]];
// Verify the resulting UI.
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool() {
return NumberOfSections() == 1;
}));
// Exit 'edit' mode.
[view_controller editButtonPressed];
// Expect address section to have been removed.
EXPECT_EQ(2, NumberOfSections());
EXPECT_EQ(1, NumberOfSections());
}
} // namespace
......@@ -45,7 +45,7 @@
#import "ios/chrome/browser/ui/settings/about_chrome_table_view_controller.h"
#import "ios/chrome/browser/ui/settings/accounts_collection_view_controller.h"
#import "ios/chrome/browser/ui/settings/autofill_credit_card_collection_view_controller.h"
#import "ios/chrome/browser/ui/settings/autofill_profile_collection_view_controller.h"
#import "ios/chrome/browser/ui/settings/autofill_profile_table_view_controller.h"
#import "ios/chrome/browser/ui/settings/bandwidth_management_table_view_controller.h"
#import "ios/chrome/browser/ui/settings/cells/account_signin_item.h"
#import "ios/chrome/browser/ui/settings/cells/legacy/legacy_settings_detail_item.h"
......@@ -867,7 +867,7 @@ void IdentityObserverBridge::OnPrimaryAccountCleared(
initWithBrowserState:_browserState];
break;
case ItemTypeAutofillProfile:
controller = [[AutofillProfileCollectionViewController alloc]
controller = [[AutofillProfileTableViewController alloc]
initWithBrowserState:_browserState];
break;
case ItemTypeVoiceSearch:
......
......@@ -104,7 +104,7 @@ newImportDataController:(ios::ChromeBrowserState*)browserState
toEmail:(NSString*)toEmail
isSignedIn:(BOOL)isSignedIn;
// Creates a new AutofillProfileCollectionViewController and the chrome around
// Creates a new AutofillProfileTableViewController and the chrome around
// it. |browserState| is used to personalize some settings aspects and should
// not be nil. |delegate| may be nil.
+ (SettingsNavigationController*)
......
......@@ -15,7 +15,7 @@
#import "ios/chrome/browser/ui/material_components/utils.h"
#import "ios/chrome/browser/ui/settings/accounts_collection_view_controller.h"
#import "ios/chrome/browser/ui/settings/autofill_credit_card_collection_view_controller.h"
#import "ios/chrome/browser/ui/settings/autofill_profile_collection_view_controller.h"
#import "ios/chrome/browser/ui/settings/autofill_profile_table_view_controller.h"
#import "ios/chrome/browser/ui/settings/google_services_settings_coordinator.h"
#import "ios/chrome/browser/ui/settings/google_services_settings_view_controller.h"
#import "ios/chrome/browser/ui/settings/import_data_table_view_controller.h"
......@@ -242,8 +242,8 @@ newImportDataController:(ios::ChromeBrowserState*)browserState
newAutofillProfilleController:(ios::ChromeBrowserState*)browserState
delegate:
(id<SettingsNavigationControllerDelegate>)delegate {
AutofillProfileCollectionViewController* controller =
[[AutofillProfileCollectionViewController alloc]
AutofillProfileTableViewController* controller =
[[AutofillProfileTableViewController alloc]
initWithBrowserState:browserState];
controller.dispatcher = [delegate dispatcherForSettings];
......@@ -561,8 +561,8 @@ initWithRootViewController:(UIViewController*)rootViewController
// TODO(crbug.com/779791) : Do not pass |baseViewController| through dispatcher.
- (void)showProfileSettingsFromViewController:
(UIViewController*)baseViewController {
AutofillProfileCollectionViewController* controller =
[[AutofillProfileCollectionViewController alloc]
AutofillProfileTableViewController* controller =
[[AutofillProfileTableViewController alloc]
initWithBrowserState:mainBrowserState_];
controller.dispatcher = [delegate_ dispatcherForSettings];
[self pushViewController:controller animated:YES];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment