Commit d9675d8b authored by Mathieu Perreault's avatar Mathieu Perreault Committed by Commit Bot

[Autofill] Reuse overlay for permanent errors in Card unmask dialog

Reuse the progress overlay (Throbber with "Confirming card...") to
display a permanent error. The Throbber is changed into an error icon,
and the error is shown in red.

Test is changed to use a long string, for easier UI regression testing.

Bug: 850571
Test: ./out/Default/browser_tests --gtest_filter=BrowserUiTest.Invoke --ui=CardUnmaskPromptViewBrowserTest.InvokeUi_valid_PermanentError  --test-launcher-interactive
Change-Id: I4d92ce0a8535e92f8707edf6f4444c53e80eea3e
Reviewed-on: https://chromium-review.googlesource.com/1100336
Commit-Queue: Mathieu Perreault <mathp@chromium.org>
Reviewed-by: default avatarEvan Stade <estade@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567440}
parent 690c84bd
...@@ -90,7 +90,9 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl { ...@@ -90,7 +90,9 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
if (expected_failure_temporary_) { if (expected_failure_temporary_) {
verification_message = base::ASCIIToUTF16("This is a temporary error."); verification_message = base::ASCIIToUTF16("This is a temporary error.");
} else if (expected_failure_permanent_) { } else if (expected_failure_permanent_) {
verification_message = base::ASCIIToUTF16("This is a permanent error."); verification_message = base::ASCIIToUTF16(
"Chrome was unable to confirm your card at this time. Please try "
"again later.");
} }
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, FROM_HERE,
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "ui/views/controls/throbber.h" #include "ui/views/controls/throbber.h"
#include "ui/views/layout/box_layout.h" #include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/style/typography.h" #include "ui/views/style/typography.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
...@@ -72,7 +73,7 @@ void CardUnmaskPromptViews::ControllerGone() { ...@@ -72,7 +73,7 @@ void CardUnmaskPromptViews::ControllerGone() {
void CardUnmaskPromptViews::DisableAndWaitForVerification() { void CardUnmaskPromptViews::DisableAndWaitForVerification() {
SetInputsEnabled(false); SetInputsEnabled(false);
controls_container_->SetVisible(false); controls_container_->SetVisible(false);
progress_overlay_->SetVisible(true); overlay_->SetVisible(true);
progress_throbber_->Start(); progress_throbber_->Start();
DialogModelChanged(); DialogModelChanged();
Layout(); Layout();
...@@ -83,7 +84,7 @@ void CardUnmaskPromptViews::GotVerificationResult( ...@@ -83,7 +84,7 @@ void CardUnmaskPromptViews::GotVerificationResult(
bool allow_retry) { bool allow_retry) {
progress_throbber_->Stop(); progress_throbber_->Stop();
if (error_message.empty()) { if (error_message.empty()) {
progress_label_->SetText(l10n_util::GetStringUTF16( overlay_label_->SetText(l10n_util::GetStringUTF16(
IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_SUCCESS)); IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_SUCCESS));
progress_throbber_->SetChecked(true); progress_throbber_->SetChecked(true);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
...@@ -92,10 +93,9 @@ void CardUnmaskPromptViews::GotVerificationResult( ...@@ -92,10 +93,9 @@ void CardUnmaskPromptViews::GotVerificationResult(
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
controller_->GetSuccessMessageDuration()); controller_->GetSuccessMessageDuration());
} else { } else {
progress_overlay_->SetVisible(false);
controls_container_->SetVisible(true);
if (allow_retry) { if (allow_retry) {
controls_container_->SetVisible(true);
overlay_->SetVisible(false);
SetInputsEnabled(true); SetInputsEnabled(true);
if (!controller_->ShouldRequestExpirationDate()) { if (!controller_->ShouldRequestExpirationDate()) {
...@@ -111,9 +111,28 @@ void CardUnmaskPromptViews::GotVerificationResult( ...@@ -111,9 +111,28 @@ void CardUnmaskPromptViews::GotVerificationResult(
// TODO(estade): When do we hide |error_label_|? // TODO(estade): When do we hide |error_label_|?
SetRetriableErrorMessage(error_message); SetRetriableErrorMessage(error_message);
} else { } else {
permanent_error_label_->SetText(error_message);
permanent_error_label_->SetVisible(true);
SetRetriableErrorMessage(base::string16()); SetRetriableErrorMessage(base::string16());
// Rows cannot be replaced in GridLayout, so we reset it.
overlay_->RemoveAllChildViews(/*delete_children=*/true);
views::GridLayout* layout = ResetOverlayLayout();
// The label of the overlay will now show the error in red.
views::Label* error_label = new views::Label(error_message);
const SkColor warning_text_color = views::style::GetColor(
*error_label, ChromeTextContext::CONTEXT_BODY_TEXT_SMALL, STYLE_RED);
error_label->SetEnabledColor(warning_text_color);
error_label->SetMultiLine(true);
// Replace the throbber with a warning icon. Since this is a permanent
// error we do not intend to return to a previous state.
views::ImageView* error_icon = new views::ImageView();
error_icon->SetImage(
gfx::CreateVectorIcon(kBrowserToolsErrorIcon, warning_text_color));
layout->StartRow(1, 0);
layout->AddView(error_icon);
layout->AddView(error_label);
} }
DialogModelChanged(); DialogModelChanged();
} }
...@@ -218,10 +237,9 @@ gfx::Size CardUnmaskPromptViews::CalculatePreferredSize() const { ...@@ -218,10 +237,9 @@ gfx::Size CardUnmaskPromptViews::CalculatePreferredSize() const {
void CardUnmaskPromptViews::OnNativeThemeChanged(const ui::NativeTheme* theme) { void CardUnmaskPromptViews::OnNativeThemeChanged(const ui::NativeTheme* theme) {
SkColor bg_color = SkColor bg_color =
theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground); theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground);
progress_overlay_->SetBackground(views::CreateSolidBackground(bg_color)); overlay_->SetBackground(views::CreateSolidBackground(bg_color));
progress_label_->SetBackgroundColor(bg_color); if (overlay_label_)
progress_label_->SetEnabledColor(theme->GetSystemColor( overlay_label_->SetBackgroundColor(bg_color);
ui::NativeTheme::kColorId_ThrobberSpinningColor));
} }
ui::ModalType CardUnmaskPromptViews::GetModalType() const { ui::ModalType CardUnmaskPromptViews::GetModalType() const {
...@@ -320,44 +338,19 @@ void CardUnmaskPromptViews::InitIfNecessary() { ...@@ -320,44 +338,19 @@ void CardUnmaskPromptViews::InitIfNecessary() {
ChromeLayoutProvider* provider = ChromeLayoutProvider::Get(); ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
// The main content view is a box layout with two things in it: the permanent // The layout is a FillLayout that will contain the progress or error overlay
// error label layout, and |main_contents|. // on top of the actual contents in |controls_container| (instructions, input
SetLayoutManager(std::make_unique<views::BoxLayout>( // fields).
views::BoxLayout::kVertical, gfx::Insets())); SetLayoutManager(std::make_unique<views::FillLayout>());
// This is a big red-background section at the top of the dialog in case there
// is a permanent error. It is not in an inset layout because the red
// background needs the full width.
permanent_error_label_ = new views::Label();
permanent_error_label_->SetFontList(
rb.GetFontList(ui::ResourceBundle::BoldFont));
permanent_error_label_->SetBorder(views::CreateEmptyBorder(
provider->GetInsetsMetric(views::INSETS_DIALOG_SUBSECTION)));
permanent_error_label_->SetBackground(views::CreateSolidBackground(
permanent_error_label_->GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_AlertSeverityHigh)));
permanent_error_label_->SetEnabledColor(SK_ColorWHITE);
permanent_error_label_->SetAutoColorReadabilityEnabled(false);
permanent_error_label_->SetVisible(false);
permanent_error_label_->SetMultiLine(true);
permanent_error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(permanent_error_label_);
// The |main_contents| layout is a FillLayout that will contain the progress
// overlay on top of the actual contents in |controls_container|
// (instructions, input fields).
views::View* main_contents = new views::View();
main_contents->SetLayoutManager(std::make_unique<views::FillLayout>());
// Inset the whole main section. // Inset the whole main section.
main_contents->SetBorder(views::CreateEmptyBorder( SetBorder(views::CreateEmptyBorder(
provider->GetDialogInsetsForContentType(views::TEXT, views::CONTROL))); provider->GetDialogInsetsForContentType(views::TEXT, views::CONTROL)));
AddChildView(main_contents);
controls_container_ = new views::View(); controls_container_ = new views::View();
controls_container_->SetLayoutManager(std::make_unique<views::BoxLayout>( controls_container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical, gfx::Insets(), views::BoxLayout::kVertical, gfx::Insets(),
provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL))); provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
main_contents->AddChildView(controls_container_); AddChildView(controls_container_);
// Instruction text of the dialog. // Instruction text of the dialog.
instructions_ = new views::Label(controller_->GetInstructionsMessage()); instructions_ = new views::Label(controller_->GetInstructionsMessage());
...@@ -418,42 +411,40 @@ void CardUnmaskPromptViews::InitIfNecessary() { ...@@ -418,42 +411,40 @@ void CardUnmaskPromptViews::InitIfNecessary() {
temporary_error_layout->set_cross_axis_alignment( temporary_error_layout->set_cross_axis_alignment(
views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
const SkColor kWarningTextColor = views::style::GetColor( const SkColor warning_text_color = views::style::GetColor(
*instructions_, ChromeTextContext::CONTEXT_BODY_TEXT_SMALL, STYLE_RED); *instructions_, ChromeTextContext::CONTEXT_BODY_TEXT_SMALL, STYLE_RED);
views::ImageView* error_icon = new views::ImageView(); views::ImageView* error_icon = new views::ImageView();
error_icon->SetImage( error_icon->SetImage(
gfx::CreateVectorIcon(kBrowserToolsErrorIcon, kWarningTextColor)); gfx::CreateVectorIcon(kBrowserToolsErrorIcon, warning_text_color));
temporary_error_->SetVisible(false); temporary_error_->SetVisible(false);
temporary_error_->AddChildView(error_icon); temporary_error_->AddChildView(error_icon);
error_label_ = new views::Label(); error_label_ = new views::Label();
error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
error_label_->SetEnabledColor(kWarningTextColor); error_label_->SetEnabledColor(warning_text_color);
temporary_error_->AddChildView(error_label_); temporary_error_->AddChildView(error_label_);
temporary_error_layout->SetFlexForView(error_label_, 1); temporary_error_layout->SetFlexForView(error_label_, 1);
input_container->AddChildView(temporary_error_); input_container->AddChildView(temporary_error_);
controls_container_->AddChildView(input_container); controls_container_->AddChildView(input_container);
// On top of the main contents, we add the progress overlay and hide it. // On top of the main contents, we add the progress/error overlay and hide it.
progress_overlay_ = new views::View(); // A child view will be added to it when about to be shown.
auto progress_layout = std::make_unique<views::BoxLayout>( overlay_ = new views::View();
views::BoxLayout::kHorizontal, gfx::Insets(), views::GridLayout* overlay_layout = ResetOverlayLayout();
provider->GetDistanceMetric(views::DISTANCE_RELATED_LABEL_HORIZONTAL)); overlay_->SetVisible(false);
progress_layout->set_cross_axis_alignment(
views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
progress_layout->set_main_axis_alignment(
views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
progress_overlay_->SetLayoutManager(std::move(progress_layout));
progress_overlay_->SetVisible(false);
progress_throbber_ = new views::Throbber(); progress_throbber_ = new views::Throbber();
progress_overlay_->AddChildView(progress_throbber_); overlay_layout->AddView(progress_throbber_);
progress_label_ = new views::Label(l10n_util::GetStringUTF16( overlay_label_ = new views::Label(l10n_util::GetStringUTF16(
IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_IN_PROGRESS)); IDS_AUTOFILL_CARD_UNMASK_VERIFICATION_IN_PROGRESS));
progress_overlay_->AddChildView(progress_label_); overlay_label_->SetEnabledColor(
main_contents->AddChildView(progress_overlay_); overlay_label_->GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_ThrobberSpinningColor));
overlay_layout->AddView(overlay_label_);
AddChildView(overlay_);
} }
bool CardUnmaskPromptViews::ExpirationDateIsValid() const { bool CardUnmaskPromptViews::ExpirationDateIsValid() const {
...@@ -469,6 +460,21 @@ void CardUnmaskPromptViews::ClosePrompt() { ...@@ -469,6 +460,21 @@ void CardUnmaskPromptViews::ClosePrompt() {
GetWidget()->Close(); GetWidget()->Close();
} }
views::GridLayout* CardUnmaskPromptViews::ResetOverlayLayout() {
views::GridLayout* overlay_layout =
overlay_->SetLayoutManager(std::make_unique<views::GridLayout>(overlay_));
views::ColumnSet* columns = overlay_layout->AddColumnSet(0);
// The throbber's checkmark is 18dp.
columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
0.5, views::GridLayout::FIXED, 18, 0);
columns->AddPaddingColumn(0, ChromeLayoutProvider::Get()->GetDistanceMetric(
views::DISTANCE_RELATED_LABEL_HORIZONTAL));
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0.5,
views::GridLayout::USE_PREF, 0, 0);
overlay_layout->StartRow(1, 0);
return overlay_layout;
}
CardUnmaskPromptView* CreateCardUnmaskPromptView( CardUnmaskPromptView* CreateCardUnmaskPromptView(
CardUnmaskPromptController* controller, CardUnmaskPromptController* controller,
content::WebContents* web_contents) { content::WebContents* web_contents) {
......
...@@ -21,6 +21,7 @@ class WebContents; ...@@ -21,6 +21,7 @@ class WebContents;
namespace views { namespace views {
class Checkbox; class Checkbox;
class GridLayout;
class Label; class Label;
class Link; class Link;
class Textfield; class Textfield;
...@@ -84,6 +85,7 @@ class CardUnmaskPromptViews : public CardUnmaskPromptView, ...@@ -84,6 +85,7 @@ class CardUnmaskPromptViews : public CardUnmaskPromptView,
void SetInputsEnabled(bool enabled); void SetInputsEnabled(bool enabled);
void ShowNewCardLink(); void ShowNewCardLink();
void ClosePrompt(); void ClosePrompt();
views::GridLayout* ResetOverlayLayout();
CardUnmaskPromptController* controller_; CardUnmaskPromptController* controller_;
content::WebContents* web_contents_; content::WebContents* web_contents_;
...@@ -106,17 +108,15 @@ class CardUnmaskPromptViews : public CardUnmaskPromptView, ...@@ -106,17 +108,15 @@ class CardUnmaskPromptViews : public CardUnmaskPromptView,
// inputs. // inputs.
views::View* temporary_error_ = nullptr; views::View* temporary_error_ = nullptr;
views::Label* error_label_ = nullptr; views::Label* error_label_ = nullptr;
// The error label for permanent errors (where the user can't retry).
views::Label* permanent_error_label_ = nullptr;
views::View* controls_container_ = nullptr; views::View* controls_container_ = nullptr;
views::View* storage_row_ = nullptr; views::View* storage_row_ = nullptr;
views::Checkbox* storage_checkbox_ = nullptr; views::Checkbox* storage_checkbox_ = nullptr;
// Elements related to progress when the request is being made. // Elements related to progress or error when the request is being made.
views::View* progress_overlay_ = nullptr; views::View* overlay_ = nullptr;
views::Label* overlay_label_ = nullptr;
views::Throbber* progress_throbber_ = nullptr; views::Throbber* progress_throbber_ = nullptr;
views::Label* progress_label_ = nullptr;
base::WeakPtrFactory<CardUnmaskPromptViews> weak_ptr_factory_; base::WeakPtrFactory<CardUnmaskPromptViews> weak_ptr_factory_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment