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

Side by Side Diff: ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm

Issue 2893353002: [Payment Request] Address edit view controller (Part 2) (Closed)
Patch Set: Initial Created 3 years, 7 months 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
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h" 5 #import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #import "base/mac/foundation_util.h" 8 #import "base/mac/foundation_util.h"
9 #include "base/strings/sys_string_conversions.h" 9 #include "base/strings/sys_string_conversions.h"
10 #include "components/strings/grit/components_strings.h" 10 #include "components/strings/grit/components_strings.h"
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 typedef NS_ENUM(NSInteger, ItemType) { 61 typedef NS_ENUM(NSInteger, ItemType) {
62 ItemTypeHeader = kItemTypeEnumZero, 62 ItemTypeHeader = kItemTypeEnumZero,
63 ItemTypeFooter, 63 ItemTypeFooter,
64 ItemTypeTextField, // This is a repeated item type. 64 ItemTypeTextField, // This is a repeated item type.
65 ItemTypeSelectorField, // This is a repeated item type. 65 ItemTypeSelectorField, // This is a repeated item type.
66 ItemTypeErrorMessage, // This is a repeated item type. 66 ItemTypeErrorMessage, // This is a repeated item type.
67 }; 67 };
68 68
69 } // namespace 69 } // namespace
70 70
71 @interface PaymentRequestEditViewController ()< 71 @interface PaymentRequestEditViewController ()<AutofillEditAccessoryDelegate,
72 AutofillEditAccessoryDelegate, 72 UITextFieldDelegate,
73 UITextFieldDelegate> { 73 UIPickerViewDataSource,
74 UIPickerViewDelegate> {
74 // The currently focused cell. May be nil. 75 // The currently focused cell. May be nil.
75 __weak AutofillEditCell* _currentEditingCell; 76 __weak AutofillEditCell* _currentEditingCell;
76 77
77 AutofillEditAccessoryView* _accessoryView; 78 AutofillEditAccessoryView* _accessoryView;
78 } 79 }
79 80
81 // The map of autofill types to the fields definitions for the editor.
82 @property(nonatomic, strong)
83 NSMutableDictionary<NSNumber*, EditorField*>* fieldsMap;
84
80 // The list of field definitions for the editor. 85 // The list of field definitions for the editor.
81 @property(nonatomic, strong) NSArray<EditorField*>* fields; 86 @property(nonatomic, strong) NSArray<EditorField*>* fields;
82 87
88 // The map of autofill types to lists of UIPickerView options.
89 @property(nonatomic, strong)
90 NSMutableDictionary<NSNumber*, NSArray<NSString*>*>* options;
91
92 // The map of autofill types to UIPickerView views.
93 @property(nonatomic, strong)
94 NSMutableDictionary<NSNumber*, UIPickerView*>* pickerViews;
95
83 // Returns the indexPath for the same row as that of |indexPath| in a section 96 // Returns the indexPath for the same row as that of |indexPath| in a section
84 // with the given offset relative to that of |indexPath|. May return nil. 97 // with the given offset relative to that of |indexPath|. May return nil.
85 - (NSIndexPath*)indexPathWithSectionOffset:(NSInteger)offset 98 - (NSIndexPath*)indexPathWithSectionOffset:(NSInteger)offset
86 fromPath:(NSIndexPath*)indexPath; 99 fromPath:(NSIndexPath*)indexPath;
87 100
88 // Returns the text field with the given offset relative to the currently 101 // Returns the text field with the given offset relative to the currently
89 // focused text field. May return nil. 102 // focused text field. May return nil.
90 - (AutofillEditCell*)nextTextFieldWithOffset:(NSInteger)offset; 103 - (AutofillEditCell*)nextTextFieldWithOffset:(NSInteger)offset;
91 104
92 // Enables or disables the accessory view's previous and next buttons depending 105 // Enables or disables the accessory view's previous and next buttons depending
93 // on whether there is a text field before and after the currently focused text 106 // on whether there is a text field before and after the currently focused text
94 // field. 107 // field.
95 - (void)updateAccessoryViewButtonsStates; 108 - (void)updateAccessoryViewButtonsStates;
96 109
97 // Adds an error message item in the section |sectionIdentifier| if 110 // Adds an error message item in the section |sectionIdentifier| if
98 // |errorMessage| is non-empty. Otherwise removes such an item if one exists. 111 // |errorMessage| is non-empty. Otherwise removes such an item if one exists.
99 - (void)addOrRemoveErrorMessage:(NSString*)errorMessage 112 - (void)addOrRemoveErrorMessage:(NSString*)errorMessage
100 inSectionWithIdentifier:(NSInteger)sectionIdentifier; 113 inSectionWithIdentifier:(NSInteger)sectionIdentifier;
101 114
102 @end 115 @end
103 116
104 @implementation PaymentRequestEditViewController 117 @implementation PaymentRequestEditViewController
105 118
106 @synthesize dataSource = _dataSource; 119 @synthesize dataSource = _dataSource;
107 @synthesize delegate = _delegate; 120 @synthesize delegate = _delegate;
108 @synthesize validatorDelegate = _validatorDelegate; 121 @synthesize validatorDelegate = _validatorDelegate;
122 @synthesize fieldsMap = _fieldsMap;
109 @synthesize fields = _fields; 123 @synthesize fields = _fields;
124 @synthesize options = _options;
125 @synthesize pickerViews = _pickerViews;
110 126
111 - (instancetype)initWithStyle:(CollectionViewControllerStyle)style { 127 - (instancetype)initWithStyle:(CollectionViewControllerStyle)style {
112 self = [super initWithStyle:style]; 128 self = [super initWithStyle:style];
113 if (self) { 129 if (self) {
114 _accessoryView = [[AutofillEditAccessoryView alloc] initWithDelegate:self]; 130 _accessoryView = [[AutofillEditAccessoryView alloc] initWithDelegate:self];
131 _options = [[NSMutableDictionary alloc] init];
132 _pickerViews = [[NSMutableDictionary alloc] init];
115 } 133 }
116 return self; 134 return self;
117 } 135 }
118 136
119 - (void)viewDidAppear:(BOOL)animated { 137 - (void)viewDidAppear:(BOOL)animated {
120 [super viewDidAppear:animated]; 138 [super viewDidAppear:animated];
121 [[NSNotificationCenter defaultCenter] 139 [[NSNotificationCenter defaultCenter]
122 addObserver:self 140 addObserver:self
123 selector:@selector(keyboardDidShow) 141 selector:@selector(keyboardDidShow)
124 name:UIKeyboardDidShowNotification 142 name:UIKeyboardDidShowNotification
125 object:nil]; 143 object:nil];
126 } 144 }
127 145
128 - (void)viewWillDisappear:(BOOL)animated { 146 - (void)viewWillDisappear:(BOOL)animated {
129 [super viewWillDisappear:animated]; 147 [super viewWillDisappear:animated];
130 [[NSNotificationCenter defaultCenter] 148 [[NSNotificationCenter defaultCenter]
131 removeObserver:self 149 removeObserver:self
132 name:UIKeyboardDidShowNotification 150 name:UIKeyboardDidShowNotification
133 object:nil]; 151 object:nil];
134 } 152 }
135 153
136 #pragma mark - CollectionViewController methods 154 #pragma mark - CollectionViewController methods
137 155
138 - (void)loadModel { 156 - (void)loadModel {
139 [super loadModel]; 157 [super loadModel];
140 CollectionViewModel* model = self.collectionViewModel; 158 CollectionViewModel* model = self.collectionViewModel;
141 159
160 [self.pickerViews removeAllObjects];
161
142 CollectionViewItem* headerItem = [_dataSource headerItem]; 162 CollectionViewItem* headerItem = [_dataSource headerItem];
143 if (headerItem) { 163 if (headerItem) {
144 [headerItem setType:ItemTypeHeader]; 164 [headerItem setType:ItemTypeHeader];
145 [model addSectionWithIdentifier:SectionIdentifierHeader]; 165 [model addSectionWithIdentifier:SectionIdentifierHeader];
146 [model addItem:headerItem toSectionWithIdentifier:SectionIdentifierHeader]; 166 [model addItem:headerItem toSectionWithIdentifier:SectionIdentifierHeader];
147 } 167 }
148 168
149 // Iterate over the fields and add the respective sections and items. 169 // Iterate over the fields and add the respective sections and items.
150 int sectionIdentifier = static_cast<int>(SectionIdentifierFirstField); 170 [self.fields enumerateObjectsUsingBlock:^(EditorField* field,
151 for (EditorField* field in self.fields) { 171 NSUInteger index, BOOL* stop) {
172 NSInteger sectionIdentifier = SectionIdentifierFirstField + index;
152 [model addSectionWithIdentifier:sectionIdentifier]; 173 [model addSectionWithIdentifier:sectionIdentifier];
153 switch (field.fieldType) { 174 switch (field.fieldType) {
154 case EditorFieldTypeTextField: { 175 case EditorFieldTypeTextField: {
155 AutofillEditItem* item = 176 AutofillEditItem* item =
156 [[AutofillEditItem alloc] initWithType:ItemTypeTextField]; 177 [[AutofillEditItem alloc] initWithType:ItemTypeTextField];
157 item.textFieldName = field.label; 178 item.textFieldName = field.label;
158 item.textFieldEnabled = YES; 179 item.textFieldEnabled = field.enabled;
159 item.textFieldValue = field.value; 180 item.textFieldValue = field.value;
160 item.required = field.isRequired; 181 item.required = field.isRequired;
161 item.autofillUIType = field.autofillUIType; 182 item.autofillUIType = field.autofillUIType;
162 [model addItem:item 183 [model addItem:item toSectionWithIdentifier:sectionIdentifier];
163 toSectionWithIdentifier:static_cast<NSInteger>(sectionIdentifier)];
164 field.item = item; 184 field.item = item;
185
165 break; 186 break;
166 } 187 }
167 case EditorFieldTypeSelector: { 188 case EditorFieldTypeSelector: {
168 PaymentsSelectorEditItem* item = [[PaymentsSelectorEditItem alloc] 189 PaymentsSelectorEditItem* item = [[PaymentsSelectorEditItem alloc]
169 initWithType:ItemTypeSelectorField]; 190 initWithType:ItemTypeSelectorField];
170 item.name = field.label; 191 item.name = field.label;
171 item.value = field.displayValue; 192 item.value = field.displayValue;
172 item.required = field.isRequired; 193 item.required = field.isRequired;
173 item.autofillUIType = field.autofillUIType; 194 item.autofillUIType = field.autofillUIType;
174 item.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator; 195 item.accessoryType = MDCCollectionViewCellAccessoryDisclosureIndicator;
175 [model addItem:item 196 [model addItem:item toSectionWithIdentifier:sectionIdentifier];
176 toSectionWithIdentifier:static_cast<NSInteger>(sectionIdentifier)];
177 field.item = item; 197 field.item = item;
178 break; 198 break;
179 } 199 }
180 default: 200 default:
181 NOTREACHED(); 201 NOTREACHED();
182 } 202 }
183 203
184 field.sectionIdentifier = static_cast<NSInteger>(sectionIdentifier); 204 field.sectionIdentifier = sectionIdentifier;
185 ++sectionIdentifier; 205 }];
186 }
187 206
188 [self loadFooterItems]; 207 [self loadFooterItems];
189 } 208 }
190 209
191 - (void)viewDidLoad { 210 - (void)viewDidLoad {
192 [super viewDidLoad]; 211 [super viewDidLoad];
193 212
194 self.collectionView.accessibilityIdentifier = 213 self.collectionView.accessibilityIdentifier =
195 kPaymentRequestEditCollectionViewAccessibilityID; 214 kPaymentRequestEditCollectionViewAccessibilityID;
196 215
197 // Customize collection view settings. 216 // Customize collection view settings.
198 self.styler.cellStyle = MDCCollectionViewCellStyleCard; 217 self.styler.cellStyle = MDCCollectionViewCellStyleCard;
199 self.styler.separatorInset = 218 self.styler.separatorInset =
200 UIEdgeInsetsMake(0, kSeparatorEdgeInset, 0, kSeparatorEdgeInset); 219 UIEdgeInsetsMake(0, kSeparatorEdgeInset, 0, kSeparatorEdgeInset);
201 } 220 }
202 221
203 #pragma mark - PaymentRequestEditConsumer 222 #pragma mark - PaymentRequestEditConsumer
204 223
205 - (void)setEditorFields:(NSArray<EditorField*>*)fields { 224 - (void)setEditorFields:(NSArray<EditorField*>*)fields {
206 self.fields = fields; 225 self.fields = fields;
226 self.fieldsMap = [[NSMutableDictionary alloc] initWithCapacity:fields.count];
227 // Iterate over the fields and populate the map.
228 [self.fields enumerateObjectsUsingBlock:^(EditorField* field,
229 NSUInteger index, BOOL* stop) {
230 NSNumber* key = [NSNumber numberWithInt:field.autofillUIType];
231 [self.fieldsMap setObject:field forKey:key];
232 }];
233 }
234
235 - (void)setOptions:(NSArray<NSString*>*)options
236 forEditorField:(EditorField*)field {
237 DCHECK(field.fieldType == EditorFieldTypeTextField);
238 AutofillEditItem* item =
239 base::mac::ObjCCastStrict<AutofillEditItem>(field.item);
240
241 // Enable the previously disabled text field and reset its value.
242 item.textFieldEnabled = YES;
243 item.textFieldValue = nil;
244
245 // Cache the options if there are any and set the text field's UIPickerView.
246 if (options.count) {
247 NSNumber* key = [NSNumber numberWithInt:field.autofillUIType];
248 [self.options setObject:options forKey:key];
249
250 UIPickerView* pickerView = [[UIPickerView alloc] initWithFrame:CGRectZero];
251 pickerView.delegate = self;
252 pickerView.dataSource = self;
253 [self.pickerViews setObject:pickerView forKey:key];
254 item.inputView = pickerView;
255 }
256
257 // Reload the item.
258 NSIndexPath* indexPath =
259 [self.collectionViewModel indexPathForItemType:ItemTypeTextField
260 sectionIdentifier:field.sectionIdentifier];
261 [self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]];
207 } 262 }
208 263
209 #pragma mark - UITextFieldDelegate 264 #pragma mark - UITextFieldDelegate
210 265
211 - (void)textFieldDidBeginEditing:(UITextField*)textField { 266 - (void)textFieldDidBeginEditing:(UITextField*)textField {
212 _currentEditingCell = AutofillEditCellForTextField(textField); 267 _currentEditingCell = AutofillEditCellForTextField(textField);
213 [textField setInputAccessoryView:_accessoryView]; 268 [textField setInputAccessoryView:_accessoryView];
214 [self updateAccessoryViewButtonsStates]; 269 [self updateAccessoryViewButtonsStates];
215 } 270 }
216 271
217 - (void)textFieldDidEndEditing:(UITextField*)textField { 272 - (void)textFieldDidEndEditing:(UITextField*)textField {
218 DCHECK(_currentEditingCell == AutofillEditCellForTextField(textField)); 273 DCHECK(_currentEditingCell == AutofillEditCellForTextField(textField));
219 274
220 // Validate the text field.
221 CollectionViewModel* model = self.collectionViewModel; 275 CollectionViewModel* model = self.collectionViewModel;
222 276
223 NSIndexPath* indexPath = [self indexPathForCurrentTextField]; 277 NSIndexPath* indexPath = [self indexPathForCurrentTextField];
224 AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( 278 AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>(
225 [model itemAtIndexPath:indexPath]); 279 [model itemAtIndexPath:indexPath]);
226 280
227 // Create a dummy EditorField for validation only. 281 // Find and validate the respective editor field.
228 EditorField* fieldForValidation = 282 NSNumber* key = [NSNumber numberWithInt:item.autofillUIType];
229 [[EditorField alloc] initWithAutofillUIType:item.autofillUIType 283 EditorField* field = self.fieldsMap[key];
230 fieldType:EditorFieldTypeTextField 284 DCHECK(field);
231 label:nil 285 field.value = textField.text;
232 value:textField.text
233 required:item.required];
234 NSString* errorMessage = 286 NSString* errorMessage =
235 [_validatorDelegate paymentRequestEditViewController:self 287 [_validatorDelegate paymentRequestEditViewController:self
236 validateField:fieldForValidation]; 288 validateField:field];
237 NSInteger sectionIdentifier = 289 NSInteger sectionIdentifier =
238 [model sectionIdentifierForSection:[indexPath section]]; 290 [model sectionIdentifierForSection:[indexPath section]];
239 [self addOrRemoveErrorMessage:errorMessage 291 [self addOrRemoveErrorMessage:errorMessage
240 inSectionWithIdentifier:sectionIdentifier]; 292 inSectionWithIdentifier:sectionIdentifier];
241 293
242 [textField setInputAccessoryView:nil]; 294 [textField setInputAccessoryView:nil];
243 _currentEditingCell = nil; 295 _currentEditingCell = nil;
244 } 296 }
245 297
246 - (BOOL)textFieldShouldReturn:(UITextField*)textField { 298 - (BOOL)textFieldShouldReturn:(UITextField*)textField {
(...skipping 18 matching lines...) Expand all
265 - (void)previousPressed { 317 - (void)previousPressed {
266 AutofillEditCell* previousCell = [self nextTextFieldWithOffset:-1]; 318 AutofillEditCell* previousCell = [self nextTextFieldWithOffset:-1];
267 if (previousCell) 319 if (previousCell)
268 [previousCell.textField becomeFirstResponder]; 320 [previousCell.textField becomeFirstResponder];
269 } 321 }
270 322
271 - (void)closePressed { 323 - (void)closePressed {
272 [[_currentEditingCell textField] resignFirstResponder]; 324 [[_currentEditingCell textField] resignFirstResponder];
273 } 325 }
274 326
327 #pragma mark - UIPickerViewDataSource methods
328
329 - (NSInteger)numberOfComponentsInPickerView:(UIPickerView*)thePickerView {
330 return 1;
331 }
332
333 - (NSInteger)pickerView:(UIPickerView*)thePickerView
334 numberOfRowsInComponent:(NSInteger)component {
335 NSArray<NSNumber*>* indices =
336 [self.pickerViews allKeysForObject:thePickerView];
337 DCHECK(indices.count == 1);
338 NSArray<NSString*>* options = self.options[indices[0]];
339 return options.count;
340 }
341
342 #pragma mark - UIPickerViewDelegate methods
343
344 - (NSString*)pickerView:(UIPickerView*)thePickerView
345 titleForRow:(NSInteger)row
346 forComponent:(NSInteger)component {
347 NSArray<NSNumber*>* indices =
348 [self.pickerViews allKeysForObject:thePickerView];
349 DCHECK(indices.count == 1);
350 NSArray<NSString*>* options = self.options[indices[0]];
351 DCHECK(row < static_cast<NSInteger>(options.count));
352 return options[row];
353 }
354
355 - (void)pickerView:(UIPickerView*)thePickerView
356 didSelectRow:(NSInteger)row
357 inComponent:(NSInteger)component {
358 DCHECK(_currentEditingCell);
359 _currentEditingCell.textField.text =
360 [self pickerView:thePickerView titleForRow:row forComponent:component];
361 }
362
275 #pragma mark - UICollectionViewDataSource 363 #pragma mark - UICollectionViewDataSource
276 364
277 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView 365 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
278 cellForItemAtIndexPath:(NSIndexPath*)indexPath { 366 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
279 UICollectionViewCell* cell = 367 UICollectionViewCell* cell =
280 [super collectionView:collectionView cellForItemAtIndexPath:indexPath]; 368 [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
281 369
282 CollectionViewItem* item = 370 CollectionViewItem* item =
283 [self.collectionViewModel itemAtIndexPath:indexPath]; 371 [self.collectionViewModel itemAtIndexPath:indexPath];
284 switch (item.type) { 372 switch (item.type) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 [super collectionView:collectionView didSelectItemAtIndexPath:indexPath]; 413 [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
326 414
327 // Every field has its own section. Find out which field is selected using 415 // Every field has its own section. Find out which field is selected using
328 // the section of |indexPath|. Adjust the index if a header section is 416 // the section of |indexPath|. Adjust the index if a header section is
329 // present before the editor fields. 417 // present before the editor fields.
330 NSInteger index = indexPath.section; 418 NSInteger index = indexPath.section;
331 if ([self.collectionViewModel 419 if ([self.collectionViewModel
332 hasSectionForSectionIdentifier:SectionIdentifierHeader]) 420 hasSectionForSectionIdentifier:SectionIdentifierHeader])
333 index--; 421 index--;
334 DCHECK(index >= 0 && index < static_cast<NSInteger>(self.fields.count)); 422 DCHECK(index >= 0 && index < static_cast<NSInteger>(self.fields.count));
335 [_delegate 423 EditorField* field = [self.fields objectAtIndex:index];
336 paymentRequestEditViewController:self 424
337 didSelectField:[self.fields objectAtIndex:index]]; 425 // If a selector field is selected, blur the focused text field.
426 if (field.fieldType == EditorFieldTypeSelector)
427 [[_currentEditingCell textField] resignFirstResponder];
428
429 [_delegate paymentRequestEditViewController:self didSelectField:field];
338 } 430 }
339 431
340 #pragma mark MDCCollectionViewStylingDelegate 432 #pragma mark MDCCollectionViewStylingDelegate
341 433
342 - (CGFloat)collectionView:(UICollectionView*)collectionView 434 - (CGFloat)collectionView:(UICollectionView*)collectionView
343 cellHeightAtIndexPath:(NSIndexPath*)indexPath { 435 cellHeightAtIndexPath:(NSIndexPath*)indexPath {
344 CollectionViewItem* item = 436 CollectionViewItem* item =
345 [self.collectionViewModel itemAtIndexPath:indexPath]; 437 [self.collectionViewModel itemAtIndexPath:indexPath];
346 switch (item.type) { 438 switch (item.type) {
347 case ItemTypeHeader: 439 case ItemTypeHeader:
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
513 605
514 - (NSIndexPath*)indexPathForCurrentTextField { 606 - (NSIndexPath*)indexPathForCurrentTextField {
515 DCHECK(_currentEditingCell); 607 DCHECK(_currentEditingCell);
516 NSIndexPath* indexPath = 608 NSIndexPath* indexPath =
517 [[self collectionView] indexPathForCell:_currentEditingCell]; 609 [[self collectionView] indexPathForCell:_currentEditingCell];
518 DCHECK(indexPath); 610 DCHECK(indexPath);
519 return indexPath; 611 return indexPath;
520 } 612 }
521 613
522 @end 614 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698