Index: ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm |
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm |
index 5eb5a5199c2bb65d82e88d62ea174728f925f343..05604e9b00bbb3a68a8b6944075be8ee43d7e87a 100644 |
--- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm |
+++ b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm |
@@ -12,7 +12,9 @@ |
#import "ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h" |
#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h" |
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h" |
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item+collection_view_controller.h" |
#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" |
+#import "ios/chrome/browser/ui/payments/cells/payments_selector_edit_item.h" |
#import "ios/chrome/browser/ui/payments/cells/payments_text_item.h" |
#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller+internal.h" |
#import "ios/chrome/browser/ui/payments/payment_request_editor_field.h" |
@@ -30,8 +32,8 @@ NSString* const kWarningMessageAccessibilityID = |
namespace { |
-NSString* const kPaymentRequestEditCollectionViewID = |
- @"kPaymentRequestEditCollectionViewID"; |
+NSString* const kPaymentRequestEditCollectionViewAccessibilityID = |
+ @"kPaymentRequestEditCollectionViewAccessibilityID"; |
const CGFloat kSeparatorEdgeInset = 14; |
@@ -51,21 +53,23 @@ AutofillEditCell* AutofillEditCellForTextField(UITextField* textField) { |
} |
typedef NS_ENUM(NSInteger, SectionIdentifier) { |
- SectionIdentifierFooter = kSectionIdentifierEnumZero, |
- SectionIdentifierFirstTextField, |
+ SectionIdentifierHeader = kSectionIdentifierEnumZero, |
+ SectionIdentifierFooter, |
+ SectionIdentifierFirstField, // Must be the last section identifier. |
}; |
typedef NS_ENUM(NSInteger, ItemType) { |
- ItemTypeFooter = kItemTypeEnumZero, |
- ItemTypeTextField, // This is a repeated item type. |
- ItemTypeErrorMessage, // This is a repeated item type. |
+ ItemTypeHeader = kItemTypeEnumZero, |
+ ItemTypeFooter, |
+ ItemTypeTextField, // This is a repeated item type. |
+ ItemTypeSelectorField, // This is a repeated item type. |
+ ItemTypeErrorMessage, // This is a repeated item type. |
}; |
} // namespace |
@interface PaymentRequestEditViewController ()< |
AutofillEditAccessoryDelegate, |
- PaymentRequestEditViewControllerValidator, |
UITextFieldDelegate> { |
NSArray<EditorField*>* _fields; |
@@ -89,19 +93,22 @@ typedef NS_ENUM(NSInteger, ItemType) { |
// field. |
- (void)updateAccessoryViewButtonsStates; |
+// Adds an error message item in the section |sectionIdentifier| if |
+// |errorMessage| is non-empty. Otherwise removes such an item if one exists. |
+- (void)addOrRemoveErrorMessage:(NSString*)errorMessage |
+ inSectionWithIdentifier:(NSInteger)sectionIdentifier; |
+ |
@end |
@implementation PaymentRequestEditViewController |
@synthesize dataSource = _dataSource; |
+@synthesize delegate = _delegate; |
@synthesize validatorDelegate = _validatorDelegate; |
- (instancetype)initWithStyle:(CollectionViewControllerStyle)style { |
self = [super initWithStyle:style]; |
if (self) { |
- // Set self as the validator delegate. |
- _validatorDelegate = self; |
- |
_accessoryView = [[AutofillEditAccessoryView alloc] initWithDelegate:self]; |
} |
return self; |
@@ -136,22 +143,48 @@ typedef NS_ENUM(NSInteger, ItemType) { |
[super loadModel]; |
CollectionViewModel* model = self.collectionViewModel; |
- [self loadHeaderItems]; |
+ CollectionViewItem* headerItem = [_dataSource headerItem]; |
+ if (headerItem) { |
+ [headerItem setType:ItemTypeHeader]; |
+ [model addSectionWithIdentifier:SectionIdentifierHeader]; |
+ [model addItem:headerItem toSectionWithIdentifier:SectionIdentifierHeader]; |
+ } |
// Iterate over the fields and add the respective sections and items. |
- int sectionIdentifier = static_cast<int>(SectionIdentifierFirstTextField); |
+ int sectionIdentifier = static_cast<int>(SectionIdentifierFirstField); |
for (EditorField* field in _fields) { |
[model addSectionWithIdentifier:sectionIdentifier]; |
- AutofillEditItem* item = |
- [[AutofillEditItem alloc] initWithType:ItemTypeTextField]; |
- item.textFieldName = field.label; |
- item.textFieldEnabled = YES; |
- item.textFieldValue = field.value; |
- item.required = field.isRequired; |
- item.autofillUIType = field.autofillUIType; |
- [model addItem:item |
- toSectionWithIdentifier:static_cast<NSInteger>(sectionIdentifier)]; |
- field.item = item; |
+ switch (field.fieldType) { |
+ case EditorFieldTypeTextField: { |
+ AutofillEditItem* item = |
+ [[AutofillEditItem alloc] initWithType:ItemTypeTextField]; |
+ item.textFieldName = field.label; |
+ item.textFieldEnabled = YES; |
+ item.textFieldValue = field.value; |
+ item.required = field.isRequired; |
+ item.autofillUIType = field.autofillUIType; |
+ [model addItem:item |
+ toSectionWithIdentifier:static_cast<NSInteger>(sectionIdentifier)]; |
+ field.item = item; |
+ break; |
+ } |
+ case EditorFieldTypeSelector: { |
+ PaymentsSelectorEditItem* item = [[PaymentsSelectorEditItem alloc] |
+ initWithType:ItemTypeSelectorField]; |
+ item.name = field.label; |
+ item.value = field.displayValue; |
+ item.required = field.isRequired; |
+ item.autofillUIType = field.autofillUIType; |
+ item.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator; |
+ [model addItem:item |
+ toSectionWithIdentifier:static_cast<NSInteger>(sectionIdentifier)]; |
+ field.item = item; |
+ break; |
+ } |
+ default: |
+ NOTREACHED(); |
+ } |
+ |
field.sectionIdentifier = static_cast<NSInteger>(sectionIdentifier); |
++sectionIdentifier; |
} |
@@ -163,7 +196,7 @@ typedef NS_ENUM(NSInteger, ItemType) { |
[super viewDidLoad]; |
self.collectionView.accessibilityIdentifier = |
- kPaymentRequestEditCollectionViewID; |
+ kPaymentRequestEditCollectionViewAccessibilityID; |
// Customize collection view settings. |
self.styler.cellStyle = MDCCollectionViewCellStyleCard; |
@@ -189,11 +222,16 @@ typedef NS_ENUM(NSInteger, ItemType) { |
AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( |
[model itemAtIndexPath:indexPath]); |
+ // Create a dummy EditorField for validation only. |
+ EditorField* fieldForValidation = |
+ [[EditorField alloc] initWithAutofillUIType:item.autofillUIType |
+ fieldType:EditorFieldTypeTextField |
+ label:nil |
+ value:textField.text |
+ required:item.required]; |
NSString* errorMessage = |
[_validatorDelegate paymentRequestEditViewController:self |
- validateValue:textField.text |
- autofillUIType:item.autofillUIType |
- required:item.required]; |
+ validateField:fieldForValidation]; |
NSInteger sectionIdentifier = |
[model sectionIdentifierForSection:[indexPath section]]; |
[self addOrRemoveErrorMessage:errorMessage |
@@ -278,6 +316,24 @@ typedef NS_ENUM(NSInteger, ItemType) { |
return cell; |
} |
+#pragma mark UICollectionViewDelegate |
+ |
+- (void)collectionView:(UICollectionView*)collectionView |
+ didSelectItemAtIndexPath:(NSIndexPath*)indexPath { |
+ [super collectionView:collectionView didSelectItemAtIndexPath:indexPath]; |
+ |
+ // Every field has its own section. Find out which field is selected using |
+ // the section of |indexPath|. Adjust the index if a header section is |
+ // present before the editor fields. |
+ NSInteger index = indexPath.section; |
+ if ([self.collectionViewModel |
+ hasSectionForSectionIdentifier:SectionIdentifierHeader]) |
+ index--; |
+ DCHECK(index >= 0 && index < static_cast<NSInteger>(_fields.count)); |
+ [_delegate paymentRequestEditViewController:self |
+ didSelectField:[_fields objectAtIndex:index]]; |
+} |
+ |
#pragma mark MDCCollectionViewStylingDelegate |
- (CGFloat)collectionView:(UICollectionView*)collectionView |
@@ -285,12 +341,15 @@ typedef NS_ENUM(NSInteger, ItemType) { |
CollectionViewItem* item = |
[self.collectionViewModel itemAtIndexPath:indexPath]; |
switch (item.type) { |
+ case ItemTypeHeader: |
+ case ItemTypeFooter: |
case ItemTypeTextField: |
case ItemTypeErrorMessage: |
- case ItemTypeFooter: |
return [MDCCollectionViewCell |
cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) |
forItem:item]; |
+ case ItemTypeSelectorField: |
+ return MDCCellDefaultOneLineHeight; |
default: |
NOTREACHED(); |
return MDCCellDefaultOneLineHeight; |
@@ -301,8 +360,9 @@ typedef NS_ENUM(NSInteger, ItemType) { |
hidesInkViewAtIndexPath:(NSIndexPath*)indexPath { |
NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; |
switch (type) { |
- case ItemTypeErrorMessage: |
+ case ItemTypeHeader: |
case ItemTypeFooter: |
+ case ItemTypeErrorMessage: |
return YES; |
default: |
return NO; |
@@ -313,6 +373,8 @@ typedef NS_ENUM(NSInteger, ItemType) { |
shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath { |
NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; |
switch (type) { |
+ case ItemTypeHeader: |
+ return [_dataSource shouldHideBackgroundForHeaderItem]; |
case ItemTypeFooter: |
return YES; |
default: |
@@ -320,20 +382,6 @@ typedef NS_ENUM(NSInteger, ItemType) { |
} |
} |
-#pragma mark - PaymentRequestEditViewControllerValidator |
- |
-- (NSString*)paymentRequestEditViewController: |
- (PaymentRequestEditViewController*)controller |
- validateValue:(NSString*)value |
- autofillUIType:(AutofillUIType)autofillUIType |
- required:(BOOL)required { |
- if (required && !value.length) { |
- return l10n_util::GetNSString( |
- IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE); |
- } |
- return nil; |
-} |
- |
#pragma mark - Helper methods |
- (NSIndexPath*)indexPathWithSectionOffset:(NSInteger)offset |
@@ -354,12 +402,14 @@ typedef NS_ENUM(NSInteger, ItemType) { |
DCHECK(currentCellPath); |
NSIndexPath* nextCellPath = |
[self indexPathWithSectionOffset:offset fromPath:currentCellPath]; |
- if (nextCellPath) { |
+ while (nextCellPath) { |
id nextCell = [collectionView cellForItemAtIndexPath:nextCellPath]; |
if ([nextCell isKindOfClass:[AutofillEditCell class]]) { |
return base::mac::ObjCCastStrict<AutofillEditCell>( |
[collectionView cellForItemAtIndexPath:nextCellPath]); |
} |
+ nextCellPath = |
+ [self indexPathWithSectionOffset:offset fromPath:nextCellPath]; |
} |
return nil; |
} |
@@ -372,6 +422,39 @@ typedef NS_ENUM(NSInteger, ItemType) { |
[[_accessoryView nextButton] setEnabled:nextCell != nil]; |
} |
+- (void)addOrRemoveErrorMessage:(NSString*)errorMessage |
+ inSectionWithIdentifier:(NSInteger)sectionIdentifier { |
+ CollectionViewModel* model = self.collectionViewModel; |
+ if ([model hasItemForItemType:ItemTypeErrorMessage |
+ sectionIdentifier:sectionIdentifier]) { |
+ NSIndexPath* indexPath = [model indexPathForItemType:ItemTypeErrorMessage |
+ sectionIdentifier:sectionIdentifier]; |
+ if (!errorMessage.length) { |
+ // Remove the item at the index path. |
+ [model removeItemWithType:ItemTypeErrorMessage |
+ fromSectionWithIdentifier:sectionIdentifier]; |
+ [self.collectionView deleteItemsAtIndexPaths:@[ indexPath ]]; |
+ } else { |
+ // Reload the item at the index path. |
+ PaymentsTextItem* item = base::mac::ObjCCastStrict<PaymentsTextItem>( |
+ [model itemAtIndexPath:indexPath]); |
+ item.text = errorMessage; |
+ [self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]]; |
+ } |
+ } else if (errorMessage.length) { |
+ // Insert an item at the index path. |
+ PaymentsTextItem* errorMessageItem = |
+ [[PaymentsTextItem alloc] initWithType:ItemTypeErrorMessage]; |
+ errorMessageItem.text = errorMessage; |
+ errorMessageItem.image = NativeImage(IDR_IOS_PAYMENTS_WARNING); |
+ errorMessageItem.accessibilityIdentifier = kWarningMessageAccessibilityID; |
+ [model addItem:errorMessageItem toSectionWithIdentifier:sectionIdentifier]; |
+ NSIndexPath* indexPath = [model indexPathForItemType:ItemTypeErrorMessage |
+ sectionIdentifier:sectionIdentifier]; |
+ [self.collectionView insertItemsAtIndexPaths:@[ indexPath ]]; |
+ } |
+} |
+ |
#pragma mark - Keyboard handling |
- (void)keyboardDidShow { |
@@ -388,26 +471,33 @@ typedef NS_ENUM(NSInteger, ItemType) { |
- (BOOL)validateForm { |
for (EditorField* field in _fields) { |
- AutofillEditItem* item = field.item; |
+ switch (field.fieldType) { |
+ case EditorFieldTypeTextField: { |
+ AutofillEditItem* item = |
+ base::mac::ObjCCastStrict<AutofillEditItem>(field.item); |
+ // Update the EditorField with the value of the text field. |
+ field.value = item.textFieldValue; |
+ break; |
+ } |
+ case EditorFieldTypeSelector: { |
+ // No need to update the EditorField. It should already be up-to-date. |
+ break; |
+ } |
+ default: |
+ NOTREACHED(); |
+ } |
- NSString* errorMessage = [_validatorDelegate |
- paymentRequestEditViewController:self |
- validateValue:item.textFieldValue |
- autofillUIType:field.autofillUIType |
- required:field.isRequired]; |
+ NSString* errorMessage = |
+ [_validatorDelegate paymentRequestEditViewController:self |
+ validateField:field]; |
[self addOrRemoveErrorMessage:errorMessage |
inSectionWithIdentifier:field.sectionIdentifier]; |
if (errorMessage.length) |
return NO; |
- |
- field.value = item.textFieldValue; |
} |
return YES; |
} |
-- (void)loadHeaderItems { |
-} |
- |
- (void)loadFooterItems { |
CollectionViewModel* model = self.collectionViewModel; |
@@ -426,37 +516,4 @@ typedef NS_ENUM(NSInteger, ItemType) { |
return indexPath; |
} |
-- (void)addOrRemoveErrorMessage:(NSString*)errorMessage |
- inSectionWithIdentifier:(NSInteger)sectionIdentifier { |
- CollectionViewModel* model = self.collectionViewModel; |
- if ([model hasItemForItemType:ItemTypeErrorMessage |
- sectionIdentifier:sectionIdentifier]) { |
- NSIndexPath* indexPath = [model indexPathForItemType:ItemTypeErrorMessage |
- sectionIdentifier:sectionIdentifier]; |
- if (!errorMessage.length) { |
- // Remove the item at the index path. |
- [model removeItemWithType:ItemTypeErrorMessage |
- fromSectionWithIdentifier:sectionIdentifier]; |
- [self.collectionView deleteItemsAtIndexPaths:@[ indexPath ]]; |
- } else { |
- // Reload the item at the index path. |
- PaymentsTextItem* item = base::mac::ObjCCastStrict<PaymentsTextItem>( |
- [model itemAtIndexPath:indexPath]); |
- item.text = errorMessage; |
- [self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]]; |
- } |
- } else if (errorMessage.length) { |
- // Insert an item at the index path. |
- PaymentsTextItem* errorMessageItem = |
- [[PaymentsTextItem alloc] initWithType:ItemTypeErrorMessage]; |
- errorMessageItem.text = errorMessage; |
- errorMessageItem.image = NativeImage(IDR_IOS_PAYMENTS_WARNING); |
- errorMessageItem.accessibilityIdentifier = kWarningMessageAccessibilityID; |
- [model addItem:errorMessageItem toSectionWithIdentifier:sectionIdentifier]; |
- NSIndexPath* indexPath = [model indexPathForItemType:ItemTypeErrorMessage |
- sectionIdentifier:sectionIdentifier]; |
- [self.collectionView insertItemsAtIndexPaths:@[ indexPath ]]; |
- } |
-} |
- |
@end |