0

scanner: Add try again link to action container error view.

It is never shown for now. The actual try again functionality will be
added in a followup.

Bug: b:378582420
Change-Id: I9c78ca07f02d2e28c55e5798776cdb4fb4ae4980
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6210899
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: Elijah Hewer <hewer@chromium.org>
Commit-Queue: Michelle Chen <michellegc@google.com>
Cr-Commit-Position: refs/heads/main@{#1413344}
This commit is contained in:
Michelle Chen
2025-01-30 00:03:49 -08:00
committed by Chromium LUCI CQ
parent 128a7e96f1
commit 7a8f2aa750
5 changed files with 86 additions and 6 deletions

@ -6877,6 +6877,9 @@ Here are some things you can try to get started.
<message name="IDS_ASH_SCANNER_ACTION_FAILURE_TOAST_COPY_TEXT_AND_FORMAT" desc="The message shown on a toast to indicate an error occurred when trying to copy text with formatting from the contents of a screenshot.">
Couldnt copy with formatting
</message>
<message name="IDS_ASH_SCANNER_ERROR_TRY_AGAIN_LINK_TEXT" desc="The text on a try again link shown next to an error message indicating that something went wrong. The link can be pressed to try the action again.">
Try again
</message>
<!-- Snap Group -->
<message name="IDS_ASH_SNAP_GROUP_CLICK_TO_LOCK_WINDOWS" desc="Click to lock the windows.">

@ -0,0 +1 @@
0ea17fcbfdc379da42c64544320115bd4c6ce3dd

@ -13,12 +13,15 @@
#include "ash/capture_mode/action_button_view.h"
#include "ash/capture_mode/capture_mode_types.h"
#include "ash/capture_mode/capture_mode_util.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/system_shadow.h"
#include "ash/style/typography.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/time/time.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/models/image_model.h"
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
@ -35,6 +38,7 @@
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/link.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/vector_icons.h"
@ -60,6 +64,9 @@ constexpr int kErrorViewLeadingIconSize = 20;
// from the error message label.
constexpr auto kErrorViewLeadingIconRightPadding = 4;
// Padding around the try again link in the error view.
constexpr auto kErrorViewTryAgainLinkPadding = gfx::Insets::TLBR(0, 8, 0, 4);
// The horizontal distance between action buttons in a row.
constexpr int kActionButtonSpacing = 10;
@ -113,6 +120,21 @@ ActionButtonContainerView::ErrorView::ErrorView()
.SetFontList(TypographyProvider::Get()->ResolveTypographyToken(
TypographyToken::kCrosAnnotation1))
.Build());
// TODO(crbug.com/388451361): Implement keyboard navigation for the try again
// link.
AddChildView(
views::Builder<views::Link>()
.CopyAddressTo(&try_again_link_)
.SetText(l10n_util::GetStringUTF16(
IDS_ASH_SCANNER_ERROR_TRY_AGAIN_LINK_TEXT))
.SetFontList(TypographyProvider::Get()->ResolveTypographyToken(
TypographyToken::kCrosButton2))
.SetEnabledColorId(cros_tokens::kCrosSysPrimary)
.SetForceUnderline(false)
.SetProperty(views::kMarginsKey, kErrorViewTryAgainLinkPadding)
.SetVisible(false)
.Build());
}
ActionButtonContainerView::ErrorView::~ErrorView() = default;
@ -143,6 +165,12 @@ void ActionButtonContainerView::ErrorView::SetErrorMessage(
error_label_->SetText(error_message);
}
void ActionButtonContainerView::ErrorView::SetTryAgainCallback(
base::RepeatingClosure try_again_callback) {
try_again_link_->SetVisible(!try_again_callback.is_null());
try_again_link_->SetCallback(std::move(try_again_callback));
}
const std::u16string&
ActionButtonContainerView::ErrorView::GetErrorMessageForTesting() const {
return error_label_->GetText();
@ -223,8 +251,10 @@ const views::View::Views& ActionButtonContainerView::GetActionButtons() const {
}
void ActionButtonContainerView::ShowErrorView(
const std::u16string& error_message) {
const std::u16string& error_message,
base::RepeatingClosure try_again_callback) {
error_view_->SetErrorMessage(error_message);
error_view_->SetTryAgainCallback(std::move(try_again_callback));
error_view_->SetVisible(true);
}

@ -10,6 +10,8 @@
#include "ash/ash_export.h"
#include "ash/capture_mode/capture_mode_types.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
@ -23,6 +25,7 @@ struct VectorIcon;
namespace views {
class Label;
class Link;
}
namespace ash {
@ -36,7 +39,8 @@ class ASH_EXPORT ActionButtonContainerView : public views::View {
METADATA_HEADER(ActionButtonContainerView, views::View)
public:
// A view that displays an error message and icon.
// A view that displays an error message and icon. It may optionally also show
// a try again link.
class ASH_EXPORT ErrorView : public views::BoxLayoutView {
METADATA_HEADER(ErrorView, views::BoxLayoutView)
@ -53,12 +57,20 @@ class ASH_EXPORT ActionButtonContainerView : public views::View {
// Sets the error message to show on the error view.
void SetErrorMessage(const std::u16string& error_message);
// Sets the callback to run when the try again link is pressed. Note that
// the try again link is only shown if `try_again_callback` is not null.
void SetTryAgainCallback(base::RepeatingClosure try_again_callback);
views::Link* try_again_link_for_testing() { return try_again_link_; }
const std::u16string& GetErrorMessageForTesting() const;
private:
std::unique_ptr<SystemShadow> shadow_;
raw_ptr<views::Label> error_label_ = nullptr;
raw_ptr<views::Link> try_again_link_ = nullptr;
};
ActionButtonContainerView();
@ -83,8 +95,12 @@ class ASH_EXPORT ActionButtonContainerView : public views::View {
// Returns the action buttons in this container.
const views::View::Views& GetActionButtons() const;
// Shows an error view with the given `error_message`.
void ShowErrorView(const std::u16string& error_message);
// Shows an error view with the given `error_message`. If `try_again_callback`
// is not null, then the error view will also show a try again link that runs
// `try_again_callback` when pressed.
void ShowErrorView(
const std::u16string& error_message,
base::RepeatingClosure try_again_callback = base::NullCallback());
// Hides the error view.
void HideErrorView();
@ -95,7 +111,7 @@ class ASH_EXPORT ActionButtonContainerView : public views::View {
// copy text and search buttons.
void StartSmartActionsButtonTransition();
const ErrorView* error_view_for_testing() const { return error_view_; }
ErrorView* error_view_for_testing() { return error_view_; }
private:
// Called when the smart actions button has faded out, to start the transition

@ -19,6 +19,7 @@
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/link.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_utils.h"
@ -126,7 +127,7 @@ TEST_F(ActionButtonContainerViewTest, SmartActionsButtonTransition) {
TEST_F(ActionButtonContainerViewTest, ShowsErrorView) {
ActionButtonContainerView action_button_container;
const ActionButtonContainerView::ErrorView* error_view =
ActionButtonContainerView::ErrorView* error_view =
action_button_container.error_view_for_testing();
EXPECT_FALSE(error_view->GetVisible());
@ -135,11 +136,40 @@ TEST_F(ActionButtonContainerViewTest, ShowsErrorView) {
EXPECT_TRUE(error_view->GetVisible());
EXPECT_EQ(error_view->GetErrorMessageForTesting(), u"Error message");
EXPECT_FALSE(error_view->try_again_link_for_testing()->GetVisible());
action_button_container.HideErrorView();
EXPECT_FALSE(error_view->GetVisible());
}
TEST_F(ActionButtonContainerViewTest, ShowsErrorViewWithTryAgainLink) {
std::unique_ptr<views::Widget> widget =
CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET);
widget->SetBounds(gfx::Rect(50, 50, 300, 200));
widget->Show();
auto* action_button_container =
widget->SetContentsView(std::make_unique<ActionButtonContainerView>());
base::test::TestFuture<void> try_again_future;
action_button_container->ShowErrorView(
u"Error message", try_again_future.GetRepeatingCallback());
ActionButtonContainerView::ErrorView* error_view =
action_button_container->error_view_for_testing();
EXPECT_TRUE(error_view->GetVisible());
views::Link* try_again_link = error_view->try_again_link_for_testing();
EXPECT_TRUE(try_again_link->GetVisible());
// Check that clicking the try again link runs the try again callback.
ViewDrawnWaiter().Wait(try_again_link);
ui::test::EventGenerator event_generator(GetRootWindow(widget.get()));
event_generator.MoveMouseTo(
try_again_link->GetBoundsInScreen().CenterPoint());
event_generator.ClickLeftButton();
EXPECT_TRUE(try_again_future.Wait());
}
} // namespace
} // namespace ash