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

Side by Side Diff: ios/chrome/browser/payments/credit_card_edit_view_controller.mm

Issue 2744823003: [Payment Request] Generic edit form (Closed)
Patch Set: Created 3 years, 9 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
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698