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

Side by Side Diff: chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc

Issue 2896263002: [Payments] Changes to validation in the Credit Card editor (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 #include "chrome/browser/ui/views/payments/credit_card_editor_view_controller.h" 5 #include "chrome/browser/ui/views/payments/credit_card_editor_view_controller.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 #include <vector> 10 #include <vector>
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 #include "ui/views/view.h" 47 #include "ui/views/view.h"
48 48
49 namespace payments { 49 namespace payments {
50 50
51 namespace { 51 namespace {
52 52
53 // Number of years (including the current one) to be shown in the expiration 53 // Number of years (including the current one) to be shown in the expiration
54 // year dropdown. 54 // year dropdown.
55 const int kNumberOfExpirationYears = 10; 55 const int kNumberOfExpirationYears = 10;
56 56
57 // Opacity of card network icons when they are not selected and are displayed
58 // alongside a selected icon.
59 const float kDimmedCardIconOpacity = 0.33f;
anthonyvd 2017/05/23 15:59:42 Didn't Bruno specify 50%?
60
57 // This is not quite right but is the closest server type that wasn't already 61 // This is not quite right but is the closest server type that wasn't already
58 // used. 62 // used.
59 const auto kBillingAddressType = autofill::ADDRESS_BILLING_LINE1; 63 const auto kBillingAddressType = autofill::ADDRESS_BILLING_LINE1;
60 64
61 // Returns the items that are in the expiration month dropdown. Will return the 65 // Returns the items that are in the expiration month dropdown. Will return the
62 // months in order starting at "01" until "12". Uses a clock so that the 66 // months in order starting at "01" until "12". Uses a clock so that the
63 // |default_index| is set to the current month. 67 // |default_index| is set to the current month.
64 std::vector<base::string16> GetExpirationMonthItems(int* default_index) { 68 std::vector<base::string16> GetExpirationMonthItems(int* default_index) {
65 std::vector<base::string16> months; 69 std::vector<base::string16> months;
66 months.reserve(12); 70 months.reserve(12);
(...skipping 27 matching lines...) Expand all
94 autofill::CreditCard card; 98 autofill::CreditCard card;
95 card.SetExpirationMonthFromString(month, app_locale); 99 card.SetExpirationMonthFromString(month, app_locale);
96 card.SetExpirationYearFromString(year); 100 card.SetExpirationYearFromString(year);
97 return card.IsExpired(autofill::AutofillClock::Now()); 101 return card.IsExpired(autofill::AutofillClock::Now());
98 } 102 }
99 103
100 // Validates the two comboboxes used for expiration date. 104 // Validates the two comboboxes used for expiration date.
101 class ExpirationDateValidationDelegate : public ValidationDelegate { 105 class ExpirationDateValidationDelegate : public ValidationDelegate {
102 public: 106 public:
103 ExpirationDateValidationDelegate(EditorViewController* controller, 107 ExpirationDateValidationDelegate(EditorViewController* controller,
104 const std::string& app_locale) 108 const std::string& app_locale,
105 : controller_(controller), app_locale_(app_locale) {} 109 bool initially_valid)
110 : controller_(controller),
111 app_locale_(app_locale),
112 initially_valid_(initially_valid) {}
106 113
107 bool IsValidTextfield(views::Textfield* textfield) override { 114 bool IsValidTextfield(views::Textfield* textfield) override {
108 NOTREACHED(); 115 NOTREACHED();
109 return true; 116 return true;
110 } 117 }
111 118
112 bool IsValidCombobox(views::Combobox* combobox) override { 119 bool IsValidCombobox(views::Combobox* combobox) override {
120 // View will have no parent if it's not been attached yet. Use initial
121 // validity state.
122 views::View* view_parent = combobox->parent();
123 if (!view_parent)
124 return initially_valid_;
125
113 // Get the combined date from the month and year dropdowns. 126 // Get the combined date from the month and year dropdowns.
114 views::View* view_parent = combobox->parent();
115
116 views::Combobox* month_combobox = static_cast<views::Combobox*>( 127 views::Combobox* month_combobox = static_cast<views::Combobox*>(
117 view_parent->GetViewByID(EditorViewController::GetInputFieldViewId( 128 view_parent->GetViewByID(EditorViewController::GetInputFieldViewId(
118 autofill::CREDIT_CARD_EXP_MONTH))); 129 autofill::CREDIT_CARD_EXP_MONTH)));
119 base::string16 month = 130 base::string16 month =
120 month_combobox->model()->GetItemAt(month_combobox->selected_index()); 131 month_combobox->model()->GetItemAt(month_combobox->selected_index());
121 132
122 views::Combobox* year_combobox = static_cast<views::Combobox*>( 133 views::Combobox* year_combobox = static_cast<views::Combobox*>(
123 view_parent->GetViewByID(EditorViewController::GetInputFieldViewId( 134 view_parent->GetViewByID(EditorViewController::GetInputFieldViewId(
124 autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR))); 135 autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR)));
125 base::string16 year = 136 base::string16 year =
126 year_combobox->model()->GetItemAt(year_combobox->selected_index()); 137 year_combobox->model()->GetItemAt(year_combobox->selected_index());
127 138
128 bool is_expired = IsCardExpired(month, year, app_locale_); 139 bool is_expired = IsCardExpired(month, year, app_locale_);
129 month_combobox->SetInvalid(is_expired); 140 month_combobox->SetInvalid(is_expired);
130 year_combobox->SetInvalid(is_expired); 141 year_combobox->SetInvalid(is_expired);
131 142
132 return !is_expired; 143 return !is_expired;
133 } 144 }
134 145
135 bool TextfieldValueChanged(views::Textfield* textfield) override { 146 bool TextfieldValueChanged(views::Textfield* textfield,
147 bool was_blurred) override {
136 NOTREACHED(); 148 NOTREACHED();
137 return true; 149 return true;
138 } 150 }
139 151
140 bool ComboboxValueChanged(views::Combobox* combobox) override { 152 bool ComboboxValueChanged(views::Combobox* combobox) override {
141 bool is_valid = IsValidCombobox(combobox); 153 bool is_valid = IsValidCombobox(combobox);
142 controller_->DisplayErrorMessageForField( 154 controller_->DisplayErrorMessageForField(
143 autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 155 autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
144 is_valid ? base::string16() 156 is_valid ? base::string16()
145 : l10n_util::GetStringUTF16( 157 : l10n_util::GetStringUTF16(
146 IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRED)); 158 IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRED));
147 return is_valid; 159 return is_valid;
148 } 160 }
149 161
150 void ComboboxModelChanged(views::Combobox* combobox) override {} 162 void ComboboxModelChanged(views::Combobox* combobox) override {}
151 163
152 private: 164 private:
153 EditorViewController* controller_; 165 EditorViewController* controller_;
154 const std::string app_locale_; 166 const std::string app_locale_;
167 bool initially_valid_;
155 168
156 DISALLOW_COPY_AND_ASSIGN(ExpirationDateValidationDelegate); 169 DISALLOW_COPY_AND_ASSIGN(ExpirationDateValidationDelegate);
157 }; 170 };
158 171
159 } // namespace 172 } // namespace
160 173
161 CreditCardEditorViewController::CreditCardEditorViewController( 174 CreditCardEditorViewController::CreditCardEditorViewController(
162 PaymentRequestSpec* spec, 175 PaymentRequestSpec* spec,
163 PaymentRequestState* state, 176 PaymentRequestState* state,
164 PaymentRequestDialogView* dialog, 177 PaymentRequestDialogView* dialog,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 label->SetEnabled(false); 220 label->SetEnabled(false);
208 view->AddChildView(label.release()); 221 view->AddChildView(label.release());
209 222
210 // 8dp padding is required between icons. 223 // 8dp padding is required between icons.
211 constexpr int kPaddingBetweenCardIcons = 8; 224 constexpr int kPaddingBetweenCardIcons = 8;
212 std::unique_ptr<views::View> icons_row = base::MakeUnique<views::View>(); 225 std::unique_ptr<views::View> icons_row = base::MakeUnique<views::View>();
213 views::BoxLayout* icons_layout = new views::BoxLayout( 226 views::BoxLayout* icons_layout = new views::BoxLayout(
214 views::BoxLayout::kHorizontal, 0, 0, kPaddingBetweenCardIcons); 227 views::BoxLayout::kHorizontal, 0, 0, kPaddingBetweenCardIcons);
215 icons_row->SetLayoutManager(icons_layout); 228 icons_row->SetLayoutManager(icons_layout);
216 229
230 std::string selected_network =
231 credit_card_to_edit_ ? autofill::data_util::GetPaymentRequestData(
232 credit_card_to_edit_->network())
233 .basic_card_issuer_network
234 : "";
217 constexpr gfx::Size kCardIconSize = gfx::Size(30, 18); 235 constexpr gfx::Size kCardIconSize = gfx::Size(30, 18);
218 for (const std::string& supported_network : 236 for (const std::string& supported_network :
219 spec()->supported_card_networks()) { 237 spec()->supported_card_networks()) {
220 const std::string autofill_card_type = 238 const std::string autofill_card_type =
221 autofill::data_util::GetIssuerNetworkForBasicCardIssuerNetwork( 239 autofill::data_util::GetIssuerNetworkForBasicCardIssuerNetwork(
222 supported_network); 240 supported_network);
241 // Icon is fully opaque if no network is selected, or if it is the selected
242 // network.
243 float opacity =
244 selected_network.empty() || selected_network == supported_network
245 ? 1.0f
246 : kDimmedCardIconOpacity;
223 std::unique_ptr<views::ImageView> card_icon_view = CreateInstrumentIconView( 247 std::unique_ptr<views::ImageView> card_icon_view = CreateInstrumentIconView(
224 autofill::data_util::GetPaymentRequestData(autofill_card_type) 248 autofill::data_util::GetPaymentRequestData(autofill_card_type)
225 .icon_resource_id, 249 .icon_resource_id,
226 base::UTF8ToUTF16(supported_network)); 250 base::UTF8ToUTF16(supported_network), opacity);
227 card_icon_view->SetImageSize(kCardIconSize); 251 card_icon_view->SetImageSize(kCardIconSize);
228 252
253 // Keep track of this card icon to later adjust opacity.
254 card_icons_[supported_network] = card_icon_view.get();
255
229 icons_row->AddChildView(card_icon_view.release()); 256 icons_row->AddChildView(card_icon_view.release());
230 } 257 }
231 view->AddChildView(icons_row.release()); 258 view->AddChildView(icons_row.release());
232 259
233 return view; 260 return view;
234 } 261 }
235 262
236 std::unique_ptr<views::View> 263 std::unique_ptr<views::View>
237 CreditCardEditorViewController::CreateCustomFieldView( 264 CreditCardEditorViewController::CreateCustomFieldView(
238 autofill::ServerFieldType type, 265 autofill::ServerFieldType type,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 views::GridLayout::FILL, views::GridLayout::FILL, 0, 300 views::GridLayout::FILL, views::GridLayout::FILL, 0,
274 kInputFieldHeight); 301 kInputFieldHeight);
275 302
276 view->SetLayoutManager(combobox_layout.release()); 303 view->SetLayoutManager(combobox_layout.release());
277 304
278 // Set the initial validity of the custom view. 305 // Set the initial validity of the custom view.
279 base::string16 month = 306 base::string16 month =
280 GetInitialValueForType(autofill::CREDIT_CARD_EXP_MONTH); 307 GetInitialValueForType(autofill::CREDIT_CARD_EXP_MONTH);
281 base::string16 year = 308 base::string16 year =
282 GetInitialValueForType(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR); 309 GetInitialValueForType(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR);
283 *valid = IsCardExpired(month, year, state()->GetApplicationLocale()); 310 *valid = !IsCardExpired(month, year, state()->GetApplicationLocale());
284 return view; 311 return view;
285 } 312 }
286 313
287 std::unique_ptr<views::View> 314 std::unique_ptr<views::View>
288 CreditCardEditorViewController::CreateExtraViewForField( 315 CreditCardEditorViewController::CreateExtraViewForField(
289 autofill::ServerFieldType type) { 316 autofill::ServerFieldType type) {
290 if (type != kBillingAddressType) 317 if (type != kBillingAddressType)
291 return nullptr; 318 return nullptr;
292 319
293 std::unique_ptr<views::View> button_view = base::MakeUnique<views::View>(); 320 std::unique_ptr<views::View> button_view = base::MakeUnique<views::View>();
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 state()->GetPersonalDataManager()->UpdateCreditCard(*credit_card_to_edit_); 434 state()->GetPersonalDataManager()->UpdateCreditCard(*credit_card_to_edit_);
408 std::move(on_edited_).Run(); 435 std::move(on_edited_).Run();
409 } 436 }
410 437
411 return true; 438 return true;
412 } 439 }
413 440
414 std::unique_ptr<ValidationDelegate> 441 std::unique_ptr<ValidationDelegate>
415 CreditCardEditorViewController::CreateValidationDelegate( 442 CreditCardEditorViewController::CreateValidationDelegate(
416 const EditorField& field) { 443 const EditorField& field) {
444 if (field.type == autofill::CREDIT_CARD_EXP_MONTH ||
445 field.type == autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR) {
446 bool initially_valid =
447 credit_card_to_edit_
448 ? !credit_card_to_edit_->IsExpired(autofill::AutofillClock::Now())
449 : true;
450 return base::MakeUnique<ExpirationDateValidationDelegate>(
451 this, state()->GetApplicationLocale(), initially_valid);
452 }
417 // The supported card networks for non-cc-number types are not passed to avoid 453 // The supported card networks for non-cc-number types are not passed to avoid
418 // the data copy in the delegate. 454 // the data copy in the delegate.
419 if (field.type == autofill::CREDIT_CARD_EXP_MONTH ||
420 field.type == autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR)
421 return base::MakeUnique<ExpirationDateValidationDelegate>(
422 this, state()->GetApplicationLocale());
423 return base::MakeUnique< 455 return base::MakeUnique<
424 CreditCardEditorViewController::CreditCardValidationDelegate>( 456 CreditCardEditorViewController::CreditCardValidationDelegate>(
425 field, this, 457 field, this,
426 field.type == autofill::CREDIT_CARD_NUMBER 458 field.type == autofill::CREDIT_CARD_NUMBER
427 ? spec()->supported_card_networks() 459 ? spec()->supported_card_networks()
428 : std::vector<std::string>()); 460 : std::vector<std::string>());
429 } 461 }
430 462
431 std::unique_ptr<ui::ComboboxModel> 463 std::unique_ptr<ui::ComboboxModel>
432 CreditCardEditorViewController::GetComboboxModelForType( 464 CreditCardEditorViewController::GetComboboxModelForType(
(...skipping 16 matching lines...) Expand all
449 *state()->GetPersonalDataManager(), state()->GetApplicationLocale(), 481 *state()->GetPersonalDataManager(), state()->GetApplicationLocale(),
450 credit_card_to_edit_ ? credit_card_to_edit_->billing_address_id() 482 credit_card_to_edit_ ? credit_card_to_edit_->billing_address_id()
451 : ""); 483 : "");
452 default: 484 default:
453 NOTREACHED(); 485 NOTREACHED();
454 break; 486 break;
455 } 487 }
456 return std::unique_ptr<ui::ComboboxModel>(); 488 return std::unique_ptr<ui::ComboboxModel>();
457 } 489 }
458 490
491 void CreditCardEditorViewController::SelectBasicCardNetworkIcon(
492 const std::string& basic_card_network) {
493 // If empty string was passed or if the icon representing |basic_card_network|
494 // is not present (i.e. not supported), all icons have full opacity.
495 bool full_opacity =
496 card_icons_.find(basic_card_network) == card_icons_.end() ||
497 basic_card_network.empty();
498 for (auto network_icon_it : card_icons_) {
499 float target_opacity =
500 full_opacity || network_icon_it.first == basic_card_network
501 ? 1.0f
502 : kDimmedCardIconOpacity;
503 network_icon_it.second->layer()->SetOpacity(target_opacity);
504 network_icon_it.second->layer()->ScheduleDraw();
505 }
506 }
507
459 void CreditCardEditorViewController::FillContentView( 508 void CreditCardEditorViewController::FillContentView(
460 views::View* content_view) { 509 views::View* content_view) {
461 EditorViewController::FillContentView(content_view); 510 EditorViewController::FillContentView(content_view);
462 // We need to search from the content view here, since the dialog may not have 511 // We need to search from the content view here, since the dialog may not have
463 // the content view added to it yet. 512 // the content view added to it yet.
464 views::Combobox* combobox = static_cast<views::Combobox*>( 513 views::Combobox* combobox = static_cast<views::Combobox*>(
465 content_view->GetViewByID(GetInputFieldViewId(kBillingAddressType))); 514 content_view->GetViewByID(GetInputFieldViewId(kBillingAddressType)));
466 // When the combobox has a single item, it's because it has no addresses 515 // When the combobox has a single item, it's because it has no addresses
467 // (otherwise, it would have the select header, and a separator before the 516 // (otherwise, it would have the select header, and a separator before the
468 // first address to choose from). 517 // first address to choose from).
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 // SetSelectedIndex doesn't trigger a perform action notification, which is 559 // SetSelectedIndex doesn't trigger a perform action notification, which is
511 // needed to update the valid state. 560 // needed to update the valid state.
512 address_combobox->SetSelectedRow(index); 561 address_combobox->SetSelectedRow(index);
513 // But it needs to be blured at least once. 562 // But it needs to be blured at least once.
514 address_combobox->OnBlur(); 563 address_combobox->OnBlur();
515 } 564 }
516 565
517 CreditCardEditorViewController::CreditCardValidationDelegate:: 566 CreditCardEditorViewController::CreditCardValidationDelegate::
518 CreditCardValidationDelegate( 567 CreditCardValidationDelegate(
519 const EditorField& field, 568 const EditorField& field,
520 EditorViewController* controller, 569 CreditCardEditorViewController* controller,
521 const std::vector<std::string>& supported_card_networks) 570 const std::vector<std::string>& supported_card_networks)
522 : field_(field), 571 : field_(field),
523 controller_(controller), 572 controller_(controller),
524 supported_card_networks_(supported_card_networks.begin(), 573 supported_card_networks_(supported_card_networks.begin(),
525 supported_card_networks.end()) {} 574 supported_card_networks.end()) {}
526 CreditCardEditorViewController::CreditCardValidationDelegate:: 575 CreditCardEditorViewController::CreditCardValidationDelegate::
527 ~CreditCardValidationDelegate() {} 576 ~CreditCardValidationDelegate() {}
528 577
529 bool CreditCardEditorViewController::CreditCardValidationDelegate:: 578 bool CreditCardEditorViewController::CreditCardValidationDelegate::
530 IsValidTextfield(views::Textfield* textfield) { 579 IsValidTextfield(views::Textfield* textfield) {
531 return ValidateValue(textfield->text(), nullptr); 580 return ValidateValue(textfield->text(), nullptr);
532 } 581 }
533 582
534 bool CreditCardEditorViewController::CreditCardValidationDelegate:: 583 bool CreditCardEditorViewController::CreditCardValidationDelegate::
535 IsValidCombobox(views::Combobox* combobox) { 584 IsValidCombobox(views::Combobox* combobox) {
536 return ValidateCombobox(combobox, nullptr); 585 return ValidateCombobox(combobox, nullptr);
537 } 586 }
538 587
539 bool CreditCardEditorViewController::CreditCardValidationDelegate:: 588 bool CreditCardEditorViewController::CreditCardValidationDelegate::
540 TextfieldValueChanged(views::Textfield* textfield) { 589 TextfieldValueChanged(views::Textfield* textfield, bool was_blurred) {
590 // The only behavior pre-blur is selecting the card icon.
591 if (field_.type == autofill::CREDIT_CARD_NUMBER) {
592 std::string basic_card_network =
593 autofill::data_util::GetPaymentRequestData(
594 autofill::CreditCard::GetCardNetwork(textfield->text()))
595 .basic_card_issuer_network;
596 controller_->SelectBasicCardNetworkIcon(basic_card_network);
597 }
598
599 // We return true if the field was not yet blurred, because validation should
600 // not occur yet.
601 if (!was_blurred)
602 return true;
603
541 base::string16 error_message; 604 base::string16 error_message;
542 bool is_valid = ValidateValue(textfield->text(), &error_message); 605 bool is_valid = ValidateValue(textfield->text(), &error_message);
543 controller_->DisplayErrorMessageForField(field_.type, error_message); 606 controller_->DisplayErrorMessageForField(field_.type, error_message);
607
544 return is_valid; 608 return is_valid;
545 } 609 }
546 610
547 bool CreditCardEditorViewController::CreditCardValidationDelegate:: 611 bool CreditCardEditorViewController::CreditCardValidationDelegate::
548 ComboboxValueChanged(views::Combobox* combobox) { 612 ComboboxValueChanged(views::Combobox* combobox) {
549 base::string16 error_message; 613 base::string16 error_message;
550 bool is_valid = ValidateCombobox(combobox, nullptr); 614 bool is_valid = ValidateCombobox(combobox, nullptr);
551 controller_->DisplayErrorMessageForField(field_.type, error_message); 615 controller_->DisplayErrorMessageForField(field_.type, error_message);
552 return is_valid; 616 return is_valid;
553 } 617 }
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 return ValidateValue(combobox->GetTextForRow(combobox->selected_index()), 659 return ValidateValue(combobox->GetTextForRow(combobox->selected_index()),
596 error_message); 660 error_message);
597 } 661 }
598 662
599 bool CreditCardEditorViewController::GetSheetId(DialogViewID* sheet_id) { 663 bool CreditCardEditorViewController::GetSheetId(DialogViewID* sheet_id) {
600 *sheet_id = DialogViewID::CREDIT_CARD_EDITOR_SHEET; 664 *sheet_id = DialogViewID::CREDIT_CARD_EDITOR_SHEET;
601 return true; 665 return true;
602 } 666 }
603 667
604 } // namespace payments 668 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698