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: chrome/browser/ui/views/payments/shipping_address_editor_view_controller.cc

Issue 2803443003: [Payments] Added region load failure tolerance and tests to PR editor. (Closed)
Patch Set: Removed unneeded include. Created 3 years, 8 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 <memory> 7 #include <memory>
8 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/bind_helpers.h" 13 #include "base/bind_helpers.h"
14 #include "base/location.h" 14 #include "base/location.h"
15 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
16 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
17 #include "base/strings/string16.h" 17 #include "base/strings/string16.h"
18 #include "base/strings/utf_string_conversions.h" 18 #include "base/strings/utf_string_conversions.h"
19 #include "base/threading/thread_task_runner_handle.h" 19 #include "base/threading/thread_task_runner_handle.h"
20 #include "chrome/browser/autofill/validation_rules_storage_factory.h"
21 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h" 21 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h"
23 #include "chrome/browser/ui/views/payments/validating_combobox.h" 22 #include "chrome/browser/ui/views/payments/validating_combobox.h"
24 #include "chrome/browser/ui/views/payments/validating_textfield.h" 23 #include "chrome/browser/ui/views/payments/validating_textfield.h"
25 #include "chrome/grit/generated_resources.h" 24 #include "chrome/grit/generated_resources.h"
26 #include "components/autofill/core/browser/autofill_address_util.h" 25 #include "components/autofill/core/browser/autofill_address_util.h"
27 #include "components/autofill/core/browser/autofill_country.h" 26 #include "components/autofill/core/browser/autofill_country.h"
28 #include "components/autofill/core/browser/autofill_type.h" 27 #include "components/autofill/core/browser/autofill_type.h"
29 #include "components/autofill/core/browser/country_combobox_model.h" 28 #include "components/autofill/core/browser/country_combobox_model.h"
30 #include "components/autofill/core/browser/field_types.h" 29 #include "components/autofill/core/browser/field_types.h"
31 #include "components/autofill/core/browser/personal_data_manager.h" 30 #include "components/autofill/core/browser/personal_data_manager.h"
32 #include "components/autofill/core/browser/region_combobox_model.h" 31 #include "components/autofill/core/browser/region_combobox_model.h"
33 #include "components/autofill/core/browser/validation.h" 32 #include "components/autofill/core/browser/validation.h"
34 #include "components/autofill/core/common/autofill_constants.h" 33 #include "components/autofill/core/common/autofill_constants.h"
35 #include "components/payments/content/payment_request_state.h" 34 #include "components/payments/content/payment_request_state.h"
36 #include "components/strings/grit/components_strings.h" 35 #include "components/strings/grit/components_strings.h"
37 #include "content/public/browser/web_contents.h" 36 #include "content/public/browser/web_contents.h"
38 #include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
39 #include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
40 #include "third_party/libaddressinput/messages.h" 37 #include "third_party/libaddressinput/messages.h"
41 #include "ui/base/l10n/l10n_util.h" 38 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/views/controls/textfield/textfield.h" 39 #include "ui/views/controls/textfield/textfield.h"
43 40
44 namespace payments { 41 namespace payments {
45 42
46 namespace { 43 namespace {
47 44
48 // Converts a field type in string format as returned by 45 // Converts a field type in string format as returned by
49 // autofill::GetAddressComponents into the appropriate autofill::ServerFieldType 46 // autofill::GetAddressComponents into the appropriate autofill::ServerFieldType
(...skipping 21 matching lines...) Expand all
71 return autofill::UNKNOWN_TYPE; 68 return autofill::UNKNOWN_TYPE;
72 } 69 }
73 70
74 } // namespace 71 } // namespace
75 72
76 ShippingAddressEditorViewController::ShippingAddressEditorViewController( 73 ShippingAddressEditorViewController::ShippingAddressEditorViewController(
77 PaymentRequestSpec* spec, 74 PaymentRequestSpec* spec,
78 PaymentRequestState* state, 75 PaymentRequestState* state,
79 PaymentRequestDialogView* dialog, 76 PaymentRequestDialogView* dialog,
80 autofill::AutofillProfile* profile) 77 autofill::AutofillProfile* profile)
81 : EditorViewController(spec, state, dialog), profile_to_edit_(profile) { 78 : EditorViewController(spec, state, dialog),
79 profile_to_edit_(profile),
80 chosen_country_index_(0),
81 failed_to_load_region_data_(false) {
82 UpdateEditorFields(); 82 UpdateEditorFields();
83 } 83 }
84 84
85 ShippingAddressEditorViewController::~ShippingAddressEditorViewController() {} 85 ShippingAddressEditorViewController::~ShippingAddressEditorViewController() {}
86 86
87 std::unique_ptr<views::View> 87 std::unique_ptr<views::View>
88 ShippingAddressEditorViewController::CreateHeaderView() { 88 ShippingAddressEditorViewController::CreateHeaderView() {
89 return base::MakeUnique<views::View>(); 89 return base::MakeUnique<views::View>();
90 } 90 }
91 91
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 model->SetCountries(*state()->GetPersonalDataManager(), 181 model->SetCountries(*state()->GetPersonalDataManager(),
182 base::Callback<bool(const std::string&)>(), 182 base::Callback<bool(const std::string&)>(),
183 state()->GetApplicationLocale()); 183 state()->GetApplicationLocale());
184 country_codes_.clear(); 184 country_codes_.clear();
185 for (size_t i = 0; i < model->countries().size(); ++i) { 185 for (size_t i = 0; i < model->countries().size(); ++i) {
186 if (model->countries()[i].get()) 186 if (model->countries()[i].get())
187 country_codes_.push_back(model->countries()[i]->country_code()); 187 country_codes_.push_back(model->countries()[i]->country_code());
188 else 188 else
189 country_codes_.push_back(""); // Separator. 189 country_codes_.push_back(""); // Separator.
190 } 190 }
191 return std::unique_ptr<ui::ComboboxModel>(model.release()); 191 return std::move(model);
192 } 192 }
193 case autofill::ADDRESS_HOME_STATE: { 193 case autofill::ADDRESS_HOME_STATE: {
194 return std::unique_ptr< 194 std::unique_ptr<autofill::RegionComboboxModel> model =
195 ui::ComboboxModel>(new autofill::RegionComboboxModel( 195 base::MakeUnique<autofill::RegionComboboxModel>(
196 base::WrapUnique(new autofill::ChromeMetadataSource( 196 state()->GetAddressInputSource(),
197 I18N_ADDRESS_VALIDATION_DATA_URL, 197 state()->GetAddressInputStorage(),
198 state()->GetPersonalDataManager()->GetURLRequestContextGetter())), 198 state()->GetApplicationLocale(),
199 autofill::ValidationRulesStorageFactory::CreateStorage(), 199 country_codes_[chosen_country_index_]);
200 state()->GetApplicationLocale(), 200 // If the data was already pre-loaded, the observer won't get notified so
201 country_codes_[chosen_country_index_])); 201 // we have to check for failure here.
202 if (!model->pending_region_data_load()) {
203 failed_to_load_region_data_ = model->failed_to_load_data();
204 if (failed_to_load_region_data_)
205 OnDataChanged();
206 }
207 return std::move(model);
202 } 208 }
203 default: 209 default:
204 NOTREACHED(); 210 NOTREACHED();
205 break; 211 break;
206 } 212 }
207 return std::unique_ptr<ui::ComboboxModel>(); 213 return std::unique_ptr<ui::ComboboxModel>();
208 } 214 }
209 215
210 void ShippingAddressEditorViewController::OnPerformAction( 216 void ShippingAddressEditorViewController::OnPerformAction(
211 views::Combobox* sender) { 217 views::Combobox* sender) {
212 EditorViewController::OnPerformAction(sender); 218 EditorViewController::OnPerformAction(sender);
213 if (sender->id() != autofill::ADDRESS_HOME_COUNTRY) 219 if (sender->id() != autofill::ADDRESS_HOME_COUNTRY)
214 return; 220 return;
215 DCHECK_GE(sender->selected_index(), 0); 221 DCHECK_GE(sender->selected_index(), 0);
216 if (chosen_country_index_ != static_cast<size_t>(sender->selected_index())) { 222 if (chosen_country_index_ != static_cast<size_t>(sender->selected_index())) {
217 chosen_country_index_ = sender->selected_index(); 223 chosen_country_index_ = sender->selected_index();
218 OnCountryChanged(sender); 224 failed_to_load_region_data_ = false;
225 OnDataChanged();
219 } 226 }
220 } 227 }
221 228
222 void ShippingAddressEditorViewController::UpdateEditorView() { 229 void ShippingAddressEditorViewController::UpdateEditorView() {
223 EditorViewController::UpdateEditorView(); 230 EditorViewController::UpdateEditorView();
224 if (chosen_country_index_ > 0UL) { 231 if (chosen_country_index_ > 0UL) {
225 views::Combobox* country_combo_box = static_cast<views::Combobox*>( 232 views::Combobox* country_combo_box = static_cast<views::Combobox*>(
226 dialog()->GetViewByID(autofill::ADDRESS_HOME_COUNTRY)); 233 dialog()->GetViewByID(autofill::ADDRESS_HOME_COUNTRY));
227 DCHECK(country_combo_box); 234 DCHECK(country_combo_box);
228 country_combo_box->SetSelectedIndex(chosen_country_index_); 235 country_combo_box->SetSelectedIndex(chosen_country_index_);
229 } 236 }
230 } 237 }
231 238
232 base::string16 ShippingAddressEditorViewController::GetSheetTitle() { 239 base::string16 ShippingAddressEditorViewController::GetSheetTitle() {
233 return l10n_util::GetStringUTF16( 240 return l10n_util::GetStringUTF16(
234 IDS_PAYMENT_REQUEST_ADDRESS_EDITOR_ADD_TITLE); 241 IDS_PAYMENT_REQUEST_ADDRESS_EDITOR_ADD_TITLE);
235 } 242 }
236 243
237 void ShippingAddressEditorViewController::UpdateEditorFields() { 244 void ShippingAddressEditorViewController::UpdateEditorFields() {
238 editor_fields_.clear(); 245 editor_fields_.clear();
239 std::string chosen_country_code; 246 std::string chosen_country_code;
240 if (chosen_country_index_ < country_codes_.size()) 247 if (chosen_country_index_ < country_codes_.size())
241 chosen_country_code = country_codes_[chosen_country_index_]; 248 chosen_country_code = country_codes_[chosen_country_index_];
242 249
243 std::unique_ptr<base::ListValue> components(new base::ListValue); 250 std::unique_ptr<base::ListValue> components(new base::ListValue);
244 std::string unused; 251 std::string unused;
245 autofill::GetAddressComponents(chosen_country_code, 252 autofill::GetAddressComponents(chosen_country_code,
246 state()->GetApplicationLocale(), 253 state()->GetApplicationLocale(),
247 components.get(), &unused); 254 components.get(), &unused);
248
249 for (size_t line_index = 0; line_index < components->GetSize(); 255 for (size_t line_index = 0; line_index < components->GetSize();
250 ++line_index) { 256 ++line_index) {
251 const base::ListValue* line = nullptr; 257 const base::ListValue* line = nullptr;
252 if (!components->GetList(line_index, &line)) { 258 if (!components->GetList(line_index, &line)) {
253 NOTREACHED(); 259 NOTREACHED();
254 return; 260 return;
255 } 261 }
256 DCHECK_NE(nullptr, line); 262 DCHECK_NE(nullptr, line);
257 for (size_t component_index = 0; component_index < line->GetSize(); 263 for (size_t component_index = 0; component_index < line->GetSize();
258 ++component_index) { 264 ++component_index) {
(...skipping 20 matching lines...) Expand all
279 EditorField::LengthHint length_hint = EditorField::LengthHint::HINT_LONG; 285 EditorField::LengthHint length_hint = EditorField::LengthHint::HINT_LONG;
280 if (field_length == autofill::kShortField) 286 if (field_length == autofill::kShortField)
281 length_hint = EditorField::LengthHint::HINT_SHORT; 287 length_hint = EditorField::LengthHint::HINT_SHORT;
282 else 288 else
283 DCHECK_EQ(autofill::kLongField, field_length); 289 DCHECK_EQ(autofill::kLongField, field_length);
284 autofill::ServerFieldType server_field_type = 290 autofill::ServerFieldType server_field_type =
285 GetFieldTypeFromString(field_type); 291 GetFieldTypeFromString(field_type);
286 EditorField::ControlType control_type = 292 EditorField::ControlType control_type =
287 EditorField::ControlType::TEXTFIELD; 293 EditorField::ControlType::TEXTFIELD;
288 if (server_field_type == autofill::ADDRESS_HOME_COUNTRY || 294 if (server_field_type == autofill::ADDRESS_HOME_COUNTRY ||
289 server_field_type == autofill::ADDRESS_HOME_STATE) { 295 (server_field_type == autofill::ADDRESS_HOME_STATE &&
296 !failed_to_load_region_data_)) {
290 control_type = EditorField::ControlType::COMBOBOX; 297 control_type = EditorField::ControlType::COMBOBOX;
291 } 298 }
292 editor_fields_.emplace_back( 299 editor_fields_.emplace_back(
293 server_field_type, base::UTF8ToUTF16(field_name), length_hint, 300 server_field_type, base::UTF8ToUTF16(field_name), length_hint,
294 /*required=*/server_field_type != autofill::COMPANY_NAME, 301 /*required=*/server_field_type != autofill::COMPANY_NAME,
295 control_type); 302 control_type);
296 // Insert the Country combobox right after NAME_FULL. 303 // Insert the Country combobox right after NAME_FULL.
297 if (server_field_type == autofill::NAME_FULL) { 304 if (server_field_type == autofill::NAME_FULL) {
298 editor_fields_.emplace_back( 305 editor_fields_.emplace_back(
299 autofill::ADDRESS_HOME_COUNTRY, 306 autofill::ADDRESS_HOME_COUNTRY,
300 l10n_util::GetStringUTF16( 307 l10n_util::GetStringUTF16(
301 IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL), 308 IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL),
302 EditorField::LengthHint::HINT_LONG, /*required=*/true, 309 EditorField::LengthHint::HINT_LONG, /*required=*/true,
303 EditorField::ControlType::COMBOBOX); 310 EditorField::ControlType::COMBOBOX);
304 } 311 }
305 } 312 }
306 } 313 }
307 // Always add phone number at the end. 314 // Always add phone number at the end.
308 editor_fields_.emplace_back( 315 editor_fields_.emplace_back(
309 autofill::PHONE_HOME_NUMBER, 316 autofill::PHONE_HOME_NUMBER,
310 l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE), 317 l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE),
311 EditorField::LengthHint::HINT_LONG, /*required=*/false, 318 EditorField::LengthHint::HINT_LONG, /*required=*/false,
312 EditorField::ControlType::TEXTFIELD); 319 EditorField::ControlType::TEXTFIELD);
313 } 320 }
314 321
315 void ShippingAddressEditorViewController::OnCountryChanged( 322 void ShippingAddressEditorViewController::OnDataChanged() {
316 views::Combobox* combobox) {
317 // TODO(crbug.com/703764): save the current state so we can map it to the new 323 // TODO(crbug.com/703764): save the current state so we can map it to the new
318 // country fields as best we can. 324 // country fields as best we can.
319 UpdateEditorFields(); 325 UpdateEditorFields();
320 326
321 // The editor can't be updated while in the middle of a combobox event. 327 // The editor can't be updated while in the middle of a combobox event.
322 base::ThreadTaskRunnerHandle::Get()->PostTask( 328 base::ThreadTaskRunnerHandle::Get()->PostTask(
323 FROM_HERE, 329 FROM_HERE,
324 base::Bind(&ShippingAddressEditorViewController::UpdateEditorView, 330 base::Bind(&ShippingAddressEditorViewController::UpdateEditorView,
325 base::Unretained(this))); 331 base::Unretained(this)));
326 } 332 }
327 333
334 void ShippingAddressEditorViewController::OnComboboxModelChanged(
335 views::Combobox* combobox) {
336 if (combobox->id() != autofill::ADDRESS_HOME_STATE)
337 return;
338 autofill::RegionComboboxModel* model =
339 static_cast<autofill::RegionComboboxModel*>(combobox->model());
340 if (model->pending_region_data_load())
341 return;
342 if (model->failed_to_load_data()) {
343 failed_to_load_region_data_ = true;
344 OnDataChanged();
345 }
346 }
347
328 ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: 348 ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
329 ShippingAddressValidationDelegate( 349 ShippingAddressValidationDelegate(
330 ShippingAddressEditorViewController* controller, 350 ShippingAddressEditorViewController* controller,
331 const EditorField& field) 351 const EditorField& field)
332 : field_(field), controller_(controller) {} 352 : field_(field), controller_(controller) {}
333 353
334 ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: 354 ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
335 ~ShippingAddressValidationDelegate() {} 355 ~ShippingAddressValidationDelegate() {}
336 356
337 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: 357 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
338 ValidateTextfield(views::Textfield* textfield) { 358 ValidateTextfield(views::Textfield* textfield) {
339 return ValidateValue(textfield->text()); 359 return ValidateValue(textfield->text());
340 } 360 }
341 361
342 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: 362 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
343 ValidateCombobox(views::Combobox* combobox) { 363 ValidateCombobox(views::Combobox* combobox) {
344 return ValidateValue(combobox->GetTextForRow(combobox->selected_index())); 364 return ValidateValue(combobox->GetTextForRow(combobox->selected_index()));
345 } 365 }
346 366
367 void ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
368 ComboboxModelChanged(views::Combobox* combobox) {
369 controller_->OnComboboxModelChanged(combobox);
370 }
371
347 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate:: 372 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
348 ValidateValue(const base::string16& value) { 373 ValidateValue(const base::string16& value) {
349 if (!value.empty()) { 374 if (!value.empty()) {
350 if (field_.type == autofill::PHONE_HOME_NUMBER && 375 if (field_.type == autofill::PHONE_HOME_NUMBER &&
351 !autofill::IsValidPhoneNumber( 376 !autofill::IsValidPhoneNumber(
352 value, 377 value,
353 controller_->country_codes_[controller_->chosen_country_index_])) { 378 controller_->country_codes_[controller_->chosen_country_index_])) {
354 controller_->DisplayErrorMessageForField( 379 controller_->DisplayErrorMessageForField(
355 field_, l10n_util::GetStringUTF16( 380 field_, l10n_util::GetStringUTF16(
356 IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE)); 381 IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE));
357 return false; 382 return false;
358 } 383 }
359 // As long as other field types are non-empty, they are valid. 384 // As long as other field types are non-empty, they are valid.
360 controller_->DisplayErrorMessageForField(field_, base::ASCIIToUTF16("")); 385 controller_->DisplayErrorMessageForField(field_, base::ASCIIToUTF16(""));
361 return true; 386 return true;
362 } 387 }
363 388
364 bool is_required_valid = !field_.required; 389 bool is_required_valid = !field_.required;
365 const base::string16 displayed_message = 390 const base::string16 displayed_message =
366 is_required_valid ? base::ASCIIToUTF16("") 391 is_required_valid ? base::ASCIIToUTF16("")
367 : l10n_util::GetStringUTF16( 392 : l10n_util::GetStringUTF16(
368 IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE); 393 IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE);
369 controller_->DisplayErrorMessageForField(field_, displayed_message); 394 controller_->DisplayErrorMessageForField(field_, displayed_message);
370 return is_required_valid; 395 return is_required_valid;
371 } 396 }
372 397
373 } // namespace payments 398 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698