| 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/credit_card_edit_view_controller.h" |
| 6 |
| 7 #include "base/guid.h" |
| 8 #import "base/mac/foundation_util.h" |
| 9 #include "base/memory/ptr_util.h" |
| 10 #include "base/strings/sys_string_conversions.h" |
| 11 #include "components/autofill/core/browser/autofill_data_util.h" |
| 12 #include "components/autofill/core/browser/credit_card.h" |
| 13 #include "components/autofill/core/browser/field_types.h" |
| 14 #include "components/autofill/core/browser/personal_data_manager.h" |
| 15 #include "components/autofill/core/common/autofill_constants.h" |
| 16 #import "components/autofill/ios/browser/credit_card_util.h" |
| 17 #include "components/strings/grit/components_strings.h" |
| 18 #include "ios/chrome/browser/application_context.h" |
| 19 #import "ios/chrome/browser/payments/cells/payments_text_item.h" |
| 20 #import "ios/chrome/browser/payments/payment_request_util.h" |
| 21 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrom
e.h" |
| 22 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item
.h" |
| 23 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" |
| 24 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" |
| 25 #import "ios/chrome/browser/ui/settings/cells/autofill_edit_item.h" |
| 26 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 27 #include "ios/chrome/grit/ios_strings.h" |
| 28 #import "ios/third_party/material_components_ios/src/components/Typography/src/M
aterialTypography.h" |
| 29 #include "ui/base/l10n/l10n_util.h" |
| 30 |
| 31 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 32 #error "This file requires ARC support." |
| 33 #endif |
| 34 |
| 35 namespace { |
| 36 |
| 37 NSString* const kCreditCardEditCollectionViewId = |
| 38 @"kCreditCardEditCollectionViewId"; |
| 39 |
| 40 const CGFloat kSeparatorEdgeInset = 14; |
| 41 |
| 42 const CGFloat kCardTypeIconDimension = 25.0; |
| 43 |
| 44 typedef NS_ENUM(NSInteger, SectionIdentifier) { |
| 45 SectionIdentifierCardNumber = kSectionIdentifierEnumZero, |
| 46 SectionIdentifierCardholderName, |
| 47 SectionIdentifierExpirationMonth, |
| 48 SectionIdentifierExpirationYear, |
| 49 SectionIdentifierBillingAddress, |
| 50 }; |
| 51 |
| 52 typedef NS_ENUM(NSInteger, ItemType) { |
| 53 ItemTypeCardNumber = kItemTypeEnumZero, |
| 54 ItemTypeCardholderName, |
| 55 ItemTypeExpirationMonth, |
| 56 ItemTypeExpirationYear, |
| 57 ItemTypeBillingAddress, |
| 58 ItemTypeErrorMessage, |
| 59 }; |
| 60 |
| 61 using ::payment_request_util::GetBillingAddressLabelFromAutofillProfile; |
| 62 |
| 63 } // namespace |
| 64 |
| 65 @interface CreditCardEditViewController () { |
| 66 UIBarButtonItem* _cancelButton; |
| 67 UIBarButtonItem* _doneButton; |
| 68 |
| 69 // The PaymentRequest object owning an instance of web::PaymentRequest as |
| 70 // provided by the page invoking the Payment Request API. This is a weak |
| 71 // pointer and should outlive this class. |
| 72 PaymentRequest* _paymentRequest; |
| 73 |
| 74 // The credit card to be edited, if any. This is a weak pointer and should |
| 75 // outlive this class. |
| 76 autofill::CreditCard* _creditCard; |
| 77 |
| 78 // GUID of the credit card's billing address, if there is one. |
| 79 std::string _billingAddressGUID; |
| 80 } |
| 81 |
| 82 @end |
| 83 |
| 84 @implementation CreditCardEditViewController |
| 85 |
| 86 @synthesize delegate = _delegate; |
| 87 |
| 88 #pragma mark - Initialization |
| 89 |
| 90 - (instancetype)initWithPaymentRequest:(PaymentRequest*)paymentRequest |
| 91 creditCard:(autofill::CreditCard*)creditCard { |
| 92 self = [super initWithPaymentRequest:paymentRequest]; |
| 93 if (self) { |
| 94 DCHECK(paymentRequest); |
| 95 _paymentRequest = paymentRequest; |
| 96 _creditCard = creditCard; |
| 97 |
| 98 // TODO(crbug.com/602666): Title varies depending on the missing fields. |
| 99 NSString* title = creditCard |
| 100 ? l10n_util::GetNSString(IDS_PAYMENTS_EDIT_CARD) |
| 101 : l10n_util::GetNSString(IDS_PAYMENTS_ADD_CARD_LABEL); |
| 102 [self setTitle:title]; |
| 103 |
| 104 // Set up leading (cancel) button. |
| 105 _cancelButton = [[UIBarButtonItem alloc] |
| 106 initWithTitle:l10n_util::GetNSString(IDS_CANCEL) |
| 107 style:UIBarButtonItemStylePlain |
| 108 target:nil |
| 109 action:@selector(onReturn)]; |
| 110 [_cancelButton setTitleTextAttributes:@{ |
| 111 NSForegroundColorAttributeName : [UIColor lightGrayColor] |
| 112 } |
| 113 forState:UIControlStateDisabled]; |
| 114 [_cancelButton |
| 115 setAccessibilityLabel:l10n_util::GetNSString(IDS_ACCNAME_CANCEL)]; |
| 116 [self navigationItem].leftBarButtonItem = _cancelButton; |
| 117 |
| 118 // Set up trailing (done) button. |
| 119 _doneButton = |
| 120 [[UIBarButtonItem alloc] initWithTitle:l10n_util::GetNSString(IDS_DONE) |
| 121 style:UIBarButtonItemStylePlain |
| 122 target:nil |
| 123 action:@selector(onConfirm)]; |
| 124 [_doneButton setTitleTextAttributes:@{ |
| 125 NSForegroundColorAttributeName : [UIColor lightGrayColor] |
| 126 } |
| 127 forState:UIControlStateDisabled]; |
| 128 [_doneButton |
| 129 setAccessibilityLabel:l10n_util::GetNSString(IDS_ACCNAME_DONE)]; |
| 130 [self navigationItem].rightBarButtonItem = _doneButton; |
| 131 } |
| 132 |
| 133 return self; |
| 134 } |
| 135 |
| 136 - (void)onReturn { |
| 137 [_delegate creditCardEditViewControllerDidReturn:self]; |
| 138 } |
| 139 |
| 140 - (void)onConfirm { |
| 141 [self validateAndSubmitForm]; |
| 142 } |
| 143 |
| 144 - (void)validateAndSubmitForm { |
| 145 CollectionViewModel* model = self.collectionViewModel; |
| 146 |
| 147 // Creat an empty credit card. If a credit card is being edited, copy over the |
| 148 // information. |
| 149 autofill::CreditCard creditCard("", autofill::kSettingsOrigin); |
| 150 if (_creditCard) |
| 151 creditCard = *_creditCard; |
| 152 |
| 153 // Validate card number, card holder name, expiration month, and expiration |
| 154 // year. If there are validation errors, display an error message item in the |
| 155 // same section as the field and return. Otherwise remove the error message |
| 156 // item in that section and set the information on the credit card. |
| 157 for (const auto& field : [self editorFields]) { |
| 158 NSIndexPath* indexPath = [model indexPathForItemType:field.item_type |
| 159 sectionIdentifier:field.section_id]; |
| 160 AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( |
| 161 [model itemAtIndexPath:indexPath]); |
| 162 |
| 163 NSString* errorMessage = [self validateValue:item.textFieldValue |
| 164 autofillType:field.data_type |
| 165 required:field.required]; |
| 166 [self addOrRemoveErrorItemWithType:ItemTypeErrorMessage |
| 167 errorMessage:errorMessage |
| 168 inSectionWithIdentifier:field.section_id]; |
| 169 if (errorMessage.length != 0) { |
| 170 return; |
| 171 } |
| 172 |
| 173 creditCard.SetRawInfo(field.data_type, |
| 174 base::SysNSStringToUTF16(item.textFieldValue)); |
| 175 } |
| 176 |
| 177 // Validate and set the billing address GUID like the rest of the fields. |
| 178 NSString* errorMessage = |
| 179 _billingAddressGUID.empty() |
| 180 ? l10n_util::GetNSString( |
| 181 IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE) |
| 182 : @""; |
| 183 [self addOrRemoveErrorItemWithType:ItemTypeErrorMessage |
| 184 errorMessage:errorMessage |
| 185 inSectionWithIdentifier:SectionIdentifierBillingAddress]; |
| 186 if (errorMessage.length != 0) { |
| 187 return; |
| 188 } |
| 189 |
| 190 creditCard.set_billing_address_id(_billingAddressGUID); |
| 191 |
| 192 if (!_creditCard) { |
| 193 // The new credit card does not yet have a valid GUID. |
| 194 creditCard.set_guid(base::GenerateGUID()); |
| 195 |
| 196 // Add the credit card to the local credit cards managed by |
| 197 // autofill::PersonalDataManager. |
| 198 _paymentRequest->GetPersonalDataManager()->AddCreditCard(creditCard); |
| 199 |
| 200 // Add the credit card to the list of credit cards in |_paymentRequest|. Do |
| 201 // this manually to avoid waiting for autofill::PersonalDataManager to get |
| 202 // updated. |_paymentRequest| takes ownership of the instance. |
| 203 std::unique_ptr<autofill::CreditCard> new_card = |
| 204 base::MakeUnique<autofill::CreditCard>(creditCard); |
| 205 _creditCard = new_card.get(); |
| 206 _paymentRequest->AddCreditCard(std::move(new_card)); |
| 207 } else { |
| 208 // Update the original credit card instance that is being edited. |
| 209 *_creditCard = creditCard; |
| 210 |
| 211 if (autofill::IsCreditCardLocal(creditCard)) { |
| 212 _paymentRequest->GetPersonalDataManager()->UpdateCreditCard(creditCard); |
| 213 } else { |
| 214 // Update server credit card's billing address. |
| 215 _paymentRequest->GetPersonalDataManager()->UpdateServerCardMetadata( |
| 216 creditCard); |
| 217 } |
| 218 } |
| 219 |
| 220 [_delegate creditCardEditViewController:self |
| 221 didFinishEditingCreditCard:_creditCard]; |
| 222 } |
| 223 |
| 224 - (std::vector<EditorField>)editorFields { |
| 225 // Serve credit cards are not editable. |
| 226 if (_creditCard && !autofill::IsCreditCardLocal(*_creditCard)) |
| 227 return std::vector<EditorField>(); |
| 228 |
| 229 return std::vector<EditorField>{ |
| 230 {autofill::CREDIT_CARD_NUMBER, |
| 231 l10n_util::GetStringUTF16(IDS_IOS_AUTOFILL_CARD_NUMBER), |
| 232 /* required= */ true, ItemTypeCardNumber, SectionIdentifierCardNumber}, |
| 233 {autofill::CREDIT_CARD_NAME_FULL, |
| 234 l10n_util::GetStringUTF16(IDS_IOS_AUTOFILL_CARDHOLDER), |
| 235 /* required= */ true, ItemTypeCardholderName, |
| 236 SectionIdentifierCardholderName}, |
| 237 {autofill::CREDIT_CARD_EXP_MONTH, |
| 238 l10n_util::GetStringUTF16(IDS_IOS_AUTOFILL_EXP_MONTH), |
| 239 /* required= */ true, ItemTypeExpirationMonth, |
| 240 SectionIdentifierExpirationMonth}, |
| 241 {autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, |
| 242 l10n_util::GetStringUTF16(IDS_IOS_AUTOFILL_EXP_YEAR), |
| 243 /* required= */ true, ItemTypeExpirationYear, |
| 244 SectionIdentifierExpirationYear}}; |
| 245 } |
| 246 |
| 247 #pragma mark - CollectionViewController methods |
| 248 |
| 249 - (void)loadModel { |
| 250 // Card number, card holder name, expiration month, and expiration year |
| 251 // sections are added in the parent class. |
| 252 [super loadModel]; |
| 253 CollectionViewModel* model = self.collectionViewModel; |
| 254 |
| 255 // Billing Address section. |
| 256 [model addSectionWithIdentifier:SectionIdentifierBillingAddress]; |
| 257 CollectionViewDetailItem* billingAddressItem = |
| 258 [[CollectionViewDetailItem alloc] initWithType:ItemTypeBillingAddress]; |
| 259 billingAddressItem.text = |
| 260 [NSString stringWithFormat:@"%@*", l10n_util::GetNSString( |
| 261 IDS_IOS_AUTOFILL_BILLING_ADDRESS)]; |
| 262 billingAddressItem.accessoryType = |
| 263 MDCCollectionViewCellAccessoryDisclosureIndicator; |
| 264 [model addItem:billingAddressItem |
| 265 toSectionWithIdentifier:SectionIdentifierBillingAddress]; |
| 266 |
| 267 if (_creditCard) { |
| 268 for (const auto& field : [self editorFields]) { |
| 269 NSIndexPath* indexPath = [model indexPathForItemType:field.item_type |
| 270 sectionIdentifier:field.section_id]; |
| 271 AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( |
| 272 [model itemAtIndexPath:indexPath]); |
| 273 switch (field.item_type) { |
| 274 case ItemTypeCardNumber: { |
| 275 NSString* cardNumber = |
| 276 base::SysUTF16ToNSString(_creditCard->number()); |
| 277 item.textFieldValue = cardNumber; |
| 278 item.cardTypeIcon = [self cardTypeIconFromCardNumber:cardNumber]; |
| 279 break; |
| 280 } |
| 281 case ItemTypeCardholderName: { |
| 282 item.textFieldValue = autofill::GetCreditCardName( |
| 283 *_creditCard, GetApplicationContext()->GetApplicationLocale()); |
| 284 break; |
| 285 } |
| 286 case ItemTypeExpirationMonth: { |
| 287 item.textFieldValue = [NSString |
| 288 stringWithFormat:@"%02d", _creditCard->expiration_month()]; |
| 289 break; |
| 290 } |
| 291 case ItemTypeExpirationYear: { |
| 292 item.textFieldValue = [NSString |
| 293 stringWithFormat:@"%04d", _creditCard->expiration_year()]; |
| 294 break; |
| 295 } |
| 296 default: |
| 297 NOTREACHED(); |
| 298 break; |
| 299 } |
| 300 } |
| 301 |
| 302 if (!_creditCard->billing_address_id().empty()) { |
| 303 _billingAddressGUID = _creditCard->billing_address_id(); |
| 304 autofill::AutofillProfile* billingAddress = |
| 305 autofill::PersonalDataManager::GetProfileFromProfilesByGUID( |
| 306 _creditCard->billing_address_id(), |
| 307 _paymentRequest->billing_profiles()); |
| 308 DCHECK(billingAddress); |
| 309 billingAddressItem.detailText = |
| 310 GetBillingAddressLabelFromAutofillProfile(*billingAddress); |
| 311 } |
| 312 } |
| 313 } |
| 314 |
| 315 - (void)viewDidLoad { |
| 316 [super viewDidLoad]; |
| 317 self.collectionView.accessibilityIdentifier = kCreditCardEditCollectionViewId; |
| 318 |
| 319 // Customize collection view settings. |
| 320 self.styler.cellStyle = MDCCollectionViewCellStyleCard; |
| 321 self.styler.separatorInset = |
| 322 UIEdgeInsetsMake(0, kSeparatorEdgeInset, 0, kSeparatorEdgeInset); |
| 323 } |
| 324 |
| 325 #pragma mark - UITextFieldDelegate |
| 326 |
| 327 // This method is called as the text is being typed in, pasted, or deleted. Asks |
| 328 // the delegate if the text should be changed. Should always return YES. During |
| 329 // typing/pasting text, |newText| contains one or more new characters. When user |
| 330 // deletes text, |newText| is empty. |range| is the range of characters to be |
| 331 // replaced. |
| 332 - (BOOL)textField:(UITextField*)textField |
| 333 shouldChangeCharactersInRange:(NSRange)range |
| 334 replacementString:(NSString*)newText { |
| 335 NSIndexPath* indexPath = [self indexPathForCurrentTextField]; |
| 336 AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( |
| 337 [self.collectionViewModel itemAtIndexPath:indexPath]); |
| 338 |
| 339 // If the user is typing in the credit card number field, update the card type |
| 340 // icon (e.g. "Visa") to reflect the number being typed. |
| 341 if (item.autofillType == autofill::CREDIT_CARD_NUMBER) { |
| 342 // Obtain the text being typed. |
| 343 NSString* updatedText = |
| 344 [textField.text stringByReplacingCharactersInRange:range |
| 345 withString:newText]; |
| 346 item.cardTypeIcon = [self cardTypeIconFromCardNumber:updatedText]; |
| 347 // Update the cell. |
| 348 [self reconfigureCellsForItems:@[ item ] |
| 349 inSectionWithIdentifier:SectionIdentifierCardNumber]; |
| 350 } |
| 351 |
| 352 return YES; |
| 353 } |
| 354 |
| 355 - (void)textFieldDidEndEditing:(UITextField*)textField { |
| 356 CollectionViewModel* model = self.collectionViewModel; |
| 357 |
| 358 NSIndexPath* indexPath = [self indexPathForCurrentTextField]; |
| 359 AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( |
| 360 [model itemAtIndexPath:indexPath]); |
| 361 |
| 362 // Validate the text field. If there is a validation error, display an error |
| 363 // message item in the same section as the field. Otherwise remove the error |
| 364 // message item in that section |
| 365 NSString* errorMessage = [self validateValue:textField.text |
| 366 autofillType:item.autofillType |
| 367 required:item.required]; |
| 368 NSInteger sectionIdentifier = |
| 369 [model sectionIdentifierForSection:[indexPath section]]; |
| 370 [self addOrRemoveErrorItemWithType:ItemTypeErrorMessage |
| 371 errorMessage:errorMessage |
| 372 inSectionWithIdentifier:sectionIdentifier]; |
| 373 |
| 374 [super textFieldDidEndEditing:textField]; |
| 375 } |
| 376 |
| 377 #pragma mark - UICollectionViewDataSource |
| 378 |
| 379 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView |
| 380 cellForItemAtIndexPath:(NSIndexPath*)indexPath { |
| 381 UICollectionViewCell* cell = |
| 382 [super collectionView:collectionView cellForItemAtIndexPath:indexPath]; |
| 383 |
| 384 NSInteger itemType = |
| 385 [self.collectionViewModel itemTypeForIndexPath:indexPath]; |
| 386 switch (itemType) { |
| 387 case ItemTypeCardNumber: { |
| 388 AutofillEditCell* textFieldCell = |
| 389 base::mac::ObjCCast<AutofillEditCell>(cell); |
| 390 textFieldCell.textField.delegate = self; |
| 391 textFieldCell.textField.autocapitalizationType = |
| 392 UITextAutocapitalizationTypeSentences; |
| 393 textFieldCell.textField.keyboardType = UIKeyboardTypeNumberPad; |
| 394 textFieldCell.textField.returnKeyType = UIReturnKeyNext; |
| 395 textFieldCell.textField.clearButtonMode = UITextFieldViewModeNever; |
| 396 textFieldCell.textLabel.font = [MDCTypography body2Font]; |
| 397 textFieldCell.textLabel.textColor = [[MDCPalette greyPalette] tint900]; |
| 398 textFieldCell.textField.font = [MDCTypography body1Font]; |
| 399 textFieldCell.textField.textColor = [[MDCPalette cr_bluePalette] tint600]; |
| 400 break; |
| 401 } |
| 402 case ItemTypeCardholderName: { |
| 403 AutofillEditCell* textFieldCell = |
| 404 base::mac::ObjCCast<AutofillEditCell>(cell); |
| 405 textFieldCell.textField.delegate = self; |
| 406 textFieldCell.textField.autocapitalizationType = |
| 407 UITextAutocapitalizationTypeWords; |
| 408 textFieldCell.textField.keyboardType = UIKeyboardTypeDefault; |
| 409 textFieldCell.textField.returnKeyType = UIReturnKeyNext; |
| 410 textFieldCell.textField.clearButtonMode = UITextFieldViewModeNever; |
| 411 textFieldCell.textLabel.font = [MDCTypography body2Font]; |
| 412 textFieldCell.textLabel.textColor = [[MDCPalette greyPalette] tint900]; |
| 413 textFieldCell.textField.font = [MDCTypography body1Font]; |
| 414 textFieldCell.textField.textColor = [[MDCPalette cr_bluePalette] tint600]; |
| 415 break; |
| 416 } |
| 417 case ItemTypeExpirationMonth: { |
| 418 AutofillEditCell* textFieldCell = |
| 419 base::mac::ObjCCast<AutofillEditCell>(cell); |
| 420 textFieldCell.textField.delegate = self; |
| 421 textFieldCell.textField.autocapitalizationType = |
| 422 UITextAutocapitalizationTypeSentences; |
| 423 textFieldCell.textField.keyboardType = UIKeyboardTypeNumberPad; |
| 424 textFieldCell.textField.returnKeyType = UIReturnKeyNext; |
| 425 textFieldCell.textField.clearButtonMode = UITextFieldViewModeNever; |
| 426 textFieldCell.textLabel.font = [MDCTypography body2Font]; |
| 427 textFieldCell.textLabel.textColor = [[MDCPalette greyPalette] tint900]; |
| 428 textFieldCell.textField.font = [MDCTypography body1Font]; |
| 429 textFieldCell.textField.textColor = [[MDCPalette cr_bluePalette] tint600]; |
| 430 break; |
| 431 } |
| 432 case ItemTypeExpirationYear: { |
| 433 AutofillEditCell* textFieldCell = |
| 434 base::mac::ObjCCast<AutofillEditCell>(cell); |
| 435 textFieldCell.textField.delegate = self; |
| 436 textFieldCell.textField.autocapitalizationType = |
| 437 UITextAutocapitalizationTypeSentences; |
| 438 textFieldCell.textField.keyboardType = UIKeyboardTypeNumberPad; |
| 439 textFieldCell.textField.returnKeyType = UIReturnKeyDone; |
| 440 textFieldCell.textField.clearButtonMode = UITextFieldViewModeNever; |
| 441 textFieldCell.textLabel.font = [MDCTypography body2Font]; |
| 442 textFieldCell.textLabel.textColor = [[MDCPalette greyPalette] tint900]; |
| 443 textFieldCell.textField.font = [MDCTypography body1Font]; |
| 444 textFieldCell.textField.textColor = [[MDCPalette cr_bluePalette] tint600]; |
| 445 break; |
| 446 } |
| 447 case ItemTypeBillingAddress: { |
| 448 CollectionViewDetailCell* billingCell = |
| 449 base::mac::ObjCCastStrict<CollectionViewDetailCell>(cell); |
| 450 billingCell.textLabel.font = [MDCTypography body2Font]; |
| 451 billingCell.textLabel.textColor = [[MDCPalette greyPalette] tint900]; |
| 452 billingCell.detailTextLabel.font = [MDCTypography body1Font]; |
| 453 billingCell.detailTextLabel.textColor = |
| 454 [[MDCPalette cr_bluePalette] tint600]; |
| 455 break; |
| 456 } |
| 457 case ItemTypeErrorMessage: { |
| 458 PaymentsTextCell* messageCell = |
| 459 base::mac::ObjCCastStrict<PaymentsTextCell>(cell); |
| 460 messageCell.textLabel.font = [MDCTypography body1Font]; |
| 461 messageCell.textLabel.textColor = [[MDCPalette cr_redPalette] tint600]; |
| 462 break; |
| 463 } |
| 464 default: |
| 465 break; |
| 466 } |
| 467 |
| 468 return cell; |
| 469 } |
| 470 |
| 471 #pragma mark UICollectionViewDelegate |
| 472 |
| 473 - (void)collectionView:(UICollectionView*)collectionView |
| 474 didSelectItemAtIndexPath:(NSIndexPath*)indexPath { |
| 475 [super collectionView:collectionView didSelectItemAtIndexPath:indexPath]; |
| 476 CollectionViewModel* model = self.collectionViewModel; |
| 477 |
| 478 CollectionViewItem* item = [model itemAtIndexPath:indexPath]; |
| 479 switch (item.type) { |
| 480 case ItemTypeCardNumber: |
| 481 case ItemTypeCardholderName: |
| 482 case ItemTypeExpirationMonth: |
| 483 case ItemTypeExpirationYear: |
| 484 case ItemTypeErrorMessage: |
| 485 break; |
| 486 case ItemTypeBillingAddress: { |
| 487 // TODO(crbug.com/602666): This is wrong! Done this way to make submitting |
| 488 // the form possible. Display a list of billing addresses instead. |
| 489 autofill::AutofillProfile* billingAddress = |
| 490 _paymentRequest->selected_shipping_profile(); |
| 491 DCHECK(billingAddress); |
| 492 _billingAddressGUID = billingAddress->guid(); |
| 493 |
| 494 CollectionViewDetailItem* billingAddressItem = |
| 495 base::mac::ObjCCastStrict<CollectionViewDetailItem>(item); |
| 496 billingAddressItem.detailText = |
| 497 GetBillingAddressLabelFromAutofillProfile(*billingAddress); |
| 498 // Update the cell. |
| 499 [self reconfigureCellsForItems:@[ billingAddressItem ] |
| 500 inSectionWithIdentifier:SectionIdentifierBillingAddress]; |
| 501 break; |
| 502 } |
| 503 default: |
| 504 NOTREACHED(); |
| 505 break; |
| 506 } |
| 507 } |
| 508 |
| 509 #pragma mark MDCCollectionViewStylingDelegate |
| 510 |
| 511 - (CGFloat)collectionView:(UICollectionView*)collectionView |
| 512 cellHeightAtIndexPath:(NSIndexPath*)indexPath { |
| 513 CollectionViewItem* item = |
| 514 [self.collectionViewModel itemAtIndexPath:indexPath]; |
| 515 switch (item.type) { |
| 516 case ItemTypeCardNumber: |
| 517 case ItemTypeCardholderName: |
| 518 case ItemTypeExpirationMonth: |
| 519 case ItemTypeExpirationYear: |
| 520 case ItemTypeErrorMessage: |
| 521 return [MDCCollectionViewCell |
| 522 cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) |
| 523 forItem:item]; |
| 524 case ItemTypeBillingAddress: |
| 525 return MDCCellDefaultOneLineHeight; |
| 526 default: |
| 527 NOTREACHED(); |
| 528 return MDCCellDefaultOneLineHeight; |
| 529 } |
| 530 } |
| 531 |
| 532 - (BOOL)collectionView:(UICollectionView*)collectionView |
| 533 hidesInkViewAtIndexPath:(NSIndexPath*)indexPath { |
| 534 NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; |
| 535 switch (type) { |
| 536 case ItemTypeErrorMessage: |
| 537 return YES; |
| 538 default: |
| 539 return NO; |
| 540 } |
| 541 } |
| 542 |
| 543 #pragma mark - Helper methods |
| 544 |
| 545 - (UIImage*)cardTypeIconFromCardNumber:(NSString*)cardNumber { |
| 546 const char* cardType = autofill::CreditCard::GetCreditCardType( |
| 547 base::SysNSStringToUTF16(cardNumber)); |
| 548 if (cardType != autofill::kGenericCard) { |
| 549 int resourceID = |
| 550 autofill::data_util::GetPaymentRequestData(cardType).icon_resource_id; |
| 551 // Resize and return the card type icon. |
| 552 CGFloat dimension = kCardTypeIconDimension; |
| 553 return ResizeImage(NativeImage(resourceID), |
| 554 CGSizeMake(dimension, dimension), |
| 555 ProjectionMode::kAspectFillNoClipping); |
| 556 } else { |
| 557 return nil; |
| 558 } |
| 559 } |
| 560 |
| 561 @end |
| OLD | NEW |