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

Side by Side Diff: ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.mm

Issue 2586993002: Upstream Chrome on iOS source code [3/11]. (Closed)
Patch Set: Created 4 years 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 2015 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 #include "ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.h"
6
7 #include "base/bind.h"
8 #include "base/ios/ios_util.h"
9 #include "base/location.h"
10 #include "base/mac/foundation_util.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "components/autofill/core/browser/ui/card_unmask_prompt_controller.h"
15 #include "components/strings/grit/components_strings.h"
16 #import "ios/chrome/browser/ui/autofill/cells/cvc_item.h"
17 #import "ios/chrome/browser/ui/autofill/cells/status_item.h"
18 #import "ios/chrome/browser/ui/autofill/cells/storage_switch_item.h"
19 #import "ios/chrome/browser/ui/autofill/storage_switch_tooltip.h"
20 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrom e.h"
21 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
22 #import "ios/chrome/browser/ui/collection_view/collection_view_controller.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/rtl_geometry.h"
26 #import "ios/third_party/material_components_ios/src/components/AppBar/src/Mater ialAppBar.h"
27 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h"
28 #include "ui/base/l10n/l10n_util.h"
29
30 namespace {
31
32 const CGFloat kTitleVerticalSpacing = 2.0f;
33
34 typedef NS_ENUM(NSInteger, SectionIdentifier) {
35 SectionIdentifierMain = kSectionIdentifierEnumZero,
36 };
37
38 typedef NS_ENUM(NSInteger, ItemType) {
39 ItemTypeCVC = kItemTypeEnumZero,
40 ItemTypeStatus,
41 ItemTypeStorageSwitch,
42 };
43
44 } // namespace
45
46 namespace autofill {
47
48 #pragma mark CardUnmaskPromptViewBridge
49
50 CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge(
51 CardUnmaskPromptController* controller)
52 : controller_(controller), weak_ptr_factory_(this) {
53 DCHECK(controller_);
54 }
55
56 CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() {
57 if (controller_)
58 controller_->OnUnmaskDialogClosed();
59 }
60
61 void CardUnmaskPromptViewBridge::Show() {
62 view_.reset([[CardUnmaskPromptViewIOS alloc] initWithBridge:this]);
63 // Present the view controller.
64 UIViewController* rootController =
65 [UIApplication sharedApplication].keyWindow.rootViewController;
66 [rootController presentViewController:view_ animated:YES completion:nil];
67 }
68
69 void CardUnmaskPromptViewBridge::ControllerGone() {
70 controller_ = nullptr;
71 PerformClose();
72 }
73
74 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() {
75 [view_ showSpinner];
76 }
77
78 void CardUnmaskPromptViewBridge::GotVerificationResult(
79 const base::string16& error_message,
80 bool allow_retry) {
81 if (error_message.empty()) {
82 [view_ showSuccess];
83 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
84 FROM_HERE, base::Bind(&CardUnmaskPromptViewBridge::PerformClose,
85 weak_ptr_factory_.GetWeakPtr()),
86 controller_->GetSuccessMessageDuration());
87 } else {
88 if (allow_retry) {
89 [view_ showCVCInputFormWithError:SysUTF16ToNSString(error_message)];
90 } else {
91 [view_ showError:SysUTF16ToNSString(error_message)];
92 }
93 }
94 }
95
96 CardUnmaskPromptController* CardUnmaskPromptViewBridge::GetController() {
97 return controller_;
98 }
99
100 void CardUnmaskPromptViewBridge::PerformClose() {
101 [view_ dismissViewControllerAnimated:YES
102 completion:^{
103 this->DeleteSelf();
104 }];
105 }
106
107 void CardUnmaskPromptViewBridge::DeleteSelf() {
108 delete this;
109 }
110
111 } // autofill
112
113 @interface CardUnmaskPromptViewIOS ()<UITextFieldDelegate> {
114 base::scoped_nsobject<UIBarButtonItem> _cancelButton;
115 base::scoped_nsobject<UIBarButtonItem> _verifyButton;
116 base::scoped_nsobject<CVCItem> _CVCItem;
117 base::scoped_nsobject<StatusItem> _statusItem;
118 base::scoped_nsobject<StorageSwitchItem> _storageSwitchItem;
119
120 // The tooltip is added as a child of the collection view rather than the
121 // StorageSwitchContentView to allow it to overflow the bounds of the switch
122 // view.
123 base::scoped_nsobject<StorageSwitchTooltip> _storageSwitchTooltip;
124
125 // Owns |self|.
126 autofill::CardUnmaskPromptViewBridge* _bridge; // weak
127 }
128
129 @end
130
131 @implementation CardUnmaskPromptViewIOS
132
133 - (instancetype)initWithBridge:(autofill::CardUnmaskPromptViewBridge*)bridge {
134 DCHECK(bridge);
135 self = [super initWithStyle:CollectionViewControllerStyleAppBar];
136 if (self) {
137 _bridge = bridge;
138 }
139 return self;
140 }
141
142 - (void)viewDidLoad {
143 [super viewDidLoad];
144
145 self.styler.cellStyle = MDCCollectionViewCellStyleCard;
146
147 UILabel* titleLabel =
148 [[[UILabel alloc] initWithFrame:CGRectZero] autorelease];
149 titleLabel.text =
150 SysUTF16ToNSString(_bridge->GetController()->GetWindowTitle());
151 titleLabel.font = [UIFont boldSystemFontOfSize:16];
152 titleLabel.accessibilityTraits |= UIAccessibilityTraitHeader;
153 [titleLabel sizeToFit];
154
155 UIView* titleView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
156 [titleView addSubview:titleLabel];
157 CGRect titleBounds = titleView.bounds;
158 titleBounds.origin.y -= kTitleVerticalSpacing;
159 titleView.bounds = titleBounds;
160 titleView.autoresizingMask = UIViewAutoresizingFlexibleLeadingMargin() |
161 UIViewAutoresizingFlexibleBottomMargin;
162 self.appBar.navigationBar.titleView = titleView;
163
164 [self showCVCInputForm];
165
166 // Add the navigation buttons.
167 _cancelButton.reset([[UIBarButtonItem alloc]
168 initWithTitle:l10n_util::GetNSString(IDS_CANCEL)
169 style:UIBarButtonItemStylePlain
170 target:self
171 action:@selector(onCancel:)]);
172 self.navigationItem.leftBarButtonItem = _cancelButton;
173
174 NSString* verifyButtonText =
175 SysUTF16ToNSString(_bridge->GetController()->GetOkButtonLabel());
176 _verifyButton.reset([[UIBarButtonItem alloc]
177 initWithTitle:verifyButtonText
178 style:UIBarButtonItemStylePlain
179 target:self
180 action:@selector(onVerify:)]);
181 [_verifyButton setTitleTextAttributes:@{
182 NSForegroundColorAttributeName : [[MDCPalette cr_bluePalette] tint600]
183 }
184 forState:UIControlStateNormal];
185 [_verifyButton setTitleTextAttributes:@{
186 NSForegroundColorAttributeName : [UIColor lightGrayColor]
187 }
188 forState:UIControlStateDisabled];
189 [_verifyButton setEnabled:NO];
190 self.navigationItem.rightBarButtonItem = _verifyButton;
191 }
192
193 - (void)viewWillLayoutSubviews {
194 [super viewWillLayoutSubviews];
195 NSIndexPath* CVCIndexPath =
196 [self.collectionViewModel indexPathForItem:_CVCItem
197 inSectionWithIdentifier:SectionIdentifierMain];
198 CVCCell* CVC = base::mac::ObjCCastStrict<CVCCell>(
199 [self.collectionView cellForItemAtIndexPath:CVCIndexPath]);
200 [self focusInputIfNeeded:CVC];
201 }
202
203 #pragma mark - CollectionViewController
204
205 - (void)loadModel {
206 [super loadModel];
207 CollectionViewModel* model = self.collectionViewModel;
208 [model addSectionWithIdentifier:SectionIdentifierMain];
209
210 autofill::CardUnmaskPromptController* controller = _bridge->GetController();
211 NSString* instructions =
212 SysUTF16ToNSString(controller->GetInstructionsMessage());
213 int CVCImageResourceID = controller->GetCvcImageRid();
214 _CVCItem.reset([[CVCItem alloc] initWithType:ItemTypeCVC]);
215 _CVCItem.get().instructionsText = instructions;
216 _CVCItem.get().CVCImageResourceID = CVCImageResourceID;
217 [model addItem:_CVCItem toSectionWithIdentifier:SectionIdentifierMain];
218
219 if (controller->CanStoreLocally()) {
220 _storageSwitchItem.reset(
221 [[StorageSwitchItem alloc] initWithType:ItemTypeStorageSwitch]);
222 _storageSwitchItem.get().on = controller->GetStoreLocallyStartState();
223 [model addItem:_storageSwitchItem
224 toSectionWithIdentifier:SectionIdentifierMain];
225
226 _storageSwitchTooltip.reset([[StorageSwitchTooltip alloc] init]);
227 [_storageSwitchTooltip setHidden:YES];
228 [self.collectionView addSubview:_storageSwitchTooltip];
229 } else {
230 _storageSwitchItem.reset();
231 }
232
233 // No status item when loading the model.
234 _statusItem.reset();
235 }
236
237 #pragma mark - Private
238
239 - (void)showCVCInputForm {
240 [self showCVCInputFormWithError:nil];
241 }
242
243 - (void)showCVCInputFormWithError:(NSString*)errorMessage {
244 [_verifyButton setEnabled:NO];
245
246 [self loadModel];
247 _CVCItem.get().errorMessage = errorMessage;
248 // If the server requested a new expiration date, show the date input. If it
249 // didn't and there was an error, show the "New card?" link which will show
250 // the date inputs on click. This link is intended to remind the user that
251 // they might have recently received a new card with updated expiration date
252 // and CVC. At the same time, we only put the CVC input in an error state if
253 // we're not requesting a new date. Because if we're asking the user for both,
254 // we don't know which is incorrect.
255 if (_bridge->GetController()->ShouldRequestExpirationDate()) {
256 _CVCItem.get().showDateInput = YES;
257 } else if (errorMessage) {
258 _CVCItem.get().showNewCardButton = YES;
259 _CVCItem.get().showCVCInputError = YES;
260 }
261 }
262
263 - (void)showSpinner {
264 [_verifyButton setEnabled:NO];
265 [_storageSwitchTooltip setHidden:YES];
266
267 [self
268 updateWithStatus:StatusItemState::VERIFYING
269 text:l10n_util::GetNSString(
270 IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_IN_PROGRESS)];
271 }
272
273 - (void)showSuccess {
274 [_verifyButton setEnabled:NO];
275
276 [self updateWithStatus:StatusItemState::VERIFIED
277 text:l10n_util::GetNSString(
278 IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_SUCCESS)];
279 }
280
281 - (void)showError:(NSString*)errorMessage {
282 [_cancelButton setTitle:l10n_util::GetNSString(IDS_CLOSE)];
283 [_verifyButton setEnabled:NO];
284
285 [self updateWithStatus:StatusItemState::ERROR text:errorMessage];
286 }
287
288 - (void)updateWithStatus:(StatusItemState)state text:(NSString*)text {
289 if (!_statusItem) {
290 _statusItem.reset([[StatusItem alloc] initWithType:ItemTypeStatus]);
291 _statusItem.get().text = text;
292 _statusItem.get().state = state;
293 // Remove all the present items to replace them with the status item.
294 [self.collectionViewModel
295 removeSectionWithIdentifier:SectionIdentifierMain];
296 [self.collectionViewModel addSectionWithIdentifier:SectionIdentifierMain];
297 [self.collectionViewModel addItem:_statusItem
298 toSectionWithIdentifier:SectionIdentifierMain];
299 [self.collectionView reloadData];
300 } else {
301 _statusItem.get().text = text;
302 _statusItem.get().state = state;
303 [self reconfigureCellsForItems:@[ _statusItem.get() ]
304 inSectionWithIdentifier:SectionIdentifierMain];
305 [self.collectionViewLayout invalidateLayout];
306 }
307 }
308
309 - (CGFloat)statusCellHeight {
310 const CGFloat collectionViewWidth =
311 CGRectGetWidth(self.collectionView.bounds);
312
313 // The status cell replaces the previous content of the collection. So it is
314 // sized based on what appears when not loading.
315 const CGFloat preferredHeightForCVC =
316 [MDCCollectionViewCell cr_preferredHeightForWidth:collectionViewWidth
317 forItem:_CVCItem];
318 CGFloat preferredHeightForStorageSwitch = 0;
319 if (_storageSwitchItem) {
320 preferredHeightForStorageSwitch =
321 [MDCCollectionViewCell cr_preferredHeightForWidth:collectionViewWidth
322 forItem:_storageSwitchItem];
323 }
324 const CGFloat preferredHeightForStatus =
325 [MDCCollectionViewCell cr_preferredHeightForWidth:collectionViewWidth
326 forItem:_statusItem];
327 // Return the size of the replaced content, but make sure it is at least the
328 // minimal status cell height.
329 return MAX(preferredHeightForCVC + preferredHeightForStorageSwitch,
330 preferredHeightForStatus);
331 }
332
333 - (void)layoutTooltipFromButton:(UIButton*)button {
334 const CGRect buttonFrameInCollectionView =
335 [self.collectionView convertRect:button.bounds fromView:button];
336 CGRect tooltipFrame = _storageSwitchTooltip.get().frame;
337
338 // First, set the width and use sizeToFit to have the label flow the text and
339 // set the height appropriately.
340 const CGFloat kTooltipMargin = 8;
341 CGFloat availableWidth =
342 CGRectGetMinX(buttonFrameInCollectionView) - 2 * kTooltipMargin;
343 const CGFloat kMaxTooltipWidth = 210;
344 tooltipFrame.size.width = MIN(availableWidth, kMaxTooltipWidth);
345 _storageSwitchTooltip.get().frame = tooltipFrame;
346 [_storageSwitchTooltip sizeToFit];
347
348 // Then use the size to position the tooltip appropriately, based on the
349 // button position.
350 tooltipFrame = _storageSwitchTooltip.get().frame;
351 tooltipFrame.origin.x = CGRectGetMinX(buttonFrameInCollectionView) -
352 kTooltipMargin - CGRectGetWidth(tooltipFrame);
353 tooltipFrame.origin.y = CGRectGetMaxY(buttonFrameInCollectionView) -
354 CGRectGetHeight(tooltipFrame);
355 _storageSwitchTooltip.get().frame = tooltipFrame;
356 }
357
358 - (BOOL)inputCVCIsValid:(CVCItem*)item {
359 return _bridge->GetController()->InputCvcIsValid(
360 base::SysNSStringToUTF16(item.CVCText));
361 }
362
363 - (BOOL)inputExpirationIsValid:(CVCItem*)item {
364 if (!item.showDateInput) {
365 return YES;
366 }
367
368 return _bridge->GetController()->InputExpirationIsValid(
369 base::SysNSStringToUTF16(item.monthText),
370 base::SysNSStringToUTF16(item.yearText));
371 }
372
373 - (void)inputsDidChange:(CVCItem*)item {
374 [_verifyButton setEnabled:[self inputCVCIsValid:item] &&
375 [self inputExpirationIsValid:item]];
376 }
377
378 - (void)updateDateErrorState:(CVCItem*)item {
379 // Only change the error state if the inputs are of a length that can be
380 // interpreted as valid or not.
381 NSUInteger monthTextLength = item.monthText.length;
382 if (monthTextLength != 1 && monthTextLength != 2) {
383 return;
384 }
385 NSUInteger yearTextLength = item.yearText.length;
386 if (yearTextLength != 2 && yearTextLength != 4) {
387 return;
388 }
389
390 if ([self inputExpirationIsValid:item]) {
391 item.showDateInputError = NO;
392 item.errorMessage = @"";
393 } else {
394 item.showDateInputError = NO;
395 item.errorMessage = l10n_util::GetNSString(
396 IDS_AUTOFILL_CARD_UNMASK_INVALID_EXPIRATION_DATE);
397 }
398
399 [self reconfigureCellsForItems:@[ item ]
400 inSectionWithIdentifier:SectionIdentifierMain];
401 [self.collectionViewLayout invalidateLayout];
402 }
403
404 - (void)focusInputIfNeeded:(CVCCell*)CVC {
405 // Focus the first visible input, unless the orientation is landscape. In
406 // landscape, the keyboard covers up the storage checkbox shown below this
407 // view and the user might never see it.
408 if (UIInterfaceOrientationIsPortrait(
409 [UIApplication sharedApplication].statusBarOrientation)) {
410 // Also check whether any of the inputs are already the first responder and
411 // are non-empty, in which case the focus should be left there.
412 if ((!CVC.monthInput.isFirstResponder || CVC.monthInput.text.length == 0) &&
413 (!CVC.yearInput.isFirstResponder || CVC.yearInput.text.length == 0) &&
414 (!CVC.CVCInput.isFirstResponder || CVC.CVCInput.text.length == 0)) {
415 if (_CVCItem.get().showDateInput) {
416 [CVC.monthInput becomeFirstResponder];
417 } else {
418 [CVC.CVCInput becomeFirstResponder];
419 }
420 }
421 }
422 }
423
424 #pragma mark - Actions
425
426 - (void)onVerify:(id)sender {
427 autofill::CardUnmaskPromptController* controller = _bridge->GetController();
428 DCHECK(controller);
429
430 // The controller requires a 4-digit year. Convert if necessary.
431 NSString* yearText = _CVCItem.get().yearText;
432 if (yearText.length == 2) {
433 NSInteger inputYear = yearText.integerValue;
434 NSInteger currentYear =
435 [[NSCalendar currentCalendar] components:NSCalendarUnitYear
436 fromDate:[NSDate date]]
437 .year;
438 inputYear += currentYear - (currentYear % 100);
439 yearText = [@(inputYear) stringValue];
440 }
441
442 controller->OnUnmaskResponse(
443 base::SysNSStringToUTF16(_CVCItem.get().CVCText),
444 base::SysNSStringToUTF16(_CVCItem.get().monthText),
445 base::SysNSStringToUTF16(yearText), _storageSwitchItem.get().on);
446 }
447
448 - (void)onCancel:(id)sender {
449 _bridge->PerformClose();
450 }
451
452 - (void)onTooltipButtonTapped:(UIButton*)button {
453 BOOL shouldShowTooltip = !button.selected;
454 button.highlighted = shouldShowTooltip;
455 if (shouldShowTooltip) {
456 button.selected = YES;
457 [self layoutTooltipFromButton:button];
458 [_storageSwitchTooltip setHidden:NO];
459 } else {
460 button.selected = NO;
461 [_storageSwitchTooltip setHidden:YES];
462 }
463 }
464
465 - (void)onStorageSwitchChanged:(UISwitch*)switchView {
466 // Update the item.
467 _storageSwitchItem.get().on = switchView.on;
468 }
469
470 - (void)onNewCardLinkTapped:(UIButton*)button {
471 _bridge->GetController()->NewCardLinkClicked();
472 _CVCItem.get().instructionsText =
473 SysUTF16ToNSString(_bridge->GetController()->GetInstructionsMessage());
474 _CVCItem.get().monthText = @"";
475 _CVCItem.get().yearText = @"";
476 _CVCItem.get().CVCText = @"";
477 _CVCItem.get().errorMessage = @"";
478 _CVCItem.get().showDateInput = YES;
479 _CVCItem.get().showNewCardButton = NO;
480 _CVCItem.get().showDateInputError = NO;
481 _CVCItem.get().showCVCInputError = NO;
482
483 [self reconfigureCellsForItems:@[ _CVCItem.get() ]
484 inSectionWithIdentifier:SectionIdentifierMain];
485 [self.collectionViewLayout invalidateLayout];
486
487 [self inputsDidChange:_CVCItem];
488 }
489
490 #pragma mark - UITextField Events
491
492 - (void)monthInputDidChange:(UITextField*)textField {
493 _CVCItem.get().monthText = textField.text;
494 [self inputsDidChange:_CVCItem];
495 [self updateDateErrorState:_CVCItem];
496 }
497
498 - (void)yearInputDidChange:(UITextField*)textField {
499 _CVCItem.get().yearText = textField.text;
500 [self inputsDidChange:_CVCItem];
501 [self updateDateErrorState:_CVCItem];
502 }
503
504 - (void)CVCInputDidChange:(UITextField*)textField {
505 _CVCItem.get().CVCText = textField.text;
506 [self inputsDidChange:_CVCItem];
507 if (_bridge->GetController()->InputCvcIsValid(
508 base::SysNSStringToUTF16(textField.text))) {
509 _CVCItem.get().showCVCInputError = NO;
510 [self updateDateErrorState:_CVCItem];
511 }
512 }
513
514 #pragma mark - MDCCollectionViewStylingDelegate
515
516 - (CGFloat)collectionView:(UICollectionView*)collectionView
517 cellHeightAtIndexPath:(NSIndexPath*)indexPath {
518 CollectionViewItem* item =
519 [self.collectionViewModel itemAtIndexPath:indexPath];
520 if (item.type == ItemTypeStatus) {
521 return [self statusCellHeight];
522 }
523 return [MDCCollectionViewCell
524 cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
525 forItem:item];
526 }
527
528 - (BOOL)collectionView:(UICollectionView*)collectionView
529 hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
530 return YES;
531 }
532
533 #pragma mark - UICollectionViewDataSource
534
535 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
536 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
537 UICollectionViewCell* cell =
538 [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
539
540 ItemType itemType = static_cast<ItemType>(
541 [self.collectionViewModel itemTypeForIndexPath:indexPath]);
542 switch (itemType) {
543 case ItemTypeCVC: {
544 CVCCell* cellForCVC = base::mac::ObjCCastStrict<CVCCell>(cell);
545 [cellForCVC.monthInput addTarget:self
546 action:@selector(monthInputDidChange:)
547 forControlEvents:UIControlEventEditingChanged];
548 [cellForCVC.yearInput addTarget:self
549 action:@selector(yearInputDidChange:)
550 forControlEvents:UIControlEventEditingChanged];
551 [cellForCVC.CVCInput addTarget:self
552 action:@selector(CVCInputDidChange:)
553 forControlEvents:UIControlEventEditingChanged];
554 [cellForCVC.buttonForNewCard addTarget:self
555 action:@selector(onNewCardLinkTapped:)
556 forControlEvents:UIControlEventTouchUpInside];
557 break;
558 }
559 case ItemTypeStorageSwitch: {
560 StorageSwitchCell* storageSwitchCell =
561 base::mac::ObjCCastStrict<StorageSwitchCell>(cell);
562 [storageSwitchCell.tooltipButton
563 addTarget:self
564 action:@selector(onTooltipButtonTapped:)
565 forControlEvents:UIControlEventTouchUpInside];
566 [storageSwitchCell.switchView addTarget:self
567 action:@selector(onStorageSwitchChanged:)
568 forControlEvents:UIControlEventValueChanged];
569 break;
570 }
571 default:
572 break;
573 }
574 return cell;
575 }
576
577 #pragma mark - UICollectionViewDelegate
578
579 - (void)collectionView:(UICollectionView*)collectionView
580 willDisplayCell:(UICollectionViewCell*)cell
581 forItemAtIndexPath:(NSIndexPath*)indexPath {
582 CVCCell* CVC = base::mac::ObjCCast<CVCCell>(cell);
583 if (CVC) {
584 [self focusInputIfNeeded:CVC];
585 }
586 }
587
588 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.h ('k') | ios/chrome/browser/ui/autofill/cells/cvc_item.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698