Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #import "ios/chrome/browser/payments/payment_request_edit_view_controller.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #import "base/mac/foundation_util.h" | |
| 9 #include "base/strings/sys_string_conversions.h" | |
| 10 #include "components/autofill/core/browser/field_types.h" | |
| 11 #include "components/strings/grit/components_strings.h" | |
| 12 #import "ios/chrome/browser/payments/cells/payments_text_item.h" | |
| 13 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrom e.h" | |
| 14 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item .h" | |
| 15 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" | |
| 16 #import "ios/chrome/browser/ui/settings/autofill_edit_accessory_view.h" | |
| 17 #import "ios/chrome/browser/ui/uikit_ui_util.h" | |
| 18 #include "ios/chrome/grit/ios_theme_resources.h" | |
| 19 #import "ios/third_party/material_components_ios/src/components/Typography/src/M aterialTypography.h" | |
| 20 #include "ui/base/l10n/l10n_util.h" | |
| 21 | |
| 22 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
| 23 #error "This file requires ARC support." | |
| 24 #endif | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 NSString* const kPaymentRequestEditCollectionViewID = | |
| 29 @"kPaymentRequestEditCollectionViewID"; | |
| 30 | |
| 31 const CGFloat kSeparatorEdgeInset = 14; | |
| 32 | |
| 33 const CGFloat kFooterCellHorizontalPadding = 16; | |
| 34 | |
| 35 AutofillEditCell* AutofillEditCellForTextField(UITextField* textField) { | |
| 36 for (UIView* view = textField; view; view = [view superview]) { | |
| 37 AutofillEditCell* cell = base::mac::ObjCCast<AutofillEditCell>(view); | |
| 38 if (cell) | |
| 39 return cell; | |
| 40 } | |
| 41 | |
| 42 // There has to be a cell associated with this text field. | |
| 43 NOTREACHED(); | |
| 44 return nil; | |
| 45 } | |
| 46 | |
| 47 typedef NS_ENUM(NSInteger, SectionIdentifier) { | |
| 48 SectionIdentifierFooter = kSectionIdentifierEnumZero, | |
| 49 SectionIdentifierFirstTextField, | |
| 50 }; | |
| 51 | |
| 52 typedef NS_ENUM(NSInteger, ItemType) { | |
| 53 ItemTypeFooter = kItemTypeEnumZero, | |
| 54 ItemTypeTextField, // This is a repeated item type. | |
| 55 ItemTypeErrorMessage, // This is a repeated item type. | |
| 56 }; | |
| 57 | |
| 58 } // namespace | |
| 59 | |
| 60 @implementation EditorField | |
| 61 | |
| 62 @synthesize autofillType = _autofillType; | |
| 63 @synthesize label = _label; | |
| 64 @synthesize value = _value; | |
| 65 @synthesize required = _required; | |
| 66 @synthesize item = _item; | |
| 67 @synthesize sectionIdentifier = _sectionIdentifier; | |
| 68 | |
| 69 - (instancetype)initWithAutofillType:(NSInteger)autofillType | |
| 70 label:(NSString*)label | |
| 71 value:(NSString*)value | |
| 72 required:(BOOL)required { | |
| 73 self = [super init]; | |
| 74 if (self) { | |
| 75 _autofillType = autofillType; | |
| 76 _label = label; | |
| 77 _value = value; | |
| 78 _required = required; | |
| 79 } | |
| 80 return self; | |
| 81 } | |
| 82 | |
| 83 @end | |
| 84 | |
| 85 @interface PaymentRequestEditViewController ()<AutofillEditAccessoryDelegate> { | |
| 86 UIBarButtonItem* _cancelButton; | |
|
lpromero
2017/03/22 10:51:33
I don't think you need ivars.
Moe
2017/03/22 17:54:32
Done.
| |
| 87 UIBarButtonItem* _doneButton; | |
| 88 | |
| 89 NSArray<EditorField*>* _fields; | |
| 90 | |
| 91 // The currently focused cell. May be nil. | |
| 92 __weak AutofillEditCell* _currentEditingCell; | |
| 93 | |
| 94 AutofillEditAccessoryView* _accessoryView; | |
| 95 } | |
| 96 | |
| 97 // Returns the indexPath for the same row as that of |indexPath| in a section | |
| 98 // with the given offset relative to that of |indexPath|. May return nil. | |
| 99 - (NSIndexPath*)indexPathWithSectionOffset:(NSInteger)offset | |
| 100 fromPath:(NSIndexPath*)indexPath; | |
| 101 | |
| 102 // Returns the text field with the given offset relative to the currently | |
| 103 // focused text field. May return nil. | |
| 104 - (AutofillEditCell*)nextTextFieldWithOffset:(NSInteger)offset; | |
| 105 | |
| 106 // Enables or disables the accessory view's previous and next buttons depending | |
| 107 // on whether there is a text field before and after the currently focused text | |
| 108 // field. | |
| 109 - (void)updateAccessoryViewButtonsStates; | |
| 110 | |
| 111 @end | |
| 112 | |
| 113 @implementation PaymentRequestEditViewController | |
| 114 | |
| 115 @synthesize editorDelegate = _editorDelegate; | |
| 116 @synthesize validatorDelegate = _validatorDelegate; | |
| 117 | |
| 118 - (instancetype)initWithEditorFields:(NSArray<EditorField*>*)fields { | |
| 119 self = [super initWithStyle:CollectionViewControllerStyleAppBar]; | |
| 120 if (self) { | |
| 121 _fields = fields; | |
| 122 | |
| 123 // Set self as the validator delegate. | |
| 124 _validatorDelegate = self; | |
| 125 | |
| 126 // Set up leading (cancel) button. | |
| 127 _cancelButton = [[UIBarButtonItem alloc] | |
| 128 initWithTitle:l10n_util::GetNSString(IDS_CANCEL) | |
| 129 style:UIBarButtonItemStylePlain | |
| 130 target:nil | |
| 131 action:@selector(onReturn)]; | |
| 132 [_cancelButton setTitleTextAttributes:@{ | |
| 133 NSForegroundColorAttributeName : [UIColor lightGrayColor] | |
| 134 } | |
| 135 forState:UIControlStateDisabled]; | |
| 136 [_cancelButton | |
| 137 setAccessibilityLabel:l10n_util::GetNSString(IDS_ACCNAME_CANCEL)]; | |
| 138 [self navigationItem].leftBarButtonItem = _cancelButton; | |
| 139 | |
| 140 // Set up trailing (done) button. | |
| 141 _doneButton = | |
| 142 [[UIBarButtonItem alloc] initWithTitle:l10n_util::GetNSString(IDS_DONE) | |
| 143 style:UIBarButtonItemStylePlain | |
| 144 target:nil | |
| 145 action:@selector(onDone)]; | |
| 146 [_doneButton setTitleTextAttributes:@{ | |
| 147 NSForegroundColorAttributeName : [UIColor lightGrayColor] | |
| 148 } | |
| 149 forState:UIControlStateDisabled]; | |
| 150 [_doneButton | |
| 151 setAccessibilityLabel:l10n_util::GetNSString(IDS_ACCNAME_DONE)]; | |
| 152 [self navigationItem].rightBarButtonItem = _doneButton; | |
| 153 | |
| 154 _accessoryView = [[AutofillEditAccessoryView alloc] initWithDelegate:self]; | |
|
lpromero
2017/03/22 10:51:33
You could also load the model, since it only needs
Moe
2017/03/22 17:54:32
Good point. For consistency with the other view co
| |
| 155 } | |
| 156 return self; | |
| 157 } | |
| 158 | |
| 159 #pragma mark - PaymentRequestEditViewControllerActions methods | |
| 160 | |
| 161 - (void)onReturn { | |
| 162 [_editorDelegate paymentRequestEditViewControllerDidReturn:self]; | |
| 163 } | |
| 164 | |
| 165 - (void)onDone { | |
| 166 if ([self validateForm]) { | |
| 167 [_editorDelegate paymentRequestEditViewController:self | |
| 168 didFinishEditingFields:_fields]; | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 - (void)viewDidAppear:(BOOL)animated { | |
| 173 [super viewDidAppear:animated]; | |
| 174 [[NSNotificationCenter defaultCenter] | |
| 175 addObserver:self | |
| 176 selector:@selector(keyboardDidShow) | |
| 177 name:UIKeyboardDidShowNotification | |
| 178 object:nil]; | |
| 179 } | |
| 180 | |
| 181 - (void)viewWillDisappear:(BOOL)animated { | |
| 182 [super viewWillDisappear:animated]; | |
| 183 [[NSNotificationCenter defaultCenter] | |
| 184 removeObserver:self | |
| 185 name:UIKeyboardDidShowNotification | |
| 186 object:nil]; | |
| 187 } | |
| 188 | |
| 189 #pragma mark - CollectionViewController methods | |
| 190 | |
| 191 - (void)loadModel { | |
| 192 [super loadModel]; | |
| 193 CollectionViewModel* model = self.collectionViewModel; | |
| 194 | |
| 195 // Iterate over the fields and add the respective sections and items. | |
| 196 int sectionIdentifier = static_cast<int>(SectionIdentifierFirstTextField); | |
| 197 for (EditorField* field in _fields) { | |
| 198 [model addSectionWithIdentifier:sectionIdentifier]; | |
| 199 AutofillEditItem* item = | |
| 200 [[AutofillEditItem alloc] initWithType:ItemTypeTextField]; | |
| 201 item.textFieldName = field.label; | |
| 202 item.textFieldEnabled = YES; | |
| 203 item.textFieldValue = field.value; | |
| 204 item.required = field.isRequired; | |
| 205 item.autofillType = | |
| 206 static_cast<autofill::ServerFieldType>(field.autofillType); | |
| 207 [model addItem:item | |
| 208 toSectionWithIdentifier:static_cast<NSInteger>(sectionIdentifier)]; | |
| 209 field.item = item; | |
| 210 field.sectionIdentifier = static_cast<NSInteger>(sectionIdentifier++); | |
|
lpromero
2017/03/22 10:51:33
Move the sectionIdentifier incrementation to its o
Moe
2017/03/22 17:54:32
Done.
| |
| 211 } | |
| 212 | |
| 213 [self loadFooterItems]; | |
| 214 } | |
| 215 | |
| 216 - (void)viewDidLoad { | |
| 217 [super viewDidLoad]; | |
| 218 | |
| 219 self.collectionView.accessibilityIdentifier = | |
| 220 kPaymentRequestEditCollectionViewID; | |
| 221 | |
| 222 // Customize collection view settings. | |
| 223 self.styler.cellStyle = MDCCollectionViewCellStyleCard; | |
| 224 self.styler.separatorInset = | |
| 225 UIEdgeInsetsMake(0, kSeparatorEdgeInset, 0, kSeparatorEdgeInset); | |
| 226 } | |
| 227 | |
| 228 #pragma mark - UITextFieldDelegate | |
| 229 | |
| 230 - (void)textFieldDidBeginEditing:(UITextField*)textField { | |
| 231 _currentEditingCell = AutofillEditCellForTextField(textField); | |
| 232 [textField setInputAccessoryView:_accessoryView]; | |
| 233 [self updateAccessoryViewButtonsStates]; | |
| 234 } | |
| 235 | |
| 236 - (void)textFieldDidEndEditing:(UITextField*)textField { | |
| 237 DCHECK(_currentEditingCell == AutofillEditCellForTextField(textField)); | |
| 238 | |
| 239 // Validate the text field. | |
| 240 CollectionViewModel* model = self.collectionViewModel; | |
| 241 | |
| 242 NSIndexPath* indexPath = [self indexPathForCurrentTextField]; | |
| 243 AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( | |
| 244 [model itemAtIndexPath:indexPath]); | |
| 245 | |
| 246 NSString* errorMessage = | |
| 247 [_validatorDelegate paymentRequestEditViewController:self | |
| 248 validateValue:textField.text | |
| 249 autofillType:item.autofillType | |
| 250 required:item.required]; | |
| 251 NSInteger sectionIdentifier = | |
| 252 [model sectionIdentifierForSection:[indexPath section]]; | |
| 253 [self addOrRemoveErrorMessage:errorMessage | |
| 254 inSectionWithIdentifier:sectionIdentifier]; | |
| 255 | |
| 256 [textField setInputAccessoryView:nil]; | |
| 257 _currentEditingCell = nil; | |
| 258 } | |
| 259 | |
| 260 - (BOOL)textFieldShouldReturn:(UITextField*)textField { | |
| 261 DCHECK([_currentEditingCell textField] == textField); | |
| 262 [self nextPressed]; | |
| 263 return NO; | |
|
lpromero
2017/03/22 10:51:33
Seems like this means that when returning from the
Moe
2017/03/22 17:54:32
Oh it probably is. Changed it to dismiss the keybo
| |
| 264 } | |
| 265 | |
| 266 #pragma mark - AutofillEditAccessoryDelegate | |
| 267 | |
| 268 - (void)nextPressed { | |
| 269 AutofillEditCell* nextCell = [self nextTextFieldWithOffset:1]; | |
| 270 if (nextCell) | |
| 271 [nextCell.textField becomeFirstResponder]; | |
| 272 } | |
| 273 | |
| 274 - (void)previousPressed { | |
| 275 AutofillEditCell* previousCell = [self nextTextFieldWithOffset:-1]; | |
| 276 if (previousCell) | |
| 277 [previousCell.textField becomeFirstResponder]; | |
| 278 } | |
| 279 | |
| 280 - (void)closePressed { | |
| 281 [[_currentEditingCell textField] resignFirstResponder]; | |
| 282 } | |
| 283 | |
| 284 #pragma mark - UICollectionViewDataSource | |
| 285 | |
| 286 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView | |
| 287 cellForItemAtIndexPath:(NSIndexPath*)indexPath { | |
| 288 UICollectionViewCell* cell = | |
| 289 [super collectionView:collectionView cellForItemAtIndexPath:indexPath]; | |
| 290 | |
| 291 if ([cell isKindOfClass:[AutofillEditCell class]]) { | |
|
lpromero
2017/03/22 10:51:33
Instead of checking the cell class, why don't you
Moe
2017/03/22 17:54:32
Actually I forgot to update this after making the
| |
| 292 AutofillEditCell* autofillEditCell = | |
| 293 base::mac::ObjCCast<AutofillEditCell>(cell); | |
|
lpromero
2017/03/22 10:51:33
Use ObjCCastStrict, since you checked the class.
Moe
2017/03/22 17:54:32
Acknowledged.
| |
| 294 autofillEditCell.textField.delegate = self; | |
| 295 autofillEditCell.textField.clearButtonMode = UITextFieldViewModeNever; | |
| 296 autofillEditCell.textLabel.font = [MDCTypography body2Font]; | |
| 297 autofillEditCell.textLabel.textColor = [[MDCPalette greyPalette] tint900]; | |
| 298 autofillEditCell.textField.font = [MDCTypography body1Font]; | |
| 299 autofillEditCell.textField.textColor = | |
| 300 [[MDCPalette cr_bluePalette] tint600]; | |
| 301 } | |
| 302 | |
| 303 CollectionViewItem* item = | |
| 304 [self.collectionViewModel itemAtIndexPath:indexPath]; | |
| 305 switch (item.type) { | |
| 306 case ItemTypeErrorMessage: { | |
| 307 PaymentsTextCell* errorMessageCell = | |
| 308 base::mac::ObjCCastStrict<PaymentsTextCell>(cell); | |
| 309 errorMessageCell.textLabel.font = [MDCTypography body1Font]; | |
| 310 errorMessageCell.textLabel.textColor = | |
| 311 [[MDCPalette cr_redPalette] tint600]; | |
| 312 break; | |
| 313 } | |
| 314 case ItemTypeFooter: { | |
| 315 CollectionViewFooterCell* footerCell = | |
| 316 base::mac::ObjCCastStrict<CollectionViewFooterCell>(cell); | |
| 317 footerCell.textLabel.font = [MDCTypography body2Font]; | |
| 318 footerCell.textLabel.textColor = [[MDCPalette greyPalette] tint600]; | |
| 319 footerCell.textLabel.shadowColor = nil; // No shadow. | |
| 320 footerCell.horizontalPadding = kFooterCellHorizontalPadding; | |
| 321 break; | |
| 322 } | |
| 323 default: | |
| 324 break; | |
| 325 } | |
| 326 | |
| 327 return cell; | |
| 328 } | |
| 329 | |
| 330 #pragma mark MDCCollectionViewStylingDelegate | |
| 331 | |
| 332 - (CGFloat)collectionView:(UICollectionView*)collectionView | |
| 333 cellHeightAtIndexPath:(NSIndexPath*)indexPath { | |
| 334 CollectionViewItem* item = | |
| 335 [self.collectionViewModel itemAtIndexPath:indexPath]; | |
| 336 | |
| 337 if ([item isKindOfClass:[AutofillEditItem class]] || | |
| 338 item.type == ItemTypeErrorMessage || item.type == ItemTypeFooter) { | |
| 339 return [MDCCollectionViewCell | |
|
lpromero
2017/03/22 10:51:33
Seems safe to always return cr_preferred. I am thi
Moe
2017/03/22 17:54:32
Yep. return MDCCellDefaultOneLineHeight; shouldn't
| |
| 340 cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) | |
| 341 forItem:item]; | |
| 342 } | |
| 343 | |
| 344 NOTREACHED(); | |
| 345 return MDCCellDefaultOneLineHeight; | |
| 346 } | |
| 347 | |
| 348 - (BOOL)collectionView:(UICollectionView*)collectionView | |
| 349 hidesInkViewAtIndexPath:(NSIndexPath*)indexPath { | |
| 350 NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; | |
| 351 switch (type) { | |
| 352 case ItemTypeErrorMessage: | |
| 353 case ItemTypeFooter: | |
| 354 return YES; | |
| 355 default: | |
| 356 return NO; | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 - (BOOL)collectionView:(UICollectionView*)collectionView | |
| 361 shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath { | |
| 362 NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; | |
| 363 switch (type) { | |
| 364 case ItemTypeFooter: | |
| 365 return YES; | |
| 366 default: | |
| 367 return NO; | |
| 368 } | |
| 369 } | |
| 370 | |
| 371 #pragma mark - Protected methods | |
| 372 | |
| 373 - (BOOL)validateForm { | |
| 374 for (EditorField* field in _fields) { | |
| 375 AutofillEditItem* item = field.item; | |
| 376 | |
| 377 NSString* errorMessage = | |
| 378 [_validatorDelegate paymentRequestEditViewController:self | |
| 379 validateValue:item.textFieldValue | |
| 380 autofillType:field.autofillType | |
| 381 required:field.isRequired]; | |
| 382 [self addOrRemoveErrorMessage:errorMessage | |
| 383 inSectionWithIdentifier:field.sectionIdentifier]; | |
| 384 if (errorMessage.length != 0) { | |
| 385 return NO; | |
| 386 } | |
| 387 | |
| 388 field.value = item.textFieldValue; | |
| 389 } | |
| 390 return YES; | |
| 391 } | |
| 392 | |
| 393 - (void)loadFooterItems { | |
| 394 CollectionViewModel* model = self.collectionViewModel; | |
| 395 | |
| 396 [model addSectionWithIdentifier:SectionIdentifierFooter]; | |
| 397 CollectionViewFooterItem* footerItem = | |
| 398 [[CollectionViewFooterItem alloc] initWithType:ItemTypeFooter]; | |
| 399 footerItem.text = l10n_util::GetNSString(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE); | |
| 400 [model addItem:footerItem toSectionWithIdentifier:SectionIdentifierFooter]; | |
| 401 } | |
| 402 | |
| 403 - (NSIndexPath*)indexPathForCurrentTextField { | |
| 404 DCHECK(_currentEditingCell); | |
| 405 NSIndexPath* indexPath = | |
| 406 [[self collectionView] indexPathForCell:_currentEditingCell]; | |
| 407 DCHECK(indexPath); | |
| 408 return indexPath; | |
| 409 } | |
| 410 | |
| 411 - (void)addOrRemoveErrorMessage:(NSString*)errorMessage | |
| 412 inSectionWithIdentifier:(NSInteger)sectionIdentifier { | |
| 413 CollectionViewModel* model = self.collectionViewModel; | |
| 414 if ([model hasItemForItemType:ItemTypeErrorMessage | |
| 415 sectionIdentifier:sectionIdentifier]) { | |
| 416 NSIndexPath* indexPath = [model indexPathForItemType:ItemTypeErrorMessage | |
| 417 sectionIdentifier:sectionIdentifier]; | |
| 418 if (errorMessage.length == 0) { | |
| 419 // Remove the item at the index path. | |
| 420 [model removeItemWithType:ItemTypeErrorMessage | |
| 421 fromSectionWithIdentifier:sectionIdentifier]; | |
| 422 [self.collectionView deleteItemsAtIndexPaths:@[ indexPath ]]; | |
| 423 } else { | |
| 424 // Reload the item at the index path. | |
| 425 PaymentsTextItem* item = base::mac::ObjCCastStrict<PaymentsTextItem>( | |
| 426 [model itemAtIndexPath:indexPath]); | |
| 427 item.text = errorMessage; | |
| 428 [self.collectionView reloadItemsAtIndexPaths:@[ indexPath ]]; | |
| 429 } | |
| 430 } else if (errorMessage.length != 0) { | |
| 431 // Insert an item at the index path. | |
| 432 PaymentsTextItem* errorMessageItem = | |
| 433 [[PaymentsTextItem alloc] initWithType:ItemTypeErrorMessage]; | |
| 434 errorMessageItem.text = errorMessage; | |
| 435 errorMessageItem.image = NativeImage(IDR_IOS_PAYMENTS_WARNING); | |
| 436 [model addItem:errorMessageItem toSectionWithIdentifier:sectionIdentifier]; | |
| 437 NSIndexPath* indexPath = [model indexPathForItemType:ItemTypeErrorMessage | |
| 438 sectionIdentifier:sectionIdentifier]; | |
| 439 [self.collectionView insertItemsAtIndexPaths:@[ indexPath ]]; | |
| 440 } | |
| 441 } | |
| 442 | |
| 443 #pragma mark - PaymentRequestEditViewControllerValidator | |
| 444 | |
| 445 - (NSString*)paymentRequestEditViewController: | |
| 446 (PaymentRequestEditViewController*)controller | |
| 447 validateValue:(NSString*)value | |
| 448 autofillType:(NSInteger)autofillType | |
| 449 required:(BOOL)required { | |
| 450 if (required && value.length == 0) { | |
| 451 return l10n_util::GetNSString( | |
| 452 IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE); | |
| 453 } | |
| 454 return @""; | |
| 455 } | |
| 456 | |
| 457 #pragma mark - Helper methods | |
| 458 | |
| 459 - (NSIndexPath*)indexPathWithSectionOffset:(NSInteger)offset | |
| 460 fromPath:(NSIndexPath*)indexPath { | |
| 461 DCHECK(indexPath); | |
| 462 DCHECK(offset); | |
| 463 NSInteger nextSection = [indexPath section] + offset; | |
| 464 if (nextSection >= 0 && | |
| 465 nextSection < [[self collectionView] numberOfSections]) { | |
| 466 return [NSIndexPath indexPathForRow:[indexPath row] inSection:nextSection]; | |
| 467 } | |
| 468 return nil; | |
| 469 } | |
| 470 | |
| 471 - (AutofillEditCell*)nextTextFieldWithOffset:(NSInteger)offset { | |
| 472 UICollectionView* collectionView = [self collectionView]; | |
| 473 NSIndexPath* currentCellPath = [self indexPathForCurrentTextField]; | |
| 474 DCHECK(currentCellPath); | |
| 475 NSIndexPath* nextCellPath = | |
| 476 [self indexPathWithSectionOffset:offset fromPath:currentCellPath]; | |
| 477 if (nextCellPath) { | |
| 478 id nextCell = [collectionView cellForItemAtIndexPath:nextCellPath]; | |
| 479 if ([nextCell isKindOfClass:[AutofillEditCell class]]) { | |
| 480 return base::mac::ObjCCastStrict<AutofillEditCell>( | |
| 481 [collectionView cellForItemAtIndexPath:nextCellPath]); | |
| 482 } | |
| 483 } | |
| 484 return nil; | |
| 485 } | |
| 486 | |
| 487 - (void)updateAccessoryViewButtonsStates { | |
| 488 AutofillEditCell* previousCell = [self nextTextFieldWithOffset:-1]; | |
| 489 [[_accessoryView previousButton] setEnabled:previousCell != nil]; | |
| 490 | |
| 491 AutofillEditCell* nextCell = [self nextTextFieldWithOffset:1]; | |
| 492 [[_accessoryView nextButton] setEnabled:nextCell != nil]; | |
| 493 } | |
| 494 | |
| 495 #pragma mark - Keyboard handling | |
| 496 | |
| 497 - (void)keyboardDidShow { | |
| 498 [self.collectionView scrollRectToVisible:[_currentEditingCell frame] | |
| 499 animated:YES]; | |
| 500 } | |
| 501 | |
| 502 @end | |
| OLD | NEW |