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

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

Issue 2709093006: Adding new shipping address editor view to payment flow. (Closed)
Patch Set: Rebase and bot error fixes Created 3 years, 9 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/views/payments/shipping_address_editor_view_controll er.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/location.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/strings/string16.h"
18 #include "base/strings/utf_string_conversions.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"
22 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h"
23 #include "chrome/browser/ui/views/payments/validating_combobox.h"
24 #include "chrome/browser/ui/views/payments/validating_textfield.h"
25 #include "chrome/grit/generated_resources.h"
26 #include "components/autofill/core/browser/autofill_address_util.h"
27 #include "components/autofill/core/browser/autofill_country.h"
28 #include "components/autofill/core/browser/autofill_type.h"
29 #include "components/autofill/core/browser/country_combobox_model.h"
30 #include "components/autofill/core/browser/field_types.h"
31 #include "components/autofill/core/browser/personal_data_manager.h"
32 #include "components/autofill/core/browser/region_combobox_model.h"
33 #include "components/autofill/core/browser/validation.h"
34 #include "components/autofill/core/common/autofill_constants.h"
35 #include "components/payments/content/payment_request.h"
36 #include "content/public/browser/web_contents.h"
37 #include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
38 #include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
39 #include "third_party/libaddressinput/messages.h"
40 // TODO(mad): Bring back when we solved the double base includes issues.
41 // #include "third_party/libphonenumber/phonenumber_api.h"
42 #include "ui/base/l10n/l10n_util.h"
43 #include "ui/views/controls/textfield/textfield.h"
44
45 // TODO(mad): Bring back when we can include libphonenumber/phonenumber_api.h.
46 // using ::i18n::phonenumbers::PhoneNumber;
47 // using ::i18n::phonenumbers::PhoneNumberUtil;
48
49 namespace payments {
50
51 namespace {
52
53 const char* kAddressValidationDataURL =
54 "https://chromium-i18n.appspot.com/ssl-aggregate-address/";
55
56 autofill::ServerFieldType GetFieldTypeFromString(const std::string& type) {
57 if (type == autofill::kFullNameField)
58 return autofill::NAME_FULL;
59 if (type == autofill::kCompanyNameField)
60 return autofill::COMPANY_NAME;
61 if (type == autofill::kAddressLineField)
62 return autofill::ADDRESS_HOME_STREET_ADDRESS;
63 if (type == autofill::kDependentLocalityField)
64 return autofill::ADDRESS_HOME_DEPENDENT_LOCALITY;
65 if (type == autofill::kCityField)
66 return autofill::ADDRESS_HOME_CITY;
67 if (type == autofill::kStateField)
68 return autofill::ADDRESS_HOME_STATE;
69 if (type == autofill::kPostalCodeField)
70 return autofill::ADDRESS_HOME_ZIP;
71 if (type == autofill::kSortingCodeField)
72 return autofill::ADDRESS_HOME_SORTING_CODE;
73 if (type == autofill::kCountryField)
74 return autofill::ADDRESS_HOME_COUNTRY;
75 NOTREACHED();
76 return autofill::UNKNOWN_TYPE;
77 }
78
79 } // namespace
80
81 ShippingAddressEditorViewController::ShippingAddressEditorViewController(
82 PaymentRequestSpec* spec,
83 PaymentRequestState* state,
84 PaymentRequestDialogView* dialog)
85 : EditorViewController(spec, state, dialog) {
86 UpdateEditorFields();
87 }
88
89 ShippingAddressEditorViewController::~ShippingAddressEditorViewController() {}
90
91 std::unique_ptr<views::View>
92 ShippingAddressEditorViewController::CreateHeaderView() {
93 return base::MakeUnique<views::View>();
94 }
95
96 int ShippingAddressEditorViewController::GetViewHeaderTitleId() const {
97 return IDS_PAYMENT_REQUEST_ADDRESS_EDITOR_ADD_TITLE;
98 }
99
100 std::vector<EditorField>
101 ShippingAddressEditorViewController::GetFieldDefinitions() {
102 return editor_fields_;
103 }
104
105 bool ShippingAddressEditorViewController::ValidateModelAndSave() {
106 autofill::AutofillProfile profile;
107 profile.set_origin(autofill::kSettingsOrigin);
108 for (const auto& field : text_fields()) {
109 // Force a blur in case the value was left untouched.
110 field.first->OnBlur();
111 // ValidatingTextfield* is the key, EditorField is the value.
112 if (field.first->invalid())
113 return false;
114
115 profile.SetRawInfo(field.second.type, field.first->text());
116 }
117 for (const auto& field : comboboxes()) {
118 // ValidatingCombobox* is the key, EditorField is the value.
119 ValidatingCombobox* combobox = field.first;
120 if (combobox->invalid())
121 return false;
122
123 if (combobox->id() == autofill::ADDRESS_HOME_COUNTRY) {
124 profile.SetRawInfo(
125 field.second.type,
126 base::UTF8ToUTF16(country_codes_[combobox->selected_index()]));
127 } else {
128 profile.SetRawInfo(field.second.type,
129 combobox->GetTextForRow(combobox->selected_index()));
130 }
131 }
132
133 // Add the profile (will not add a duplicate).
134 state()->GetPersonalDataManager()->AddProfile(profile);
135
136 return true;
137 }
138
139 std::unique_ptr<ValidationDelegate>
140 ShippingAddressEditorViewController::CreateValidationDelegate(
141 const EditorField& field) {
142 return base::MakeUnique<
143 ShippingAddressEditorViewController::ShippingAddressValidationDelegate>(
144 this, field);
145 }
146
147 std::unique_ptr<ui::ComboboxModel>
148 ShippingAddressEditorViewController::GetComboboxModelForType(
149 const autofill::ServerFieldType& type) {
150 switch (type) {
151 case autofill::ADDRESS_HOME_COUNTRY: {
152 autofill::CountryComboboxModel* model =
153 new autofill::CountryComboboxModel();
154 model->SetCountries(*state()->GetPersonalDataManager(),
155 base::Callback<bool(const std::string&)>(),
156 state()->GetPersonalDataManager()->app_locale());
157 country_codes_.clear();
158 for (size_t i = 0; i < model->countries().size(); ++i) {
159 if (model->countries()[i].get())
160 country_codes_.push_back(model->countries()[i]->country_code());
161 else
162 country_codes_.push_back(""); // Separator.
163 }
164 return std::unique_ptr<ui::ComboboxModel>(model);
165 }
166 case autofill::ADDRESS_HOME_STATE: {
167 return std::unique_ptr<
168 ui::ComboboxModel>(new autofill::RegionComboboxModel(
169 base::WrapUnique(new autofill::ChromeMetadataSource(
170 kAddressValidationDataURL,
171 state()->GetPersonalDataManager()->GetURLRequestContextGetter())),
172 autofill::ValidationRulesStorageFactory::CreateStorage(),
173 state()->GetPersonalDataManager()->app_locale(),
174 country_codes_[chosen_country_index_]));
175 }
176 default:
177 NOTREACHED();
178 break;
179 }
180 return std::unique_ptr<ui::ComboboxModel>();
181 }
182
183 void ShippingAddressEditorViewController::OnPerformAction(
184 views::Combobox* sender) {
185 if (sender->id() != autofill::ADDRESS_HOME_COUNTRY)
186 return;
187 if (chosen_country_index_ != sender->selected_index()) {
188 chosen_country_index_ = sender->selected_index();
189 OnCountryChanged(sender);
190 }
191 }
192
193 void ShippingAddressEditorViewController::UpdateEditorView() {
194 EditorViewController::UpdateEditorView();
195 if (chosen_country_index_ > 0) {
196 views::Combobox* country_combo_box = static_cast<views::Combobox*>(
197 dialog()->GetViewByID(autofill::ADDRESS_HOME_COUNTRY));
198 DCHECK(country_combo_box);
199 country_combo_box->SetSelectedIndex(chosen_country_index_);
200 }
201 }
202
203 void ShippingAddressEditorViewController::UpdateEditorFields() {
204 editor_fields_.clear();
205 std::unique_ptr<base::ListValue> components(new base::ListValue);
206 std::string unused;
207 std::string chosen_country_code;
208 if (chosen_country_index_ < country_codes_.size())
209 chosen_country_code = country_codes_[chosen_country_index_];
210
211 autofill::GetAddressComponents(
212 chosen_country_code, state()->GetPersonalDataManager()->app_locale(),
213 components.get(), &unused);
214
215 for (size_t lineIndex = 0; lineIndex < components->GetSize(); ++lineIndex) {
216 const base::ListValue* line = nullptr;
217 if (!components->GetList(lineIndex, &line)) {
218 NOTREACHED();
219 return;
220 }
221 DCHECK_NE(nullptr, line);
222 for (size_t componentIndex = 0; componentIndex < line->GetSize();
223 ++componentIndex) {
224 const base::DictionaryValue* component = nullptr;
225 if (!line->GetDictionary(componentIndex, &component)) {
226 NOTREACHED();
227 return;
228 }
229 std::string field_type;
230 if (!component->GetString(autofill::kFieldTypeKey, &field_type)) {
231 NOTREACHED();
232 return;
233 }
234 std::string field_name;
235 if (!component->GetString(autofill::kFieldNameKey, &field_name)) {
236 NOTREACHED();
237 return;
238 }
239 std::string field_length;
240 if (!component->GetString(autofill::kFieldLengthKey, &field_length)) {
241 NOTREACHED();
242 return;
243 }
244 EditorField::LengthHint length_hint = EditorField::LengthHint::HINT_LONG;
245 if (field_length == autofill::kShortField)
246 length_hint = EditorField::LengthHint::HINT_SHORT;
247 else
248 DCHECK_EQ(autofill::kLongField, field_length);
249 autofill::ServerFieldType server_field_type =
250 GetFieldTypeFromString(field_type);
251 EditorField::ControlType control_type =
252 EditorField::ControlType::TEXTFIELD;
253 if (server_field_type == autofill::ADDRESS_HOME_COUNTRY ||
254 server_field_type == autofill::ADDRESS_HOME_STATE) {
255 control_type = EditorField::ControlType::COMBOBOX;
256 }
257 editor_fields_.push_back(EditorField(
258 server_field_type, base::UTF8ToUTF16(field_name), length_hint,
259 server_field_type != autofill::COMPANY_NAME, // required.
260 control_type));
261 // Insert the Country combo box right after NAME_FULL.
262 if (server_field_type == autofill::NAME_FULL) {
263 editor_fields_.push_back(
264 EditorField(autofill::ADDRESS_HOME_COUNTRY,
265 l10n_util::GetStringUTF16(
266 IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL),
267 EditorField::LengthHint::HINT_LONG, true,
268 EditorField::ControlType::COMBOBOX));
269 }
270 }
271 }
272 // Always add phone number at the end.
273 editor_fields_.push_back(
274 EditorField(autofill::PHONE_HOME_NUMBER,
275 l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE),
276 EditorField::LengthHint::HINT_SHORT, false, // required.
Mathieu 2017/03/21 17:10:15 Let's make the phone field LONG
MAD 2017/03/21 19:28:34 Done.
277 EditorField::ControlType::TEXTFIELD));
278 }
279
280 void ShippingAddressEditorViewController::OnCountryChanged(
281 views::Combobox* combobox) {
282 // Make sure to unfocus the combo box so we can remove it when we update the
283 // view.
284 combobox->SetFocusBehavior(views::View::FocusBehavior::NEVER);
285 UpdateEditorFields();
286 // Let the focus change complete before updating the editor.
287 base::ThreadTaskRunnerHandle::Get()->PostTask(
288 FROM_HERE,
289 base::Bind(&ShippingAddressEditorViewController::UpdateEditorView,
290 base::Unretained(this)));
291 }
292
293 ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
294 ShippingAddressValidationDelegate(
295 ShippingAddressEditorViewController* parent,
296 const EditorField& field)
297 : field_(field) /* TODO(mad): Bring back when needed:, parent_(parent) */ {}
298
299 ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
300 ~ShippingAddressValidationDelegate() {}
301
302 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
303 ValidateTextfield(views::Textfield* textfield) {
304 return ValidateValue(textfield->text());
305 }
306
307 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
308 ValidateCombobox(views::Combobox* combobox) {
309 return ValidateValue(combobox->GetTextForRow(combobox->selected_index()));
310 }
311
312 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
313 ValidateValue(const base::string16& value) {
314 /*
315 TODO(mad): Bring back when we can include libphonenumber/phonenumber_api.h.
316 if (field_.type == autofill::PHONE_HOME_NUMBER) {
317 PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
318 PhoneNumber number_object;
319 return phone_util->Parse(
320 base::UTF16ToUTF8(value),
321 parent_->country_codes_[parent_->chosen_country_index_],
322 &number_object) == PhoneNumberUtil::NO_PARSING_ERROR;
323
324 }*/
325 // TODO(mathp): Display "required" error if applicable.
326 return !field_.required || !value.empty();
327 }
328
329 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698