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

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: Bot failure fix 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_state.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 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/views/controls/textfield/textfield.h"
42
43 namespace payments {
44
45 namespace {
46
47 // Converts a field type in string format as returned by
48 // autofill::GetAddressComponents into the appropriate autofill::ServerFieldType
49 // enum.
50 autofill::ServerFieldType GetFieldTypeFromString(const std::string& type) {
51 if (type == autofill::kFullNameField)
52 return autofill::NAME_FULL;
53 if (type == autofill::kCompanyNameField)
54 return autofill::COMPANY_NAME;
55 if (type == autofill::kAddressLineField)
56 return autofill::ADDRESS_HOME_STREET_ADDRESS;
57 if (type == autofill::kDependentLocalityField)
58 return autofill::ADDRESS_HOME_DEPENDENT_LOCALITY;
59 if (type == autofill::kCityField)
60 return autofill::ADDRESS_HOME_CITY;
61 if (type == autofill::kStateField)
62 return autofill::ADDRESS_HOME_STATE;
63 if (type == autofill::kPostalCodeField)
64 return autofill::ADDRESS_HOME_ZIP;
65 if (type == autofill::kSortingCodeField)
66 return autofill::ADDRESS_HOME_SORTING_CODE;
67 if (type == autofill::kCountryField)
68 return autofill::ADDRESS_HOME_COUNTRY;
69 NOTREACHED();
70 return autofill::UNKNOWN_TYPE;
71 }
72
73 } // namespace
74
75 ShippingAddressEditorViewController::ShippingAddressEditorViewController(
76 PaymentRequestSpec* spec,
77 PaymentRequestState* state,
78 PaymentRequestDialogView* dialog)
79 : EditorViewController(spec, state, dialog) {
80 UpdateEditorFields();
81 }
82
83 ShippingAddressEditorViewController::~ShippingAddressEditorViewController() {}
84
85 std::unique_ptr<views::View>
86 ShippingAddressEditorViewController::CreateHeaderView() {
87 return base::MakeUnique<views::View>();
88 }
89
90 int ShippingAddressEditorViewController::GetViewHeaderTitleId() const {
91 return IDS_PAYMENT_REQUEST_ADDRESS_EDITOR_ADD_TITLE;
92 }
93
94 std::vector<EditorField>
95 ShippingAddressEditorViewController::GetFieldDefinitions() {
96 return editor_fields_;
97 }
98
99 bool ShippingAddressEditorViewController::ValidateModelAndSave() {
100 autofill::AutofillProfile profile;
101 profile.set_origin(autofill::kSettingsOrigin);
102 for (const auto& field : text_fields()) {
103 // Force a blur in case the value was left untouched.
104 field.first->OnBlur();
105 // ValidatingTextfield* is the key, EditorField is the value.
106 if (field.first->invalid())
107 return false;
108
109 profile.SetRawInfo(field.second.type, field.first->text());
110 }
111 for (const auto& field : comboboxes()) {
112 // ValidatingCombobox* is the key, EditorField is the value.
113 ValidatingCombobox* combobox = field.first;
114 if (combobox->invalid())
115 return false;
116
117 if (combobox->id() == autofill::ADDRESS_HOME_COUNTRY) {
118 profile.SetRawInfo(
119 field.second.type,
120 base::UTF8ToUTF16(country_codes_[combobox->selected_index()]));
121 } else {
122 profile.SetRawInfo(field.second.type,
123 combobox->GetTextForRow(combobox->selected_index()));
124 }
125 }
126
127 // Add the profile (will not add a duplicate).
128 state()->GetPersonalDataManager()->AddProfile(profile);
129
130 return true;
131 }
132
133 std::unique_ptr<ValidationDelegate>
134 ShippingAddressEditorViewController::CreateValidationDelegate(
135 const EditorField& field) {
136 return base::MakeUnique<
137 ShippingAddressEditorViewController::ShippingAddressValidationDelegate>(
138 this, field);
139 }
140
141 std::unique_ptr<ui::ComboboxModel>
142 ShippingAddressEditorViewController::GetComboboxModelForType(
143 const autofill::ServerFieldType& type) {
144 switch (type) {
145 case autofill::ADDRESS_HOME_COUNTRY: {
146 std::unique_ptr<autofill::CountryComboboxModel> model =
147 base::MakeUnique<autofill::CountryComboboxModel>();
148 model->SetCountries(*state()->GetPersonalDataManager(),
149 base::Callback<bool(const std::string&)>(),
150 state()->GetApplicationLocale());
151 country_codes_.clear();
152 for (size_t i = 0; i < model->countries().size(); ++i) {
153 if (model->countries()[i].get())
154 country_codes_.push_back(model->countries()[i]->country_code());
155 else
156 country_codes_.push_back(""); // Separator.
157 }
158 return std::unique_ptr<ui::ComboboxModel>(model.release());
159 }
160 case autofill::ADDRESS_HOME_STATE: {
161 return std::unique_ptr<
162 ui::ComboboxModel>(new autofill::RegionComboboxModel(
163 base::WrapUnique(new autofill::ChromeMetadataSource(
164 I18N_ADDRESS_VALIDATION_DATA_URL,
165 state()->GetPersonalDataManager()->GetURLRequestContextGetter())),
166 autofill::ValidationRulesStorageFactory::CreateStorage(),
167 state()->GetApplicationLocale(),
168 country_codes_[chosen_country_index_]));
169 }
170 default:
171 NOTREACHED();
172 break;
173 }
174 return std::unique_ptr<ui::ComboboxModel>();
175 }
176
177 void ShippingAddressEditorViewController::OnPerformAction(
178 views::Combobox* sender) {
179 EditorViewController::OnPerformAction(sender);
180 if (sender->id() != autofill::ADDRESS_HOME_COUNTRY)
181 return;
182 DCHECK_GE(sender->selected_index(), 0);
183 if (chosen_country_index_ != static_cast<size_t>(sender->selected_index())) {
184 chosen_country_index_ = sender->selected_index();
185 OnCountryChanged(sender);
186 }
187 }
188
189 void ShippingAddressEditorViewController::UpdateEditorView() {
190 EditorViewController::UpdateEditorView();
191 if (chosen_country_index_ > 0UL) {
192 views::Combobox* country_combo_box = static_cast<views::Combobox*>(
193 dialog()->GetViewByID(autofill::ADDRESS_HOME_COUNTRY));
194 DCHECK(country_combo_box);
195 country_combo_box->SetSelectedIndex(chosen_country_index_);
196 }
197 }
198
199 void ShippingAddressEditorViewController::UpdateEditorFields() {
200 editor_fields_.clear();
201 std::string chosen_country_code;
202 if (chosen_country_index_ < country_codes_.size())
203 chosen_country_code = country_codes_[chosen_country_index_];
204
205 std::unique_ptr<base::ListValue> components(new base::ListValue);
206 std::string unused;
207 autofill::GetAddressComponents(chosen_country_code,
208 state()->GetApplicationLocale(),
209 components.get(), &unused);
210
211 for (size_t line_index = 0; line_index < components->GetSize();
212 ++line_index) {
213 const base::ListValue* line = nullptr;
214 if (!components->GetList(line_index, &line)) {
215 NOTREACHED();
216 return;
217 }
218 DCHECK_NE(nullptr, line);
219 for (size_t component_index = 0; component_index < line->GetSize();
220 ++component_index) {
221 const base::DictionaryValue* component = nullptr;
222 if (!line->GetDictionary(component_index, &component)) {
223 NOTREACHED();
224 return;
225 }
226 std::string field_type;
227 if (!component->GetString(autofill::kFieldTypeKey, &field_type)) {
228 NOTREACHED();
229 return;
230 }
231 std::string field_name;
232 if (!component->GetString(autofill::kFieldNameKey, &field_name)) {
233 NOTREACHED();
234 return;
235 }
236 std::string field_length;
237 if (!component->GetString(autofill::kFieldLengthKey, &field_length)) {
238 NOTREACHED();
239 return;
240 }
241 EditorField::LengthHint length_hint = EditorField::LengthHint::HINT_LONG;
242 if (field_length == autofill::kShortField)
243 length_hint = EditorField::LengthHint::HINT_SHORT;
244 else
245 DCHECK_EQ(autofill::kLongField, field_length);
246 autofill::ServerFieldType server_field_type =
247 GetFieldTypeFromString(field_type);
248 EditorField::ControlType control_type =
249 EditorField::ControlType::TEXTFIELD;
250 if (server_field_type == autofill::ADDRESS_HOME_COUNTRY ||
251 server_field_type == autofill::ADDRESS_HOME_STATE) {
252 control_type = EditorField::ControlType::COMBOBOX;
253 }
254 editor_fields_.emplace_back(
255 server_field_type, base::UTF8ToUTF16(field_name), length_hint,
256 /*required=*/server_field_type != autofill::COMPANY_NAME,
257 control_type);
258 // Insert the Country combobox right after NAME_FULL.
259 if (server_field_type == autofill::NAME_FULL) {
260 editor_fields_.emplace_back(
261 autofill::ADDRESS_HOME_COUNTRY,
262 l10n_util::GetStringUTF16(
263 IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL),
264 EditorField::LengthHint::HINT_LONG, /*required=*/true,
265 EditorField::ControlType::COMBOBOX);
266 }
267 }
268 }
269 // Always add phone number at the end.
270 editor_fields_.emplace_back(
271 autofill::PHONE_HOME_NUMBER,
272 l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE),
273 EditorField::LengthHint::HINT_LONG, /*required=*/false,
274 EditorField::ControlType::TEXTFIELD);
275 }
276
277 void ShippingAddressEditorViewController::OnCountryChanged(
278 views::Combobox* combobox) {
279 // TODO(crbug.com/703764): save the current state so we can map it to the new
280 // country fields as best we can.
281 UpdateEditorFields();
282
283 // The editor can't be updated while in the middle of a combobox event.
284 base::ThreadTaskRunnerHandle::Get()->PostTask(
285 FROM_HERE,
286 base::Bind(&ShippingAddressEditorViewController::UpdateEditorView,
287 base::Unretained(this)));
288 }
289
290 ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
291 ShippingAddressValidationDelegate(
292 ShippingAddressEditorViewController* parent,
293 const EditorField& field)
294 : field_(field) /* TODO(mad): Bring back when needed:, parent_(parent) */ {}
295
296 ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
297 ~ShippingAddressValidationDelegate() {}
298
299 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
300 ValidateTextfield(views::Textfield* textfield) {
301 return ValidateValue(textfield->text());
302 }
303
304 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
305 ValidateCombobox(views::Combobox* combobox) {
306 return ValidateValue(combobox->GetTextForRow(combobox->selected_index()));
307 }
308
309 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
310 ValidateValue(const base::string16& value) {
311 // TODO(crbug.com/703754) add phone validation.
312 // TODO(crbug.com/703756): Display "required" error if applicable.
313 return !field_.required || !value.empty();
314 }
315
316 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698