Chromium Code Reviews| Index: chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc | 
| diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc | 
| index 8eb09d303fe88bf79f8c77b0b983ae4f5c37d5db..ea5505635c4e177a267eb6b90d199ae8b20095bd 100644 | 
| --- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc | 
| +++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc | 
| @@ -8,13 +8,18 @@ | 
| #include "base/memory/ptr_util.h" | 
| #include "base/strings/string16.h" | 
| +#include "base/strings/stringprintf.h" | 
| #include "base/strings/utf_string_conversions.h" | 
| +#include "base/time/time.h" | 
| #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h" | 
| +#include "chrome/browser/ui/views/payments/validating_combobox.h" | 
| +#include "chrome/browser/ui/views/payments/validating_textfield.h" | 
| #include "chrome/grit/generated_resources.h" | 
| #include "components/autofill/core/browser/autofill_type.h" | 
| #include "components/autofill/core/browser/credit_card.h" | 
| #include "components/autofill/core/browser/field_types.h" | 
| #include "components/autofill/core/browser/validation.h" | 
| +#include "components/autofill/core/common/autofill_clock.h" | 
| #include "components/autofill/core/common/autofill_constants.h" | 
| #include "components/payments/payment_request.h" | 
| #include "ui/base/l10n/l10n_util.h" | 
| @@ -22,6 +27,41 @@ | 
| namespace payments { | 
| +namespace { | 
| + | 
| +// Number of years (including the current one) to be shown in the expiration | 
| +// year dropdown. | 
| +const size_t kNumberOfExpirationYears = 10u; | 
| + | 
| +// Returns the items that are in the expiration month dropdown. | 
| 
 
please use gerrit instead
2017/02/15 15:59:39
Need to add a comment about why this needs a clock
 
Mathieu
2017/02/15 19:55:51
Done.
 
 | 
| +std::vector<base::string16> GetExpirationMonthItems() { | 
| + std::vector<base::string16> months; | 
| + months.reserve(12); | 
| + | 
| + base::Time::Exploded now_exploded; | 
| + autofill::AutofillClock::Now().LocalExplode(&now_exploded); | 
| + for (int i = 0; i < 12; i++) { | 
| + int month = (now_exploded.month - 1 + i) % 12 + 1; | 
| + months.push_back(base::UTF8ToUTF16(base::StringPrintf("%02d", month))); | 
| + } | 
| + return months; | 
| +} | 
| + | 
| +// Returns the items that are in the expiration year dropdown. | 
| +std::vector<base::string16> GetExpirationYearItems() { | 
| + std::vector<base::string16> years; | 
| + years.reserve(kNumberOfExpirationYears); | 
| + | 
| + base::Time::Exploded now_exploded; | 
| + autofill::AutofillClock::Now().LocalExplode(&now_exploded); | 
| + for (size_t i = 0u; i < kNumberOfExpirationYears; i++) { | 
| + years.push_back(base::UTF8ToUTF16(std::to_string(now_exploded.year + i))); | 
| 
 
please use gerrit instead
2017/02/15 15:59:39
now_exploded.year is an "int", so let's make both
 
Mathieu
2017/02/15 19:55:50
Done.
 
 | 
| + } | 
| + return years; | 
| +} | 
| + | 
| +} // namespace | 
| + | 
| CreditCardEditorViewController::CreditCardEditorViewController( | 
| PaymentRequest* request, | 
| PaymentRequestDialogView* dialog) | 
| @@ -37,9 +77,14 @@ std::vector<EditorField> CreditCardEditorViewController::GetFieldDefinitions() { | 
| {autofill::CREDIT_CARD_NUMBER, | 
| l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_CREDIT_CARD_NUMBER), | 
| EditorField::LengthHint::HINT_LONG, true}, | 
| - {autofill::CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, | 
| - l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_EXPIRATION_DATE), | 
| - EditorField::LengthHint::HINT_SHORT, true}}; | 
| + {autofill::CREDIT_CARD_EXP_MONTH, | 
| + l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_EXPIRATION_MONTH), | 
| + EditorField::LengthHint::HINT_SHORT, true, | 
| + EditorField::ControlType::COMBOBOX}, | 
| + {autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, | 
| + l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_EXPIRATION_YEAR), | 
| + EditorField::LengthHint::HINT_SHORT, true, | 
| + EditorField::ControlType::COMBOBOX}}; | 
| } | 
| bool CreditCardEditorViewController::ValidateModelAndSave() { | 
| @@ -54,6 +99,17 @@ bool CreditCardEditorViewController::ValidateModelAndSave() { | 
| credit_card.SetRawInfo(field.second.type, field.first->text()); | 
| } | 
| + for (const auto& field : comboboxes()) { | 
| + // ValidatingCombobox* is the key, EditorField is the value. | 
| + DCHECK_EQ(autofill::CREDIT_CARD, | 
| + autofill::AutofillType(field.second.type).group()); | 
| + ValidatingCombobox* combobox = field.first; | 
| + if (combobox->invalid()) | 
| + return false; | 
| + | 
| + credit_card.SetRawInfo(field.second.type, | 
| + combobox->GetTextForRow(combobox->selected_index())); | 
| + } | 
| // TODO(mathp): Display global error message. | 
| if (!credit_card.IsValid()) | 
| @@ -65,25 +121,52 @@ bool CreditCardEditorViewController::ValidateModelAndSave() { | 
| return true; | 
| } | 
| -std::unique_ptr<ValidatingTextfield::Delegate> | 
| +std::unique_ptr<ValidationDelegate> | 
| CreditCardEditorViewController::CreateValidationDelegate( | 
| const EditorField& field) { | 
| - return base::MakeUnique<CreditCardEditorViewController::ValidationDelegate>( | 
| - field); | 
| + return base::MakeUnique< | 
| + CreditCardEditorViewController::CreditCardValidationDelegate>(field); | 
| } | 
| -CreditCardEditorViewController::ValidationDelegate::ValidationDelegate( | 
| - const EditorField& field) | 
| +std::unique_ptr<ui::ComboboxModel> | 
| +CreditCardEditorViewController::GetComboboxModelForType( | 
| + const autofill::ServerFieldType& type) { | 
| + switch (type) { | 
| + case autofill::CREDIT_CARD_EXP_MONTH: | 
| + return std::unique_ptr<ui::ComboboxModel>( | 
| + new ui::SimpleComboboxModel(GetExpirationMonthItems())); | 
| + case autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR: | 
| + return std::unique_ptr<ui::ComboboxModel>( | 
| + new ui::SimpleComboboxModel(GetExpirationYearItems())); | 
| + default: | 
| + NOTREACHED(); | 
| + break; | 
| + } | 
| + return std::unique_ptr<ui::ComboboxModel>(); | 
| +} | 
| + | 
| +CreditCardEditorViewController::CreditCardValidationDelegate:: | 
| + CreditCardValidationDelegate(const EditorField& field) | 
| : field_(field) {} | 
| -CreditCardEditorViewController::ValidationDelegate::~ValidationDelegate() {} | 
| +CreditCardEditorViewController::CreditCardValidationDelegate:: | 
| + ~CreditCardValidationDelegate() {} | 
| + | 
| +bool CreditCardEditorViewController::CreditCardValidationDelegate:: | 
| + ValidateTextfield(views::Textfield* textfield) { | 
| + return ValidateValue(textfield->text()); | 
| +} | 
| + | 
| +bool CreditCardEditorViewController::CreditCardValidationDelegate:: | 
| + ValidateCombobox(views::Combobox* combobox) { | 
| + return ValidateValue(combobox->GetTextForRow(combobox->selected_index())); | 
| +} | 
| -bool CreditCardEditorViewController::ValidationDelegate::ValidateTextfield( | 
| - views::Textfield* textfield) { | 
| - if (!textfield->text().empty()) { | 
| +bool CreditCardEditorViewController::CreditCardValidationDelegate:: | 
| + ValidateValue(const base::string16& value) { | 
| + if (!value.empty()) { | 
| base::string16 error_message; | 
| // TODO(mathp): Display |error_message| around |textfield|. | 
| - return autofill::IsValidForType(textfield->text(), field_.type, | 
| - &error_message); | 
| + return autofill::IsValidForType(value, field_.type, &error_message); | 
| } | 
| // TODO(mathp): Display "required" error if applicable. |