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

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

Issue 2715533002: [Payments] Add error messages to credit card editor. (Closed)
Patch Set: tests Created 3 years, 10 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/editor_view_controller.h" 5 #include "chrome/browser/ui/views/payments/editor_view_controller.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 54
55 std::unique_ptr<views::View> EditorViewController::CreateView() { 55 std::unique_ptr<views::View> EditorViewController::CreateView() {
56 std::unique_ptr<views::View> content_view = base::MakeUnique<views::View>(); 56 std::unique_ptr<views::View> content_view = base::MakeUnique<views::View>();
57 57
58 views::BoxLayout* layout = 58 views::BoxLayout* layout =
59 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); 59 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
60 layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START); 60 layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
61 layout->set_cross_axis_alignment( 61 layout->set_cross_axis_alignment(
62 views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH); 62 views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
63 content_view->SetLayoutManager(layout); 63 content_view->SetLayoutManager(layout);
64 // No insets. Child views below are responsible for their padding.
64 65
66 // An editor can optionally have a header view specific to it.
65 content_view->AddChildView(CreateHeaderView().release()); 67 content_view->AddChildView(CreateHeaderView().release());
66 68
67 // Create an input label/textfield for each field definition. 69 // The heart of the editor dialog: all the input fields with their labels.
68 std::vector<EditorField> fields = GetFieldDefinitions(); 70 content_view->AddChildView(CreateEditorView().release());
69 for (const auto& field : fields) {
70 content_view->AddChildView(CreateInputField(field).release());
71 }
72 71
73 return CreatePaymentView( 72 return CreatePaymentView(
74 CreateSheetHeaderView( 73 CreateSheetHeaderView(
75 true, l10n_util::GetStringUTF16( 74 true, l10n_util::GetStringUTF16(
76 IDS_PAYMENT_REQUEST_CREDIT_CARD_EDITOR_ADD_TITLE), 75 IDS_PAYMENT_REQUEST_CREDIT_CARD_EDITOR_ADD_TITLE),
77 this), 76 this),
78 std::move(content_view)); 77 std::move(content_view));
79 } 78 }
80 79
81 // Adds the "required fields" label in disabled text, to obtain this result. 80 // Adds the "required fields" label in disabled text, to obtain this result.
(...skipping 13 matching lines...) Expand all
95 // Adds the "* indicates a required field" label in "disabled" grey text. 94 // Adds the "* indicates a required field" label in "disabled" grey text.
96 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>( 95 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(
97 l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE)); 96 l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE));
98 label->SetDisabledColor(label->GetNativeTheme()->GetSystemColor( 97 label->SetDisabledColor(label->GetNativeTheme()->GetSystemColor(
99 ui::NativeTheme::kColorId_LabelDisabledColor)); 98 ui::NativeTheme::kColorId_LabelDisabledColor));
100 label->SetEnabled(false); 99 label->SetEnabled(false);
101 content_view->AddChildView(label.release()); 100 content_view->AddChildView(label.release());
102 return content_view; 101 return content_view;
103 } 102 }
104 103
104 void EditorViewController::DisplayErrorMessageForField(
105 const EditorField& field,
106 const base::string16& error_message) {
107 const auto& label_it = error_labels_.find(field);
108 DCHECK(label_it != error_labels_.end());
109 label_it->second->SetText(error_message);
110 label_it->second->SchedulePaint();
111 dialog()->Layout();
112 }
113
105 std::unique_ptr<views::Button> EditorViewController::CreatePrimaryButton() { 114 std::unique_ptr<views::Button> EditorViewController::CreatePrimaryButton() {
106 std::unique_ptr<views::Button> button( 115 std::unique_ptr<views::Button> button(
107 views::MdTextButton::CreateSecondaryUiBlueButton( 116 views::MdTextButton::CreateSecondaryUiBlueButton(
108 this, l10n_util::GetStringUTF16(IDS_DONE))); 117 this, l10n_util::GetStringUTF16(IDS_DONE)));
109 button->set_tag(static_cast<int>(EditorViewControllerTags::SAVE_BUTTON)); 118 button->set_tag(static_cast<int>(EditorViewControllerTags::SAVE_BUTTON));
110 button->set_id(static_cast<int>(DialogViewID::EDITOR_SAVE_BUTTON)); 119 button->set_id(static_cast<int>(DialogViewID::EDITOR_SAVE_BUTTON));
111 return button; 120 return button;
112 } 121 }
113 122
114 void EditorViewController::ButtonPressed(views::Button* sender, 123 void EditorViewController::ButtonPressed(views::Button* sender,
(...skipping 11 matching lines...) Expand all
126 135
127 void EditorViewController::ContentsChanged(views::Textfield* sender, 136 void EditorViewController::ContentsChanged(views::Textfield* sender,
128 const base::string16& new_contents) { 137 const base::string16& new_contents) {
129 static_cast<ValidatingTextfield*>(sender)->OnContentsChanged(); 138 static_cast<ValidatingTextfield*>(sender)->OnContentsChanged();
130 } 139 }
131 140
132 void EditorViewController::OnPerformAction(views::Combobox* sender) { 141 void EditorViewController::OnPerformAction(views::Combobox* sender) {
133 static_cast<ValidatingCombobox*>(sender)->OnContentsChanged(); 142 static_cast<ValidatingCombobox*>(sender)->OnContentsChanged();
134 } 143 }
135 144
136 std::unique_ptr<views::View> EditorViewController::CreateInputField( 145 std::unique_ptr<views::View> EditorViewController::CreateEditorView() {
137 const EditorField& field) { 146 std::unique_ptr<views::View> editor_view = base::MakeUnique<views::View>();
138 std::unique_ptr<views::View> row = base::MakeUnique<views::View>();
139 147
140 row->SetBorder(payments::CreatePaymentRequestRowBorder()); 148 views::GridLayout* editor_layout = new views::GridLayout(editor_view.get());
141 149
142 views::GridLayout* layout = new views::GridLayout(row.get()); 150 // The editor grid layout is padded vertically from the top and bottom, and
151 // horizontally inset like other content views. The top padding needs to be
152 // added to the top padding of the first row.
153 constexpr int kEditorVerticalInset = 16;
154 editor_layout->SetInsets(
155 kEditorVerticalInset, payments::kPaymentRequestRowHorizontalInsets,
156 kEditorVerticalInset, payments::kPaymentRequestRowHorizontalInsets);
143 157
144 // The vertical spacing for these rows is slightly different than the spacing 158 editor_view->SetLayoutManager(editor_layout);
145 // spacing for clickable rows, so don't use kPaymentRequestRowVerticalInsets. 159 views::ColumnSet* columns = editor_layout->AddColumnSet(0);
146 constexpr int kRowVerticalInset = 12;
147 layout->SetInsets(
148 kRowVerticalInset, payments::kPaymentRequestRowHorizontalInsets,
149 kRowVerticalInset, payments::kPaymentRequestRowHorizontalInsets);
150
151 row->SetLayoutManager(layout);
152 views::ColumnSet* columns = layout->AddColumnSet(0);
153 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0, 160 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0,
154 views::GridLayout::USE_PREF, 0, 0); 161 views::GridLayout::USE_PREF, 0, 0);
155 columns->AddPaddingColumn(1, 0); 162
156 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 0, 163 // This is the horizontal padding between the label and the input field.
164 constexpr int kLabelInputFieldHorizontalPadding = 16;
165 columns->AddPaddingColumn(0, kLabelInputFieldHorizontalPadding);
166
167 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0,
157 views::GridLayout::USE_PREF, 0, 0); 168 views::GridLayout::USE_PREF, 0, 0);
158 169
159 layout->StartRow(0, 0); 170 std::vector<EditorField> fields = GetFieldDefinitions();
160 layout->AddView(new views::Label(field.label)); 171 for (const auto& field : fields) {
172 CreateInputField(editor_layout, field);
173 }
174
175 return editor_view;
176 }
177
178 // Each input field is a 4-quadrant grid.
179 // +----------------------------------------------------------+
180 // | Field Label | Input field (textfield/combobox) |
181 // |_______________________|__________________________________|
182 // | (empty) | Error label |
183 // +----------------------------------------------------------+
184 void EditorViewController::CreateInputField(views::GridLayout* layout,
185 const EditorField& field) {
186 // This is the top padding for every row.
187 constexpr int kInputRowSpacing = 6;
188 layout->StartRowWithPadding(0, 0, 0, kInputRowSpacing);
189
190 std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(
191 field.required ? field.label + base::ASCIIToUTF16("*") : field.label);
192 // A very long label will wrap.
193 label->SetMultiLine(true);
anthonyvd 2017/02/22 19:32:45 I don't see where the max width of the label is se
Mathieu 2017/02/22 20:08:59 Correct! I've set a max width now.
194 layout->AddView(label.release());
161 195
162 if (field.control_type == EditorField::ControlType::TEXTFIELD) { 196 if (field.control_type == EditorField::ControlType::TEXTFIELD) {
163 ValidatingTextfield* text_field = 197 ValidatingTextfield* text_field =
164 new ValidatingTextfield(CreateValidationDelegate(field)); 198 new ValidatingTextfield(CreateValidationDelegate(field, this));
165 text_field->set_controller(this); 199 text_field->set_controller(this);
166 // Using autofill field type as a view ID (for testing). 200 // Using autofill field type as a view ID (for testing).
167 text_field->set_id(static_cast<int>(field.type)); 201 text_field->set_id(static_cast<int>(field.type));
168 text_field->set_default_width_in_chars( 202 text_field->set_default_width_in_chars(
169 field.length_hint == EditorField::LengthHint::HINT_SHORT 203 field.length_hint == EditorField::LengthHint::HINT_SHORT
170 ? kNumCharactersInShortField 204 ? kNumCharactersInShortField
171 : kNumCharactersInLongField); 205 : kNumCharactersInLongField);
172 206
173 text_fields_.insert(std::make_pair(text_field, field)); 207 text_fields_.insert(std::make_pair(text_field, field));
174 // |text_field| will now be owned by |row|. 208 // |text_field| will now be owned by |row|.
175 layout->AddView(text_field); 209 layout->AddView(text_field);
176 } else if (field.control_type == EditorField::ControlType::COMBOBOX) { 210 } else if (field.control_type == EditorField::ControlType::COMBOBOX) {
177 ValidatingCombobox* combobox = new ValidatingCombobox( 211 ValidatingCombobox* combobox =
178 GetComboboxModelForType(field.type), CreateValidationDelegate(field)); 212 new ValidatingCombobox(GetComboboxModelForType(field.type),
213 CreateValidationDelegate(field, this));
179 // Using autofill field type as a view ID (for testing). 214 // Using autofill field type as a view ID (for testing).
180 combobox->set_id(static_cast<int>(field.type)); 215 combobox->set_id(static_cast<int>(field.type));
181 combobox->set_listener(this); 216 combobox->set_listener(this);
182 comboboxes_.insert(std::make_pair(combobox, field)); 217 comboboxes_.insert(std::make_pair(combobox, field));
183 // |combobox| will now be owned by |row|. 218 // |combobox| will now be owned by |row|.
184 layout->AddView(combobox); 219 layout->AddView(combobox);
185 } else { 220 } else {
186 NOTREACHED(); 221 NOTREACHED();
187 } 222 }
188 223
189 return row; 224 // This is the vertical space between the input field and its error label.
225 constexpr int kInputErrorLabelPadding = 6;
226 layout->StartRowWithPadding(0, 0, 0, kInputErrorLabelPadding);
227 layout->SkipColumns(1);
228 // Error label is initially empty.
229 std::unique_ptr<views::Label> error_label =
230 base::MakeUnique<views::Label>(base::ASCIIToUTF16(""));
231 error_label->set_id(static_cast<int>(DialogViewID::ERROR_LABEL_OFFSET) +
232 field.type);
anthonyvd 2017/02/22 19:32:45 Are all fields guaranteed to have a different type
Mathieu 2017/02/22 20:08:59 Yes they all have different type, it's the autofil
233 error_label->SetFontList(
234 error_label->GetDefaultFontList().DeriveWithSizeDelta(-1));
235 error_label->SetEnabledColor(error_label->GetNativeTheme()->GetSystemColor(
236 ui::NativeTheme::kColorId_AlertSeverityHigh));
237 error_labels_[field] = error_label.get();
238
239 layout->AddView(error_label.release());
190 } 240 }
191 241
192 } // namespace payments 242 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698