Commit e12533a6 authored by David Black's avatar David Black Committed by Commit Bot

Add scroll indication to Assistant's UiElementContainerView.

Scroll indicator is drawn over UiElementContainerView's empty bottom
border to work around issue of drawing over top of Assistant cards.

Visibility of the scroll indicator view is synced to vertical scroll
bar update/visibility events.

Bug: b:112669597
Change-Id: Ib8ae57428bb827913957fdd92168868c181ab4d7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2024285Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Commit-Queue: David Black <dmblack@google.com>
Cr-Commit-Position: refs/heads/master@{#736437}
parent 91e0f47e
...@@ -10,6 +10,7 @@ include_rules = [ ...@@ -10,6 +10,7 @@ include_rules = [
"+ash/strings", "+ash/strings",
"+base", "+base",
"+build/buildflag.h", "+build/buildflag.h",
"+cc/base",
"+cc/paint", "+cc/paint",
"+chromeos/assistant", "+chromeos/assistant",
"+chromeos/services/assistant/public", "+chromeos/services/assistant/public",
......
...@@ -47,15 +47,32 @@ class ContentView : public views::View, views::ViewObserver { ...@@ -47,15 +47,32 @@ class ContentView : public views::View, views::ViewObserver {
class InvisibleScrollBar : public views::OverlayScrollBar { class InvisibleScrollBar : public views::OverlayScrollBar {
public: public:
explicit InvisibleScrollBar(bool horizontal) InvisibleScrollBar(AssistantScrollView* parent, bool horizontal)
: views::OverlayScrollBar(horizontal) {} : views::OverlayScrollBar(horizontal), parent_(parent) {}
~InvisibleScrollBar() override = default; ~InvisibleScrollBar() override = default;
// views::OverlayScrollBar: // views::OverlayScrollBar:
int GetThickness() const override { return 0; } int GetThickness() const override { return 0; }
void Update(int viewport_size,
int content_size,
int content_scroll_offset) override {
views::OverlayScrollBar::Update(viewport_size, content_size,
content_scroll_offset);
parent_->OnScrollBarUpdated(this, viewport_size, content_size,
content_scroll_offset);
}
void VisibilityChanged(views::View* starting_from, bool is_visible) override {
if (starting_from == this)
parent_->OnScrollBarVisibilityChanged(this, is_visible);
}
private: private:
AssistantScrollView* const parent_; // Owned by view hierarchy, owns |this|.
DISALLOW_COPY_AND_ASSIGN(InvisibleScrollBar); DISALLOW_COPY_AND_ASSIGN(InvisibleScrollBar);
}; };
...@@ -89,10 +106,10 @@ void AssistantScrollView::InitLayout() { ...@@ -89,10 +106,10 @@ void AssistantScrollView::InitLayout() {
// Scroll bars. // Scroll bars.
horizontal_scroll_bar_ = SetHorizontalScrollBar( horizontal_scroll_bar_ = SetHorizontalScrollBar(
std::make_unique<InvisibleScrollBar>(/*horizontal=*/true)); std::make_unique<InvisibleScrollBar>(this, /*horizontal=*/true));
vertical_scroll_bar_ = SetVerticalScrollBar( vertical_scroll_bar_ = SetVerticalScrollBar(
std::make_unique<InvisibleScrollBar>(/*horizontal=*/false)); std::make_unique<InvisibleScrollBar>(this, /*horizontal=*/false));
} }
} // namespace ash } // namespace ash
...@@ -27,12 +27,19 @@ class COMPONENT_EXPORT(ASSISTANT_UI) AssistantScrollView ...@@ -27,12 +27,19 @@ class COMPONENT_EXPORT(ASSISTANT_UI) AssistantScrollView
virtual void OnContentsPreferredSizeChanged(views::View* content_view) = 0; virtual void OnContentsPreferredSizeChanged(views::View* content_view) = 0;
virtual void OnScrollBarUpdated(views::ScrollBar* scroll_bar,
int viewport_size,
int content_size,
int content_scroll_offset) {}
virtual void OnScrollBarVisibilityChanged(views::ScrollBar* scroll_bar,
bool is_visible) {}
protected: protected:
views::View* content_view() { return content_view_; } views::View* content_view() { return content_view_; }
const views::View* content_view() const { return content_view_; } const views::View* content_view() const { return content_view_; }
views::ScrollBar* horizontal_scroll_bar() { return horizontal_scroll_bar_; } views::ScrollBar* horizontal_scroll_bar() { return horizontal_scroll_bar_; }
views::ScrollBar* vertical_scroll_bar() { return vertical_scroll_bar_; } views::ScrollBar* vertical_scroll_bar() { return vertical_scroll_bar_; }
private: private:
......
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
#include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/app_list/app_list_features.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "cc/base/math_util.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/views/background.h"
#include "ui/views/border.h" #include "ui/views/border.h"
#include "ui/views/layout/box_layout.h" #include "ui/views/layout/box_layout.h"
...@@ -33,6 +35,7 @@ constexpr int kEmbeddedUiFirstCardMarginTopDip = 8; ...@@ -33,6 +35,7 @@ constexpr int kEmbeddedUiFirstCardMarginTopDip = 8;
constexpr int kEmbeddedUiPaddingBottomDip = 8; constexpr int kEmbeddedUiPaddingBottomDip = 8;
constexpr int kMainUiFirstCardMarginTopDip = 40; constexpr int kMainUiFirstCardMarginTopDip = 40;
constexpr int kMainUiPaddingBottomDip = 24; constexpr int kMainUiPaddingBottomDip = 24;
constexpr int kScrollIndicatorHeightDip = 1;
// Helpers --------------------------------------------------------------------- // Helpers ---------------------------------------------------------------------
...@@ -86,6 +89,14 @@ gfx::Size UiElementContainerView::GetMinimumSize() const { ...@@ -86,6 +89,14 @@ gfx::Size UiElementContainerView::GetMinimumSize() const {
return gfx::Size(INT_MAX, 1); return gfx::Size(INT_MAX, 1);
} }
void UiElementContainerView::Layout() {
AnimatedContainerView::Layout();
// Scroll indicator.
scroll_indicator_->SetBounds(0, height() - kScrollIndicatorHeightDip, width(),
kScrollIndicatorHeightDip);
}
void UiElementContainerView::OnContentsPreferredSizeChanged( void UiElementContainerView::OnContentsPreferredSizeChanged(
views::View* content_view) { views::View* content_view) {
const int preferred_height = content_view->GetHeightForWidth(width()); const int preferred_height = content_view->GetHeightForWidth(width());
...@@ -93,11 +104,33 @@ void UiElementContainerView::OnContentsPreferredSizeChanged( ...@@ -93,11 +104,33 @@ void UiElementContainerView::OnContentsPreferredSizeChanged(
} }
void UiElementContainerView::InitLayout() { void UiElementContainerView::InitLayout() {
// Content.
content_view()->SetLayoutManager(std::make_unique<views::BoxLayout>( content_view()->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, views::BoxLayout::Orientation::kVertical,
gfx::Insets(0, kUiElementHorizontalMarginDip, GetPaddingBottomDip(), gfx::Insets(0, kUiElementHorizontalMarginDip, GetPaddingBottomDip(),
kUiElementHorizontalMarginDip), kUiElementHorizontalMarginDip),
kSpacingDip)); kSpacingDip));
// Scroll indicator.
scroll_indicator_ = AddChildView(std::make_unique<views::View>());
scroll_indicator_->SetBackground(
views::CreateSolidBackground(gfx::kGoogleGrey300));
// The scroll indicator paints to its own layer which is animated in/out using
// implicit animation settings.
scroll_indicator_->SetPaintToLayer();
scroll_indicator_->layer()->SetAnimator(
ui::LayerAnimator::CreateImplicitAnimator());
scroll_indicator_->layer()->SetFillsBoundsOpaquely(false);
scroll_indicator_->layer()->SetOpacity(0.f);
// We cannot draw |scroll_indicator_| over Assistant cards due to issues w/
// layer ordering. Because |kScrollIndicatorHeightDip| is sufficiently small,
// we'll use an empty bottom border to reserve space for |scroll_indicator_|.
// When |scroll_indicator_| is not visible, this just adds a negligible amount
// of margin to the bottom of the content. Otherwise, |scroll_indicator_| will
// occupy this space.
SetBorder(views::CreateEmptyBorder(0, 0, kScrollIndicatorHeightDip, 0));
} }
void UiElementContainerView::OnCommittedQueryChanged( void UiElementContainerView::OnCommittedQueryChanged(
...@@ -176,4 +209,34 @@ void UiElementContainerView::OnAllViewsAnimatedIn() { ...@@ -176,4 +209,34 @@ void UiElementContainerView::OnAllViewsAnimatedIn() {
NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true); NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
} }
void UiElementContainerView::OnScrollBarUpdated(views::ScrollBar* scroll_bar,
int viewport_size,
int content_size,
int content_scroll_offset) {
if (scroll_bar != vertical_scroll_bar())
return;
// When the vertical scroll bar is updated, we update our |scroll_indicator_|.
bool can_scroll = content_size > (content_scroll_offset + viewport_size);
UpdateScrollIndicator(can_scroll);
}
void UiElementContainerView::OnScrollBarVisibilityChanged(
views::ScrollBar* scroll_bar,
bool is_visible) {
// When the vertical scroll bar is hidden, we need to update our
// |scroll_indicator_|. This may occur during a layout pass when the new
// content no longer requires a vertical scroll bar while the old content did.
if (scroll_bar == vertical_scroll_bar() && !is_visible)
UpdateScrollIndicator(/*can_scroll=*/false);
}
void UiElementContainerView::UpdateScrollIndicator(bool can_scroll) {
const float target_opacity = can_scroll ? 1.f : 0.f;
ui::Layer* layer = scroll_indicator_->layer();
if (!cc::MathUtil::IsWithinEpsilon(layer->GetTargetOpacity(), target_opacity))
layer->SetOpacity(target_opacity);
}
} // namespace ash } // namespace ash
...@@ -37,6 +37,7 @@ class COMPONENT_EXPORT(ASSISTANT_UI) UiElementContainerView ...@@ -37,6 +37,7 @@ class COMPONENT_EXPORT(ASSISTANT_UI) UiElementContainerView
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
int GetHeightForWidth(int width) const override; int GetHeightForWidth(int width) const override;
gfx::Size GetMinimumSize() const override; gfx::Size GetMinimumSize() const override;
void Layout() override;
void OnContentsPreferredSizeChanged(views::View* content_view) override; void OnContentsPreferredSizeChanged(views::View* content_view) override;
void OnCommittedQueryChanged(const AssistantQuery& query) override; void OnCommittedQueryChanged(const AssistantQuery& query) override;
...@@ -47,9 +48,19 @@ class COMPONENT_EXPORT(ASSISTANT_UI) UiElementContainerView ...@@ -47,9 +48,19 @@ class COMPONENT_EXPORT(ASSISTANT_UI) UiElementContainerView
void HandleResponse(const AssistantResponse& response) override; void HandleResponse(const AssistantResponse& response) override;
void OnAllViewsRemoved() override; void OnAllViewsRemoved() override;
void OnAllViewsAnimatedIn() override; void OnAllViewsAnimatedIn() override;
void OnScrollBarUpdated(views::ScrollBar* scroll_bar,
int viewport_size,
int content_size,
int content_scroll_offset) override;
void OnScrollBarVisibilityChanged(views::ScrollBar* scroll_bar,
bool is_visible) override;
void OnCardElementAdded(const AssistantCardElement* card_element); void OnCardElementAdded(const AssistantCardElement* card_element);
void UpdateScrollIndicator(bool can_scroll);
views::View* scroll_indicator_ = nullptr; // Owned by view hierarchy.
// Factory instance used to construct views for modeled UI elements. // Factory instance used to construct views for modeled UI elements.
std::unique_ptr<AssistantUiElementViewFactory> view_factory_; std::unique_ptr<AssistantUiElementViewFactory> view_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