Chromium Code Reviews| 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 0e58eb97e8987e4f9cad9e9164398d2166228714..05cf2b4dd95d90aca71c5ecd9ebea66a8eee71d0 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 |
| @@ -13,10 +13,11 @@ |
| #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/collection_view/cells/collection_view_switch_item.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_edit_view_controller_actions.h" |
| #import "ios/chrome/browser/ui/payments/payment_request_editor_field.h" |
| #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| #include "ios/chrome/grit/ios_theme_resources.h" |
| @@ -52,6 +53,20 @@ AutofillEditCell* AutofillEditCellForTextField(UITextField* textField) { |
| return nil; |
| } |
| +CollectionViewSwitchCell* CollectionViewSwitchCellForSwitchField( |
| + UISwitch* switchField) { |
| + for (UIView* view = switchField; view; view = [view superview]) { |
| + CollectionViewSwitchCell* cell = |
| + base::mac::ObjCCast<CollectionViewSwitchCell>(view); |
| + if (cell) |
| + return cell; |
| + } |
| + |
| + // There should be a cell associated with this switch field. |
| + NOTREACHED(); |
| + return nil; |
| +} |
| + |
| typedef NS_ENUM(NSInteger, SectionIdentifier) { |
| SectionIdentifierHeader = kSectionIdentifierEnumZero, |
| SectionIdentifierFooter, |
| @@ -63,22 +78,25 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| ItemTypeFooter, |
| ItemTypeTextField, // This is a repeated item type. |
| ItemTypeSelectorField, // This is a repeated item type. |
| + ItemTypeSwitchField, // This is a repeated item type. |
| ItemTypeErrorMessage, // This is a repeated item type. |
| }; |
| } // namespace |
| -@interface PaymentRequestEditViewController ()<AutofillEditAccessoryDelegate, |
| - UITextFieldDelegate, |
| - UIPickerViewDataSource, |
| - UIPickerViewDelegate> { |
| +@interface PaymentRequestEditViewController ()< |
| + PaymentRequestEditViewControllerActions, |
|
lpromero
2017/05/30 12:35:45
Sort alphabetically.
Moe
2017/05/31 03:21:11
Done.
|
| + AutofillEditAccessoryDelegate, |
| + UITextFieldDelegate, |
| + UIPickerViewDataSource, |
| + UIPickerViewDelegate> { |
| // The currently focused cell. May be nil. |
| __weak AutofillEditCell* _currentEditingCell; |
| AutofillEditAccessoryView* _accessoryView; |
| } |
| -// The map of autofill types to the fields definitions for the editor. |
| +// The map of section identifiers to the fields definitions for the editor. |
| @property(nonatomic, strong) |
| NSMutableDictionary<NSNumber*, EditorField*>* fieldsMap; |
| @@ -112,6 +130,16 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| - (void)addOrRemoveErrorMessage:(NSString*)errorMessage |
| inSectionWithIdentifier:(NSInteger)sectionIdentifier; |
| +// Validates each field. If there is a validation error, displays an error |
| +// message item in the same section as the field and returns NO. Otherwise |
| +// removes the error message item in that section if one exists and sets the |
| +// value on the field. Returns YES if all the fields are validated successfully. |
| +- (BOOL)validateForm; |
| + |
| +// Returns the index path for the cell associated with the currently focused |
| +// text field. |
| +- (NSIndexPath*)indexPathForCurrentTextField; |
| + |
| @end |
| @implementation PaymentRequestEditViewController |
| @@ -200,6 +228,9 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| [model addItem:headerItem toSectionWithIdentifier:SectionIdentifierHeader]; |
| } |
| + self.fieldsMap = |
| + [[NSMutableDictionary alloc] initWithCapacity:self.fields.count]; |
| + |
| // Iterate over the fields and add the respective sections and items. |
| [self.fields enumerateObjectsUsingBlock:^(EditorField* field, |
| NSUInteger index, BOOL* stop) { |
| @@ -214,6 +245,7 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| item.textFieldValue = field.value; |
| item.required = field.isRequired; |
| item.autofillUIType = field.autofillUIType; |
| + item.identifyingIcon = [_dataSource iconIdentifyingEditorFied:field]; |
| [model addItem:item toSectionWithIdentifier:sectionIdentifier]; |
| field.item = item; |
| @@ -231,14 +263,29 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| field.item = item; |
| break; |
| } |
| + case EditorFieldTypeSwitch: { |
| + CollectionViewSwitchItem* item = |
| + [[CollectionViewSwitchItem alloc] initWithType:ItemTypeSwitchField]; |
| + item.text = field.label; |
| + item.on = [field.value boolValue]; |
| + [model addItem:item toSectionWithIdentifier:sectionIdentifier]; |
| + field.item = item; |
| + break; |
| + } |
| default: |
| NOTREACHED(); |
| } |
| field.sectionIdentifier = sectionIdentifier; |
| + NSNumber* key = [NSNumber numberWithInt:sectionIdentifier]; |
| + [self.fieldsMap setObject:field forKey:key]; |
| }]; |
| - [self loadFooterItems]; |
| + [model addSectionWithIdentifier:SectionIdentifierFooter]; |
| + CollectionViewFooterItem* footerItem = |
| + [[CollectionViewFooterItem alloc] initWithType:ItemTypeFooter]; |
| + footerItem.text = l10n_util::GetNSString(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE); |
| + [model addItem:footerItem toSectionWithIdentifier:SectionIdentifierFooter]; |
| } |
| - (void)viewDidLoad { |
| @@ -257,13 +304,6 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| - (void)setEditorFields:(NSArray<EditorField*>*)fields { |
| self.fields = fields; |
| - self.fieldsMap = [[NSMutableDictionary alloc] initWithCapacity:fields.count]; |
| - // Iterate over the fields and populate the map. |
| - [self.fields enumerateObjectsUsingBlock:^(EditorField* field, |
| - NSUInteger index, BOOL* stop) { |
| - NSNumber* key = [NSNumber numberWithInt:field.autofillUIType]; |
| - [self.fieldsMap setObject:field forKey:key]; |
| - }]; |
| } |
| - (void)setOptions:(NSArray<NSString*>*)options |
| @@ -304,22 +344,18 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| - (void)textFieldDidEndEditing:(UITextField*)textField { |
| DCHECK(_currentEditingCell == AutofillEditCellForTextField(textField)); |
| - CollectionViewModel* model = self.collectionViewModel; |
| - |
| NSIndexPath* indexPath = [self indexPathForCurrentTextField]; |
| - AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( |
| - [model itemAtIndexPath:indexPath]); |
| + NSInteger sectionIdentifier = [self.collectionViewModel |
| + sectionIdentifierForSection:[indexPath section]]; |
| - // Find and validate the respective editor field. |
| - NSNumber* key = [NSNumber numberWithInt:item.autofillUIType]; |
| + // Find the respective editor field, update its value, and validate it. |
| + NSNumber* key = [NSNumber numberWithInt:sectionIdentifier]; |
| EditorField* field = self.fieldsMap[key]; |
| DCHECK(field); |
| field.value = textField.text; |
| NSString* errorMessage = |
| [_validatorDelegate paymentRequestEditViewController:self |
| validateField:field]; |
| - NSInteger sectionIdentifier = |
| - [model sectionIdentifierForSection:[indexPath section]]; |
| [self addOrRemoveErrorMessage:errorMessage |
| inSectionWithIdentifier:sectionIdentifier]; |
| @@ -338,6 +374,44 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| return NO; |
| } |
| +// This method is called as the text is being typed in, pasted, or deleted. Asks |
| +// the delegate if the text should be changed. Should always return YES. During |
| +// typing/pasting text, |newText| contains one or more new characters. When user |
| +// deletes text, |newText| is empty. |range| is the range of characters to be |
| +// replaced. |
| +- (BOOL)textField:(UITextField*)textField |
| + shouldChangeCharactersInRange:(NSRange)range |
| + replacementString:(NSString*)newText { |
| + CollectionViewModel* model = self.collectionViewModel; |
| + |
| + DCHECK(_currentEditingCell == AutofillEditCellForTextField(textField)); |
| + |
| + NSIndexPath* indexPath = [self indexPathForCurrentTextField]; |
| + NSInteger sectionIdentifier = |
| + [model sectionIdentifierForSection:[indexPath section]]; |
| + AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( |
| + [model itemAtIndexPath:indexPath]); |
| + |
| + // Find the respective editor field and update its value. |
| + NSNumber* key = [NSNumber numberWithInt:sectionIdentifier]; |
| + EditorField* field = self.fieldsMap[key]; |
| + DCHECK(field); |
| + // Obtain the text being typed. |
| + NSString* updatedText = |
| + [textField.text stringByReplacingCharactersInRange:range |
| + withString:newText]; |
| + field.value = updatedText; |
| + |
| + // Get the icon that identifies the field value and reload the cell if the |
| + // icon changes. |
| + UIImage* oldIcon = item.identifyingIcon; |
| + item.identifyingIcon = [_dataSource iconIdentifyingEditorFied:field]; |
| + if (item.identifyingIcon != oldIcon) |
| + [self reconfigureCellsForItems:@[ item ]]; |
| + |
| + return YES; |
| +} |
| + |
| #pragma mark - AutofillEditAccessoryDelegate |
| - (void)nextPressed { |
| @@ -414,6 +488,14 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| [[MDCPalette cr_bluePalette] tint600]; |
| break; |
| } |
| + case ItemTypeSwitchField: { |
| + CollectionViewSwitchCell* switchCell = |
| + base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell); |
| + [switchCell.switchView addTarget:self |
| + action:@selector(switchToggled:) |
| + forControlEvents:UIControlEventValueChanged]; |
| + break; |
| + } |
| case ItemTypeErrorMessage: { |
| PaymentsTextCell* errorMessageCell = |
| base::mac::ObjCCastStrict<PaymentsTextCell>(cell); |
| @@ -471,6 +553,7 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| case ItemTypeHeader: |
| case ItemTypeFooter: |
| case ItemTypeTextField: |
| + case ItemTypeSwitchField: |
| case ItemTypeErrorMessage: |
| return [MDCCollectionViewCell |
| cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) |
| @@ -490,6 +573,8 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| case ItemTypeHeader: |
| case ItemTypeFooter: |
| case ItemTypeErrorMessage: |
| + case ItemTypeTextField: |
| + case ItemTypeSwitchField: |
| return YES; |
| default: |
| return NO; |
| @@ -582,20 +667,6 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| } |
| } |
| -#pragma mark - Keyboard handling |
| - |
| -- (void)keyboardDidShow { |
| - [self.collectionView |
| - scrollToItemAtIndexPath:[self.collectionView |
| - indexPathForCell:_currentEditingCell] |
| - atScrollPosition:UICollectionViewScrollPositionCenteredVertically |
| - animated:YES]; |
| -} |
| - |
| -@end |
| - |
| -@implementation PaymentRequestEditViewController (Internal) |
| - |
| - (BOOL)validateForm { |
| for (EditorField* field in self.fields) { |
| NSString* errorMessage = |
| @@ -609,16 +680,6 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| return YES; |
| } |
| -- (void)loadFooterItems { |
| - CollectionViewModel* model = self.collectionViewModel; |
| - |
| - [model addSectionWithIdentifier:SectionIdentifierFooter]; |
| - CollectionViewFooterItem* footerItem = |
| - [[CollectionViewFooterItem alloc] initWithType:ItemTypeFooter]; |
| - footerItem.text = l10n_util::GetNSString(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE); |
| - [model addItem:footerItem toSectionWithIdentifier:SectionIdentifierFooter]; |
| -} |
| - |
| - (NSIndexPath*)indexPathForCurrentTextField { |
| DCHECK(_currentEditingCell); |
| NSIndexPath* indexPath = |
| @@ -627,13 +688,48 @@ typedef NS_ENUM(NSInteger, ItemType) { |
| return indexPath; |
| } |
| +#pragma mark - Keyboard handling |
| + |
| +- (void)keyboardDidShow { |
| + [self.collectionView |
| + scrollToItemAtIndexPath:[self.collectionView |
| + indexPathForCell:_currentEditingCell] |
| + atScrollPosition:UICollectionViewScrollPositionCenteredVertically |
| + animated:YES]; |
| +} |
| + |
| +#pragma mark Switch Actions |
| + |
| +- (void)switchToggled:(UISwitch*)sender { |
| + CollectionViewSwitchCell* switchCell = |
| + CollectionViewSwitchCellForSwitchField(sender); |
| + NSIndexPath* indexPath = [[self collectionView] indexPathForCell:switchCell]; |
| + DCHECK(indexPath); |
| + |
| + NSInteger sectionIdentifier = [self.collectionViewModel |
| + sectionIdentifierForSection:[indexPath section]]; |
| + |
| + // Update editor field's value. |
| + NSNumber* key = [NSNumber numberWithInt:sectionIdentifier]; |
| + EditorField* field = self.fieldsMap[key]; |
| + DCHECK(field); |
| + field.value = [sender isOn] ? @"YES" : @"NO"; |
| +} |
| + |
| #pragma mark - PaymentRequestEditViewControllerActions methods |
| - (void)onCancel { |
| + [self.delegate paymentRequestEditViewControllerDidCancel:self]; |
| } |
| - (void)onDone { |
| [_currentEditingCell.textField resignFirstResponder]; |
| + |
| + if (![self validateForm]) |
| + return; |
| + |
| + [self.delegate paymentRequestEditViewController:self |
| + didFinishEditingFields:self.fields]; |
| } |
| @end |