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

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: CR comments 1 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 autofill::CountryComboboxModel* model =
anthonyvd 2017/03/21 21:18:24 Same comment as above about using unique_ptr and .
MAD 2017/03/22 20:15:42 Done.
147 new 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);
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 if (sender->id() != autofill::ADDRESS_HOME_COUNTRY)
180 return;
181 DCHECK_GE(sender->selected_index(), 0);
182 if (chosen_country_index_ != static_cast<size_t>(sender->selected_index())) {
183 chosen_country_index_ = sender->selected_index();
184 OnCountryChanged(sender);
185 }
186 }
187
188 void ShippingAddressEditorViewController::UpdateEditorView() {
189 EditorViewController::UpdateEditorView();
190 if (chosen_country_index_ > 0UL) {
191 views::Combobox* country_combo_box = static_cast<views::Combobox*>(
192 dialog()->GetViewByID(autofill::ADDRESS_HOME_COUNTRY));
193 DCHECK(country_combo_box);
194 country_combo_box->SetSelectedIndex(chosen_country_index_);
195 }
196 }
197
198 void ShippingAddressEditorViewController::UpdateEditorFields() {
199 editor_fields_.clear();
200 std::string chosen_country_code;
201 if (chosen_country_index_ < country_codes_.size())
202 chosen_country_code = country_codes_[chosen_country_index_];
203
204 std::unique_ptr<base::ListValue> components(new base::ListValue);
205 std::string unused;
206 autofill::GetAddressComponents(chosen_country_code,
207 state()->GetApplicationLocale(),
208 components.get(), &unused);
209
210 for (size_t line_index = 0; line_index < components->GetSize();
211 ++line_index) {
212 const base::ListValue* line = nullptr;
213 if (!components->GetList(line_index, &line)) {
214 NOTREACHED();
215 return;
216 }
217 DCHECK_NE(nullptr, line);
218 for (size_t component_index = 0; component_index < line->GetSize();
219 ++component_index) {
220 const base::DictionaryValue* component = nullptr;
221 if (!line->GetDictionary(component_index, &component)) {
222 NOTREACHED();
223 return;
224 }
225 std::string field_type;
226 if (!component->GetString(autofill::kFieldTypeKey, &field_type)) {
227 NOTREACHED();
228 return;
229 }
230 std::string field_name;
231 if (!component->GetString(autofill::kFieldNameKey, &field_name)) {
232 NOTREACHED();
233 return;
234 }
235 std::string field_length;
236 if (!component->GetString(autofill::kFieldLengthKey, &field_length)) {
237 NOTREACHED();
238 return;
239 }
240 EditorField::LengthHint length_hint = EditorField::LengthHint::HINT_LONG;
241 if (field_length == autofill::kShortField)
242 length_hint = EditorField::LengthHint::HINT_SHORT;
243 else
244 DCHECK_EQ(autofill::kLongField, field_length);
245 autofill::ServerFieldType server_field_type =
246 GetFieldTypeFromString(field_type);
247 EditorField::ControlType control_type =
248 EditorField::ControlType::TEXTFIELD;
249 if (server_field_type == autofill::ADDRESS_HOME_COUNTRY ||
250 server_field_type == autofill::ADDRESS_HOME_STATE) {
251 control_type = EditorField::ControlType::COMBOBOX;
252 }
253 editor_fields_.emplace_back(
254 server_field_type, base::UTF8ToUTF16(field_name), length_hint,
255 /*required=*/server_field_type != autofill::COMPANY_NAME,
256 control_type);
257 // Insert the Country combobox right after NAME_FULL.
258 if (server_field_type == autofill::NAME_FULL) {
259 editor_fields_.emplace_back(
260 autofill::ADDRESS_HOME_COUNTRY,
261 l10n_util::GetStringUTF16(
262 IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL),
263 EditorField::LengthHint::HINT_LONG, /*required=*/true,
264 EditorField::ControlType::COMBOBOX);
265 }
266 }
267 }
268 // Always add phone number at the end.
269 editor_fields_.emplace_back(
270 autofill::PHONE_HOME_NUMBER,
271 l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE),
272 EditorField::LengthHint::HINT_LONG, /*required=*/false,
273 EditorField::ControlType::TEXTFIELD);
274 }
275
276 void ShippingAddressEditorViewController::OnCountryChanged(
277 views::Combobox* combobox) {
278 // TODO(crbug.com/703764): save the current state so we can map it to the new
279 // country fields as best we can.
280
281 // Make sure to unfocus the combobox so we can remove it when we update the
282 // view.
283 combobox->SetFocusBehavior(views::View::FocusBehavior::NEVER);
284 UpdateEditorFields();
285 // Let the focus change complete before updating the editor.
286 base::ThreadTaskRunnerHandle::Get()->PostTask(
287 FROM_HERE,
288 base::Bind(&ShippingAddressEditorViewController::UpdateEditorView,
289 base::Unretained(this)));
290 }
291
292 ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
293 ShippingAddressValidationDelegate(
294 ShippingAddressEditorViewController* parent,
295 const EditorField& field)
296 : field_(field) /* TODO(mad): Bring back when needed:, parent_(parent) */ {}
297
298 ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
299 ~ShippingAddressValidationDelegate() {}
300
301 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
302 ValidateTextfield(views::Textfield* textfield) {
303 return ValidateValue(textfield->text());
304 }
305
306 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
307 ValidateCombobox(views::Combobox* combobox) {
308 return ValidateValue(combobox->GetTextForRow(combobox->selected_index()));
309 }
310
311 bool ShippingAddressEditorViewController::ShippingAddressValidationDelegate::
312 ValidateValue(const base::string16& value) {
313 // TODO(crbug.com/703754) add phone validation.
314 // TODO(crbug.com/703756): Display "required" error if applicable.
315 return !field_.required || !value.empty();
316 }
317
318 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698