scanner: Add ErrorView to show in the action button container.
Add an ErrorView to be shown in the action button container if actions are not available. Followups will handle the logic for showing and hiding the ErrorView. Bug: b:378582420 Change-Id: I87471fa9465ee3f53dcab39ad96a91950e6552ce Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6189039 Reviewed-by: Elijah Hewer <hewer@chromium.org> Commit-Queue: Michelle Chen <michellegc@google.com> Reviewed-by: Ahmed Fakhry <afakhry@chromium.org> Cr-Commit-Position: refs/heads/main@{#1410114}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
5062c2c7d5
commit
4de3867103
@@ -11,24 +11,35 @@
|
||||
|
||||
#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/style/system_shadow.h"
|
||||
#include "ash/style/typography.h"
|
||||
#include "base/check.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/ranges/algorithm.h"
|
||||
#include "base/time/time.h"
|
||||
#include "ui/aura/window.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"
|
||||
#include "ui/compositor/layer.h"
|
||||
#include "ui/compositor/layer_animator.h"
|
||||
#include "ui/gfx/animation/tween.h"
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
#include "ui/gfx/geometry/rounded_corners_f.h"
|
||||
#include "ui/gfx/geometry/size.h"
|
||||
#include "ui/gfx/geometry/transform.h"
|
||||
#include "ui/gfx/geometry/vector2d.h"
|
||||
#include "ui/views/animation/animation_builder.h"
|
||||
#include "ui/views/background.h"
|
||||
#include "ui/views/controls/button/button.h"
|
||||
#include "ui/views/controls/image_view.h"
|
||||
#include "ui/views/controls/label.h"
|
||||
#include "ui/views/layout/box_layout.h"
|
||||
#include "ui/views/layout/box_layout_view.h"
|
||||
#include "ui/views/vector_icons.h"
|
||||
#include "ui/views/view.h"
|
||||
#include "ui/views/view_class_properties.h"
|
||||
#include "ui/views/view_utils.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
@@ -36,6 +47,19 @@ namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
// Horizontal spacing between the error view and action buttons.
|
||||
constexpr int kErrorViewActionButtonSpacing = 6;
|
||||
|
||||
constexpr auto kErrorViewBorderInsets = gfx::Insets::TLBR(8, 8, 8, 12);
|
||||
|
||||
constexpr int kErrorViewCornerRadius = 18;
|
||||
|
||||
constexpr int kErrorViewLeadingIconSize = 20;
|
||||
|
||||
// Padding to the right of the error view's leading icon, to separate the icon
|
||||
// from the error message label.
|
||||
constexpr auto kErrorViewLeadingIconRightPadding = 4;
|
||||
|
||||
// The horizontal distance between action buttons in a row.
|
||||
constexpr int kActionButtonSpacing = 10;
|
||||
|
||||
@@ -56,8 +80,82 @@ constexpr base::TimeDelta kSmartActionsButtonTransitionSlideInDuration =
|
||||
|
||||
} // namespace
|
||||
|
||||
ActionButtonContainerView::ErrorView::ErrorView()
|
||||
: shadow_(SystemShadow::CreateShadowOnTextureLayer(
|
||||
SystemShadow::Type::kElevation12)) {
|
||||
SetOrientation(views::BoxLayout::Orientation::kHorizontal);
|
||||
SetInsideBorderInsets(kErrorViewBorderInsets);
|
||||
|
||||
SetBackground(views::CreateThemedRoundedRectBackground(
|
||||
cros_tokens::kCrosSysSystemBaseElevated,
|
||||
gfx::RoundedCornersF(kErrorViewCornerRadius)));
|
||||
SetPaintToLayer();
|
||||
layer()->SetFillsBoundsOpaquely(false);
|
||||
shadow_->SetRoundedCornerRadius(kErrorViewCornerRadius);
|
||||
capture_mode_util::SetHighlightBorder(
|
||||
this, kErrorViewCornerRadius,
|
||||
views::HighlightBorder::Type::kHighlightBorderNoShadow);
|
||||
|
||||
AddChildView(views::Builder<views::ImageView>()
|
||||
.SetPreferredSize(gfx::Size(kErrorViewLeadingIconSize,
|
||||
kErrorViewLeadingIconSize))
|
||||
.SetImage(ui::ImageModel::FromVectorIcon(
|
||||
views::kInfoIcon, cros_tokens::kCrosSysSecondary))
|
||||
.SetProperty(views::kMarginsKey,
|
||||
gfx::Insets::TLBR(
|
||||
0, 0, 0, kErrorViewLeadingIconRightPadding))
|
||||
.Build());
|
||||
|
||||
AddChildView(
|
||||
views::Builder<views::Label>()
|
||||
.CopyAddressTo(&error_label_)
|
||||
.SetEnabledColorId(cros_tokens::kCrosSysSecondary)
|
||||
.SetFontList(TypographyProvider::Get()->ResolveTypographyToken(
|
||||
TypographyToken::kCrosAnnotation1))
|
||||
.Build());
|
||||
}
|
||||
|
||||
ActionButtonContainerView::ErrorView::~ErrorView() = default;
|
||||
|
||||
void ActionButtonContainerView::ErrorView::AddedToWidget() {
|
||||
views::BoxLayoutView::AddedToWidget();
|
||||
|
||||
// Attach the shadow at the bottom of the widget layer.
|
||||
ui::Layer* shadow_layer = shadow_->GetLayer();
|
||||
ui::Layer* widget_layer = GetWidget()->GetLayer();
|
||||
widget_layer->Add(shadow_layer);
|
||||
widget_layer->StackAtBottom(shadow_layer);
|
||||
|
||||
// Make the shadow observe the color provider source change to update the
|
||||
// colors.
|
||||
shadow_->ObserveColorProviderSource(GetWidget());
|
||||
}
|
||||
|
||||
void ActionButtonContainerView::ErrorView::OnBoundsChanged(
|
||||
const gfx::Rect& previous_bounds) {
|
||||
// The shadow layer is a sibling of this view's layer, and should have the
|
||||
// same bounds.
|
||||
shadow_->SetContentBounds(layer()->bounds());
|
||||
}
|
||||
|
||||
void ActionButtonContainerView::ErrorView::SetErrorMessage(
|
||||
const std::u16string& error_message) {
|
||||
error_label_->SetText(error_message);
|
||||
}
|
||||
|
||||
const std::u16string&
|
||||
ActionButtonContainerView::ErrorView::GetErrorMessageForTesting() const {
|
||||
return error_label_->GetText();
|
||||
}
|
||||
|
||||
ActionButtonContainerView::ActionButtonContainerView() {
|
||||
SetUseDefaultFillLayout(true);
|
||||
auto* box_layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
|
||||
views::BoxLayout::Orientation::kHorizontal));
|
||||
box_layout->set_between_child_spacing(kErrorViewActionButtonSpacing);
|
||||
|
||||
error_view_ = AddChildView(std::make_unique<ErrorView>());
|
||||
error_view_->SetVisible(false);
|
||||
|
||||
AddChildView(
|
||||
views::Builder<views::BoxLayoutView>()
|
||||
.CopyAddressTo(&action_button_row_)
|
||||
@@ -124,6 +222,16 @@ const views::View::Views& ActionButtonContainerView::GetActionButtons() const {
|
||||
return action_button_row_->children();
|
||||
}
|
||||
|
||||
void ActionButtonContainerView::ShowErrorView(
|
||||
const std::u16string& error_message) {
|
||||
error_view_->SetErrorMessage(error_message);
|
||||
error_view_->SetVisible(true);
|
||||
}
|
||||
|
||||
void ActionButtonContainerView::HideErrorView() {
|
||||
error_view_->SetVisible(false);
|
||||
}
|
||||
|
||||
void ActionButtonContainerView::StartSmartActionsButtonTransition() {
|
||||
views::Widget* widget = GetWidget();
|
||||
if (!widget) {
|
||||
@@ -214,6 +322,9 @@ void ActionButtonContainerView::SetWidgetEventsEnabled(bool enabled) {
|
||||
: aura::EventTargetingPolicy::kNone);
|
||||
}
|
||||
|
||||
BEGIN_METADATA(ActionButtonContainerView, ErrorView)
|
||||
END_METADATA
|
||||
|
||||
BEGIN_METADATA(ActionButtonContainerView)
|
||||
END_METADATA
|
||||
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#ifndef ASH_CAPTURE_MODE_ACTION_BUTTON_CONTAINER_VIEW_H_
|
||||
#define ASH_CAPTURE_MODE_ACTION_BUTTON_CONTAINER_VIEW_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
@@ -13,21 +14,53 @@
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "ui/base/metadata/metadata_header_macros.h"
|
||||
#include "ui/views/controls/button/button.h"
|
||||
#include "ui/views/layout/box_layout_view.h"
|
||||
#include "ui/views/view.h"
|
||||
|
||||
namespace gfx {
|
||||
struct VectorIcon;
|
||||
} // namespace gfx
|
||||
|
||||
namespace views {
|
||||
class Label;
|
||||
}
|
||||
|
||||
namespace ash {
|
||||
|
||||
class ActionButtonView;
|
||||
class SystemShadow;
|
||||
|
||||
// A view that displays a row of action buttons near the capture region.
|
||||
// A view that displays a row of action buttons near the capture region. It may
|
||||
// display an error message if actions are not available.
|
||||
class ASH_EXPORT ActionButtonContainerView : public views::View {
|
||||
METADATA_HEADER(ActionButtonContainerView, views::View)
|
||||
|
||||
public:
|
||||
// A view that displays an error message and icon.
|
||||
class ASH_EXPORT ErrorView : public views::BoxLayoutView {
|
||||
METADATA_HEADER(ErrorView, views::BoxLayoutView)
|
||||
|
||||
public:
|
||||
ErrorView();
|
||||
ErrorView(const ErrorView&) = delete;
|
||||
ErrorView& operator=(const ErrorView&) = delete;
|
||||
~ErrorView() override;
|
||||
|
||||
// views::BoxLayoutView:
|
||||
void AddedToWidget() override;
|
||||
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
|
||||
|
||||
// Sets the error message to show on the error view.
|
||||
void SetErrorMessage(const std::u16string& error_message);
|
||||
|
||||
const std::u16string& GetErrorMessageForTesting() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<SystemShadow> shadow_;
|
||||
|
||||
raw_ptr<views::Label> error_label_ = nullptr;
|
||||
};
|
||||
|
||||
ActionButtonContainerView();
|
||||
ActionButtonContainerView(const ActionButtonContainerView&) = delete;
|
||||
ActionButtonContainerView& operator=(const ActionButtonContainerView&) =
|
||||
@@ -50,12 +83,20 @@ 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);
|
||||
|
||||
// Hides the error view.
|
||||
void HideErrorView();
|
||||
|
||||
// Starts performing the button transition triggered after pressing the smart
|
||||
// actions button. This will fade out existing action buttons, remove the
|
||||
// smart actions button, then animate in new icon buttons to replace the old
|
||||
// copy text and search buttons.
|
||||
void StartSmartActionsButtonTransition();
|
||||
|
||||
const ErrorView* error_view_for_testing() const { return error_view_; }
|
||||
|
||||
private:
|
||||
// Called when the smart actions button has faded out, to start the transition
|
||||
// to new buttons. See `StartSmartActionsButtonTransition()`.
|
||||
@@ -67,6 +108,9 @@ class ASH_EXPORT ActionButtonContainerView : public views::View {
|
||||
// Contains the row of action buttons.
|
||||
raw_ptr<views::View> action_button_row_ = nullptr;
|
||||
|
||||
// Used to show an error message.
|
||||
raw_ptr<ErrorView> error_view_ = nullptr;
|
||||
|
||||
base::WeakPtrFactory<ActionButtonContainerView> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
|
@@ -124,5 +124,22 @@ TEST_F(ActionButtonContainerViewTest, SmartActionsButtonTransition) {
|
||||
EXPECT_TRUE(IsActionButtonCollapsed(search_button));
|
||||
}
|
||||
|
||||
TEST_F(ActionButtonContainerViewTest, ShowsErrorView) {
|
||||
ActionButtonContainerView action_button_container;
|
||||
const ActionButtonContainerView::ErrorView* error_view =
|
||||
action_button_container.error_view_for_testing();
|
||||
|
||||
EXPECT_FALSE(error_view->GetVisible());
|
||||
|
||||
action_button_container.ShowErrorView(u"Error message");
|
||||
|
||||
EXPECT_TRUE(error_view->GetVisible());
|
||||
EXPECT_EQ(error_view->GetErrorMessageForTesting(), u"Error message");
|
||||
|
||||
action_button_container.HideErrorView();
|
||||
|
||||
EXPECT_FALSE(error_view->GetVisible());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ash
|
||||
|
Reference in New Issue
Block a user