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

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

Issue 2883333003: Payment request shipping address editor now properly handles countries (Closed)
Patch Set: Rebase 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/shipping_address_editor_view_controll er.h" 5 #include "chrome/browser/ui/views/payments/shipping_address_editor_view_controll er.h"
6 6
7 #include <utility>
8
9 #include "base/bind.h" 7 #include "base/bind.h"
10 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
11 #include "base/callback.h" 9 #include "base/callback.h"
12 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
13 #include "base/strings/utf_string_conversions.h" 11 #include "base/strings/utf_string_conversions.h"
14 #include "base/threading/thread_task_runner_handle.h" 12 #include "base/threading/thread_task_runner_handle.h"
15 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h" 13 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h"
16 #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h" 14 #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
17 #include "chrome/browser/ui/views/payments/validating_combobox.h" 15 #include "chrome/browser/ui/views/payments/validating_combobox.h"
18 #include "chrome/browser/ui/views/payments/validating_textfield.h" 16 #include "chrome/browser/ui/views/payments/validating_textfield.h"
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 BackNavigationType back_navigation_type, 70 BackNavigationType back_navigation_type,
73 base::OnceClosure on_edited, 71 base::OnceClosure on_edited,
74 base::OnceCallback<void(const autofill::AutofillProfile&)> on_added, 72 base::OnceCallback<void(const autofill::AutofillProfile&)> on_added,
75 autofill::AutofillProfile* profile) 73 autofill::AutofillProfile* profile)
76 : EditorViewController(spec, state, dialog, back_navigation_type), 74 : EditorViewController(spec, state, dialog, back_navigation_type),
77 on_edited_(std::move(on_edited)), 75 on_edited_(std::move(on_edited)),
78 on_added_(std::move(on_added)), 76 on_added_(std::move(on_added)),
79 profile_to_edit_(profile), 77 profile_to_edit_(profile),
80 chosen_country_index_(0), 78 chosen_country_index_(0),
81 failed_to_load_region_data_(false) { 79 failed_to_load_region_data_(false) {
80 autofill::CountryComboboxModel model;
Mathieu 2017/05/16 20:10:06 I would put lines 80-112 inside a private function
MAD 2017/05/17 12:38:11 Done.
81 model.SetCountries(*state->GetPersonalDataManager(),
82 base::Callback<bool(const std::string&)>(),
83 state->GetApplicationLocale());
84 for (size_t i = 0; i < model.countries().size(); ++i) {
85 autofill::AutofillCountry* country(model.countries()[i].get());
86 if (country) {
87 countries_.push_back(
88 std::make_pair(country->country_code(), country->name()));
89 } else {
90 // Separator.
91 countries_.push_back(std::make_pair("", base::UTF8ToUTF16("")));
92 }
93 }
94 // If there is a profile to edit, make sure to use its country for the initial
95 // |chosen_country_index_|.
96 if (profile_to_edit_) {
97 autofill::AutofillType country_type(autofill::ADDRESS_HOME_COUNTRY);
98 base::string16 chosen_country(
99 profile_to_edit_->GetInfo(country_type, state->GetApplicationLocale()));
100 for (chosen_country_index_ = 0; chosen_country_index_ < countries_.size();
101 ++chosen_country_index_) {
102 if (chosen_country == countries_[chosen_country_index_].second)
103 break;
104 }
105 if (chosen_country_index_ >= countries_.size()) {
106 LOG(ERROR) << "Unexpected country: " << chosen_country;
107 CHECK_GT(countries_.size(), 0);
Mathieu 2017/05/16 20:10:06 could this ever happen in the wild? Crashing is pr
MAD 2017/05/17 12:38:10 It would crash below otherwise... But now that y
108 chosen_country_index_ = 0;
109 profile_to_edit_->SetInfo(country_type,
110 countries_[chosen_country_index_].second,
111 state->GetApplicationLocale());
112 }
113 }
82 UpdateEditorFields(); 114 UpdateEditorFields();
83 } 115 }
84 116
85 ShippingAddressEditorViewController::~ShippingAddressEditorViewController() {} 117 ShippingAddressEditorViewController::~ShippingAddressEditorViewController() {}
86 118
87 std::vector<EditorField> 119 std::vector<EditorField>
88 ShippingAddressEditorViewController::GetFieldDefinitions() { 120 ShippingAddressEditorViewController::GetFieldDefinitions() {
89 return editor_fields_; 121 return editor_fields_;
90 } 122 }
91 123
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 std::unique_ptr<ui::ComboboxModel> 176 std::unique_ptr<ui::ComboboxModel>
145 ShippingAddressEditorViewController::GetComboboxModelForType( 177 ShippingAddressEditorViewController::GetComboboxModelForType(
146 const autofill::ServerFieldType& type) { 178 const autofill::ServerFieldType& type) {
147 switch (type) { 179 switch (type) {
148 case autofill::ADDRESS_HOME_COUNTRY: { 180 case autofill::ADDRESS_HOME_COUNTRY: {
149 std::unique_ptr<autofill::CountryComboboxModel> model = 181 std::unique_ptr<autofill::CountryComboboxModel> model =
150 base::MakeUnique<autofill::CountryComboboxModel>(); 182 base::MakeUnique<autofill::CountryComboboxModel>();
151 model->SetCountries(*state()->GetPersonalDataManager(), 183 model->SetCountries(*state()->GetPersonalDataManager(),
152 base::Callback<bool(const std::string&)>(), 184 base::Callback<bool(const std::string&)>(),
153 state()->GetApplicationLocale()); 185 state()->GetApplicationLocale());
154 country_codes_.clear();
155 for (size_t i = 0; i < model->countries().size(); ++i) {
156 if (model->countries()[i].get())
157 country_codes_.push_back(model->countries()[i]->country_code());
158 else
159 country_codes_.push_back(""); // Separator.
160 }
161 return std::move(model); 186 return std::move(model);
162 } 187 }
163 case autofill::ADDRESS_HOME_STATE: { 188 case autofill::ADDRESS_HOME_STATE: {
164 std::unique_ptr<autofill::RegionComboboxModel> model = 189 std::unique_ptr<autofill::RegionComboboxModel> model =
165 base::MakeUnique<autofill::RegionComboboxModel>(); 190 base::MakeUnique<autofill::RegionComboboxModel>();
166 model->LoadRegionData(country_codes_[chosen_country_index_], 191 model->LoadRegionData(countries_[chosen_country_index_].first,
167 state()->GetRegionDataLoader(), 192 state()->GetRegionDataLoader(),
168 /*timeout_ms=*/5000); 193 /*timeout_ms=*/5000);
169 if (!model->IsPendingRegionDataLoad()) { 194 if (!model->IsPendingRegionDataLoad()) {
170 // If the data was already pre-loaded, the observer won't get notified 195 // If the data was already pre-loaded, the observer won't get notified
171 // so we have to check for failure here. 196 // so we have to check for failure here.
172 failed_to_load_region_data_ = model->failed_to_load_data(); 197 failed_to_load_region_data_ = model->failed_to_load_data();
173 if (failed_to_load_region_data_) { 198 if (failed_to_load_region_data_) {
174 // We can update the view synchronously while building the view. 199 // We can't update the view synchronously while building the view.
175 OnDataChanged(/*synchronous=*/false); 200 OnDataChanged(/*synchronous=*/false);
176 } 201 }
177 } 202 }
178 return std::move(model); 203 return std::move(model);
179 } 204 }
180 default: 205 default:
181 NOTREACHED(); 206 NOTREACHED();
182 break; 207 break;
183 } 208 }
184 return std::unique_ptr<ui::ComboboxModel>(); 209 return std::unique_ptr<ui::ComboboxModel>();
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 ShippingAddressEditorViewController::CreatePrimaryButton() { 247 ShippingAddressEditorViewController::CreatePrimaryButton() {
223 std::unique_ptr<views::Button> button( 248 std::unique_ptr<views::Button> button(
224 EditorViewController::CreatePrimaryButton()); 249 EditorViewController::CreatePrimaryButton());
225 button->set_id(static_cast<int>(DialogViewID::SAVE_ADDRESS_BUTTON)); 250 button->set_id(static_cast<int>(DialogViewID::SAVE_ADDRESS_BUTTON));
226 return button; 251 return button;
227 } 252 }
228 253
229 void ShippingAddressEditorViewController::UpdateEditorFields() { 254 void ShippingAddressEditorViewController::UpdateEditorFields() {
230 editor_fields_.clear(); 255 editor_fields_.clear();
231 std::string chosen_country_code; 256 std::string chosen_country_code;
232 if (chosen_country_index_ < country_codes_.size()) 257 if (chosen_country_index_ < countries_.size())
233 chosen_country_code = country_codes_[chosen_country_index_]; 258 chosen_country_code = countries_[chosen_country_index_].first;
234 259
235 std::unique_ptr<base::ListValue> components(new base::ListValue); 260 std::unique_ptr<base::ListValue> components(new base::ListValue);
236 std::string unused; 261 std::string unused;
237 autofill::GetAddressComponents(chosen_country_code, 262 autofill::GetAddressComponents(chosen_country_code,
238 state()->GetApplicationLocale(), 263 state()->GetApplicationLocale(),
239 components.get(), &unused); 264 components.get(), &unused);
240 for (size_t line_index = 0; line_index < components->GetSize(); 265 for (size_t line_index = 0; line_index < components->GetSize();
241 ++line_index) { 266 ++line_index) {
242 const base::ListValue* line = nullptr; 267 const base::ListValue* line = nullptr;
243 if (!components->GetList(line_index, &line)) { 268 if (!components->GetList(line_index, &line)) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 FROM_HERE, 341 FROM_HERE,
317 base::BindOnce(&ShippingAddressEditorViewController::UpdateEditorView, 342 base::BindOnce(&ShippingAddressEditorViewController::UpdateEditorView,
318 base::Unretained(this))); 343 base::Unretained(this)));
319 } 344 }
320 } 345 }
321 346
322 bool ShippingAddressEditorViewController::SaveFieldsToProfile( 347 bool ShippingAddressEditorViewController::SaveFieldsToProfile(
323 autofill::AutofillProfile* profile, 348 autofill::AutofillProfile* profile,
324 bool ignore_errors) { 349 bool ignore_errors) {
325 const std::string& locale = state()->GetApplicationLocale(); 350 const std::string& locale = state()->GetApplicationLocale();
351 // The country must be set first, because the profile uses the country to
352 // interpret some of the data (e.g., phone numbers) passed to SetInfo.
353 views::Combobox* combobox = static_cast<views::Combobox*>(
354 dialog()->GetViewByID(autofill::ADDRESS_HOME_COUNTRY));
355 // The combobox can be null when saving to temporary profile while updating
356 // the view.
357 if (combobox) {
358 base::string16 country(combobox->GetTextForRow(combobox->selected_index()));
359 bool success =
360 profile->SetInfo(autofill::AutofillType(autofill::ADDRESS_HOME_COUNTRY),
361 country, locale);
362 LOG_IF(ERROR, !success && !ignore_errors)
363 << "Can't set profile country to: " << country;
364 if (!success && !ignore_errors)
365 return false;
366 } else {
367 DCHECK_EQ(temporary_profile_.get(), profile);
368 }
369
326 bool success = true; 370 bool success = true;
327 for (const auto& field : text_fields()) { 371 for (const auto& field : text_fields()) {
328 // Force a blur in case the value was left untouched. 372 // Force a blur in case the value was left untouched.
329 field.first->OnBlur(); 373 field.first->OnBlur();
330 // ValidatingTextfield* is the key, EditorField is the value. 374 // ValidatingTextfield* is the key, EditorField is the value.
331 if (field.first->invalid()) { 375 if (field.first->invalid()) {
332 success = false; 376 success = false;
333 } else { 377 } else {
334 success = profile->SetInfo(autofill::AutofillType(field.second.type), 378 success = profile->SetInfo(autofill::AutofillType(field.second.type),
335 field.first->text(), locale); 379 field.first->text(), locale);
336 } 380 }
337 LOG_IF(ERROR, !success && !ignore_errors) 381 LOG_IF(ERROR, !success && !ignore_errors)
338 << "Can't setinfo(" << field.second.type << ", " << field.first->text(); 382 << "Can't setinfo(" << field.second.type << ", " << field.first->text();
339 if (!success && !ignore_errors) 383 if (!success && !ignore_errors)
340 return false; 384 return false;
341 } 385 }
342 for (const auto& field : comboboxes()) { 386 for (const auto& field : comboboxes()) {
343 // ValidatingCombobox* is the key, EditorField is the value. 387 // ValidatingCombobox* is the key, EditorField is the value.
344 ValidatingCombobox* combobox = field.first; 388 ValidatingCombobox* combobox = field.first;
389 // The country has already been dealt with.
390 if (combobox->id() == autofill::ADDRESS_HOME_COUNTRY)
391 continue;
345 if (combobox->invalid()) { 392 if (combobox->invalid()) {
346 success = false; 393 success = false;
347 } else { 394 } else {
348 if (combobox->id() == autofill::ADDRESS_HOME_COUNTRY) { 395 success = profile->SetInfo(
349 success = profile->SetInfo( 396 autofill::AutofillType(field.second.type),
350 autofill::AutofillType(field.second.type), 397 combobox->GetTextForRow(combobox->selected_index()), locale);
351 base::UTF8ToUTF16(country_codes_[combobox->selected_index()]),
352 locale);
353 } else {
354 success = profile->SetInfo(
355 autofill::AutofillType(field.second.type),
356 combobox->GetTextForRow(combobox->selected_index()), locale);
357 }
358 } 398 }
359 LOG_IF(ERROR, !success && !ignore_errors) 399 LOG_IF(ERROR, !success && !ignore_errors)
360 << "Can't setinfo(" << field.second.type << ", " 400 << "Can't setinfo(" << field.second.type << ", "
361 << combobox->GetTextForRow(combobox->selected_index()); 401 << combobox->GetTextForRow(combobox->selected_index());
362 if (!success && !ignore_errors) 402 if (!success && !ignore_errors)
363 return false; 403 return false;
364 } 404 }
365 return success; 405 return success;
366 } 406 }
367 407
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 void ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: 448 void ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
409 ComboboxModelChanged(views::Combobox* combobox) { 449 ComboboxModelChanged(views::Combobox* combobox) {
410 controller_->OnComboboxModelChanged(combobox); 450 controller_->OnComboboxModelChanged(combobox);
411 } 451 }
412 452
413 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: 453 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
414 ValidateValue(const base::string16& value) { 454 ValidateValue(const base::string16& value) {
415 if (!value.empty()) { 455 if (!value.empty()) {
416 if (field_.type == autofill::PHONE_HOME_WHOLE_NUMBER && 456 if (field_.type == autofill::PHONE_HOME_WHOLE_NUMBER &&
417 !autofill::IsValidPhoneNumber( 457 !autofill::IsValidPhoneNumber(
418 value, 458 value, controller_->countries_[controller_->chosen_country_index_]
419 controller_->country_codes_[controller_->chosen_country_index_])) { 459 .first)) {
420 controller_->DisplayErrorMessageForField( 460 controller_->DisplayErrorMessageForField(
421 field_, l10n_util::GetStringUTF16( 461 field_, l10n_util::GetStringUTF16(
422 IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE)); 462 IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE));
423 return false; 463 return false;
424 } 464 }
425 // As long as other field types are non-empty, they are valid. 465 // As long as other field types are non-empty, they are valid.
426 controller_->DisplayErrorMessageForField(field_, base::ASCIIToUTF16("")); 466 controller_->DisplayErrorMessageForField(field_, base::ASCIIToUTF16(""));
427 return true; 467 return true;
428 } 468 }
429 bool is_required_valid = !field_.required; 469 bool is_required_valid = !field_.required;
430 const base::string16 displayed_message = 470 const base::string16 displayed_message =
431 is_required_valid ? base::ASCIIToUTF16("") 471 is_required_valid ? base::ASCIIToUTF16("")
432 : l10n_util::GetStringUTF16( 472 : l10n_util::GetStringUTF16(
433 IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE); 473 IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE);
434 controller_->DisplayErrorMessageForField(field_, displayed_message); 474 controller_->DisplayErrorMessageForField(field_, displayed_message);
435 return is_required_valid; 475 return is_required_valid;
436 } 476 }
437 477
438 } // namespace payments 478 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698