Skip to content

Commit

Permalink
Add AssistantZeroStateView to AssistantMainStage.
Browse files Browse the repository at this point in the history
Currently AssistantZeroStateView's only child is the pre-existing
greeting label.

Moving forward, AssistantZeroStateView will conditionally show a richer
view in lieu of greeting label.

The changes in this CL should not be perceivable to the end user.

Bug: b:157510546
Change-Id: I9e813a3d04a9ee9c734c9f5e2ff6913fd18b0ceb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2213925
Commit-Queue: David Black <dmblack@google.com>
Reviewed-by: Xiaohui Chen <xiaohuic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772483}
  • Loading branch information
David Black authored and Commit Bot committed May 28, 2020
1 parent 3b4458a commit 784ed21
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 75 deletions.
104 changes: 42 additions & 62 deletions ash/app_list/views/assistant/assistant_main_stage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
#include "ash/assistant/ui/main_stage/assistant_footer_view.h"
#include "ash/assistant/ui/main_stage/assistant_progress_indicator.h"
#include "ash/assistant/ui/main_stage/assistant_query_view.h"
#include "ash/assistant/ui/main_stage/assistant_zero_state_view.h"
#include "ash/assistant/ui/main_stage/ui_element_container_view.h"
#include "ash/assistant/util/animation_util.h"
#include "ash/assistant/util/assistant_util.h"
#include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h"
#include "ash/public/cpp/assistant/controller/assistant_ui_controller.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/bind.h"
#include "base/time/time.h"
#include "ui/base/l10n/l10n_util.h"
Expand All @@ -29,7 +29,6 @@
#include "ui/gfx/color_palette.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/layout_manager.h"
Expand Down Expand Up @@ -60,15 +59,15 @@ constexpr base::TimeDelta kDividerAnimationFadeInDuration =
constexpr base::TimeDelta kDividerAnimationFadeOutDuration =
base::TimeDelta::FromMilliseconds(83);

// Greeting animation.
constexpr base::TimeDelta kGreetingAnimationFadeOutDuration =
// Zero state animation.
constexpr base::TimeDelta kZeroStateAnimationFadeOutDuration =
base::TimeDelta::FromMilliseconds(83);
constexpr int kGreetingAnimationTranslationDip = 115;
constexpr base::TimeDelta kGreetingAnimationFadeInDelay =
constexpr int kZeroStateAnimationTranslationDip = 115;
constexpr base::TimeDelta kZeroStateAnimationFadeInDelay =
base::TimeDelta::FromMilliseconds(33);
constexpr base::TimeDelta kGreetingAnimationFadeInDuration =
constexpr base::TimeDelta kZeroStateAnimationFadeInDuration =
base::TimeDelta::FromMilliseconds(167);
constexpr base::TimeDelta kGreetingAnimationTranslateUpDuration =
constexpr base::TimeDelta kZeroStateAnimationTranslateUpDuration =
base::TimeDelta::FromMilliseconds(250);

// HorizontalSeparator ---------------------------------------------------------
Expand Down Expand Up @@ -173,7 +172,7 @@ AppListAssistantMainStage::CreateContentLayoutContainer() {
// The content layout container stacks two views.
// On top is a main content container including the line separator, progress
// indicator query view and |ui_element_container_|.
// |greeting_label_| is laid out above of the main content container. As
// The |zero_state_view_| is laid out above of the main content container. As
// such, it floats above and does not cause repositioning to any of content
// layout's underlying views.
auto content_layout_container = std::make_unique<views::View>();
Expand All @@ -189,37 +188,18 @@ AppListAssistantMainStage::CreateContentLayoutContainer() {
stack_layout->SetRespectDimensionForView(
main_content_layout_container, StackLayout::RespectDimension::kWidth);

greeting_label_ = content_layout_container->AddChildView(InitGreetingLabel());
// Zero state, which will be animated on its own layer.
zero_state_view_ = content_layout_container->AddChildView(
std::make_unique<AssistantZeroStateView>());
zero_state_view_->SetPaintToLayer();
zero_state_view_->layer()->SetFillsBoundsOpaquely(false);

// We need to stretch |greeting_label_| to match its parent so that it
// won't use heuristics in Label to infer line breaking, which seems to cause
// text clipping with DPI adjustment. See b/112843496.
stack_layout->SetRespectDimensionForView(
greeting_label_, StackLayout::RespectDimension::kHeight);
stack_layout->SetVerticalAlignmentForView(
greeting_label_, StackLayout::VerticalAlignment::kCenter);
zero_state_view_, StackLayout::VerticalAlignment::kCenter);

return content_layout_container;
}

std::unique_ptr<views::Label> AppListAssistantMainStage::InitGreetingLabel() {
// Greeting label, which will be animated on its own layer.
auto greeting_label = std::make_unique<views::Label>(
l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_PROMPT_DEFAULT));
greeting_label->SetID(AssistantViewID::kGreetingLabel);
greeting_label->SetAutoColorReadabilityEnabled(false);
greeting_label->SetEnabledColor(kTextColorPrimary);
greeting_label->SetFontList(assistant::ui::GetDefaultFontList()
.DeriveWithSizeDelta(8)
.DeriveWithWeight(gfx::Font::Weight::MEDIUM));
greeting_label->SetHorizontalAlignment(
gfx::HorizontalAlignment::ALIGN_CENTER);
greeting_label->SetMultiLine(true);
greeting_label->SetPaintToLayer();
greeting_label->SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
return greeting_label;
}

std::unique_ptr<views::View>
AppListAssistantMainStage::CreateMainContentLayoutContainer() {
auto content_layout_container = std::make_unique<views::View>();
Expand Down Expand Up @@ -295,31 +275,31 @@ AppListAssistantMainStage::CreateFooterLayoutContainer() {
return footer_container;
}

void AppListAssistantMainStage::AnimateInGreetingLabel() {
greeting_label_->layer()->GetAnimator()->StopAnimating();
void AppListAssistantMainStage::AnimateInZeroState() {
zero_state_view_->layer()->GetAnimator()->StopAnimating();

// We're going to animate the greeting label up into position so we'll
// need to apply an initial transformation.
// We're going to animate the zero state view up into position so we'll need
// to apply an initial transformation.
gfx::Transform transform;
transform.Translate(0, kGreetingAnimationTranslationDip);
transform.Translate(0, kZeroStateAnimationTranslationDip);

// Set up our pre-animation values.
greeting_label_->layer()->SetOpacity(0.f);
greeting_label_->layer()->SetTransform(transform);
greeting_label_->SetVisible(true);
zero_state_view_->layer()->SetOpacity(0.f);
zero_state_view_->layer()->SetTransform(transform);
zero_state_view_->SetVisible(true);

// Start animating greeting label.
greeting_label_->layer()->GetAnimator()->StartTogether(
// Start animating the zero state view.
zero_state_view_->layer()->GetAnimator()->StartTogether(
{// Animate the transformation.
CreateLayerAnimationSequence(CreateTransformElement(
gfx::Transform(), kGreetingAnimationTranslateUpDuration,
gfx::Transform(), kZeroStateAnimationTranslateUpDuration,
gfx::Tween::Type::FAST_OUT_SLOW_IN_2)),
// Animate the opacity to 100% with delay.
CreateLayerAnimationSequence(
ui::LayerAnimationElement::CreatePauseElement(
ui::LayerAnimationElement::AnimatableProperty::OPACITY,
kGreetingAnimationFadeInDelay),
CreateOpacityElement(1.f, kGreetingAnimationFadeInDuration))});
kZeroStateAnimationFadeInDelay),
CreateOpacityElement(1.f, kZeroStateAnimationFadeInDuration))});
}

void AppListAssistantMainStage::AnimateInFooter() {
Expand All @@ -345,8 +325,8 @@ void AppListAssistantMainStage::OnCommittedQueryChanged(
// Update the view.
query_view_->SetQuery(query);

// If query is empty and we are showing greeting label, do not update the Ui.
if (query.Empty() && IsShown(greeting_label_))
// If query is empty and we are showing zero state, do not update the Ui.
if (query.Empty() && IsShown(zero_state_view_))
return;

// Hide the horizontal separator.
Expand All @@ -364,18 +344,18 @@ void AppListAssistantMainStage::OnCommittedQueryChanged(
// ...then fade in.
CreateOpacityElement(1.f, kDividerAnimationFadeInDuration)));

MaybeHideGreetingLabel();
MaybeHideZeroState();
}

void AppListAssistantMainStage::OnPendingQueryChanged(
const AssistantQuery& query) {
// Update the view.
query_view_->SetQuery(query);

if (!IsShown(greeting_label_))
if (!IsShown(zero_state_view_))
return;

// Animate the opacity to 100% with delay equal to |greeting_label_| fade out
// Animate the opacity to 100% with delay equal to |zero_state_view_| fade out
// animation duration to avoid the two views displaying at the same time.
constexpr base::TimeDelta kQueryAnimationFadeInDuration =
base::TimeDelta::FromMilliseconds(433);
Expand All @@ -384,11 +364,11 @@ void AppListAssistantMainStage::OnPendingQueryChanged(
CreateLayerAnimationSequence(
ui::LayerAnimationElement::CreatePauseElement(
ui::LayerAnimationElement::AnimatableProperty::OPACITY,
kGreetingAnimationFadeOutDuration),
kZeroStateAnimationFadeOutDuration),
CreateOpacityElement(1.f, kQueryAnimationFadeInDuration)));

if (!query.Empty())
MaybeHideGreetingLabel();
MaybeHideZeroState();
}

void AppListAssistantMainStage::OnPendingQueryCleared(bool due_to_commit) {
Expand All @@ -402,7 +382,7 @@ void AppListAssistantMainStage::OnPendingQueryCleared(bool due_to_commit) {

void AppListAssistantMainStage::OnResponseChanged(
const scoped_refptr<AssistantResponse>& response) {
MaybeHideGreetingLabel();
MaybeHideZeroState();

// Show the horizontal separator.
horizontal_separator_->layer()->GetAnimator()->StartAnimation(
Expand All @@ -427,16 +407,16 @@ void AppListAssistantMainStage::OnUiVisibilityChanged(
base::Optional<AssistantExitPoint> exit_point) {
if (assistant::util::IsStartingSession(new_visibility, old_visibility)) {
// When Assistant is starting a new session, we animate in the appearance of
// the greeting label and footer.
// the zero state view and footer.
const bool from_search =
entry_point == AssistantEntryPoint::kLauncherSearchResult;
progress_indicator_->layer()->SetOpacity(0.f);
horizontal_separator_->layer()->SetOpacity(from_search ? 1.f : 0.f);

if (!from_search)
AnimateInGreetingLabel();
AnimateInZeroState();
else
greeting_label_->SetVisible(false);
zero_state_view_->SetVisible(false);

AnimateInFooter();
return;
Expand All @@ -449,12 +429,12 @@ void AppListAssistantMainStage::OnUiVisibilityChanged(
footer_->set_can_process_events_within_subtree(true);
}

void AppListAssistantMainStage::MaybeHideGreetingLabel() {
if (!IsShown(greeting_label_))
void AppListAssistantMainStage::MaybeHideZeroState() {
if (!IsShown(zero_state_view_))
return;

assistant::util::FadeOutAndHide(greeting_label_,
kGreetingAnimationFadeOutDuration);
assistant::util::FadeOutAndHide(zero_state_view_,
kZeroStateAnimationFadeOutDuration);
}

} // namespace ash
13 changes: 5 additions & 8 deletions ash/app_list/views/assistant/assistant_main_stage.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,13 @@
#include "ui/views/view.h"
#include "ui/views/view_observer.h"

namespace views {
class Label;
} // namespace views

namespace ash {

class AssistantFooterView;
class AssistantProgressIndicator;
class AssistantQueryView;
class AssistantViewDelegate;
class AssistantZeroStateView;
class UiElementContainerView;

// AppListAssistantMainStage is the child of AssistantMainView responsible for
Expand Down Expand Up @@ -68,15 +66,14 @@ class APP_LIST_EXPORT AppListAssistantMainStage
private:
void InitLayout();
std::unique_ptr<views::View> CreateContentLayoutContainer();
std::unique_ptr<views::Label> InitGreetingLabel();
std::unique_ptr<views::View> CreateMainContentLayoutContainer();
std::unique_ptr<views::View> CreateDividerLayoutContainer();
std::unique_ptr<views::View> CreateFooterLayoutContainer();

void AnimateInGreetingLabel();
void AnimateInZeroState();
void AnimateInFooter();

void MaybeHideGreetingLabel();
void MaybeHideZeroState();

AssistantViewDelegate* const delegate_; // Owned by Shell.

Expand All @@ -85,7 +82,7 @@ class APP_LIST_EXPORT AppListAssistantMainStage
views::View* horizontal_separator_;
AssistantQueryView* query_view_;
UiElementContainerView* ui_element_container_;
views::Label* greeting_label_;
AssistantZeroStateView* zero_state_view_;
AssistantFooterView* footer_;

ScopedObserver<AssistantController, AssistantControllerObserver>
Expand Down
10 changes: 5 additions & 5 deletions ash/app_list/views/assistant/assistant_page_view_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -356,36 +356,36 @@ TEST_F(AssistantPageViewTest, ShouldFocusMicWhenOpeningWithHotword) {
TEST_F(AssistantPageViewTest, ShouldShowGreetingLabelWhenOpening) {
ShowAssistantUi();

EXPECT_TRUE(greeting_label()->GetVisible());
EXPECT_TRUE(greeting_label()->IsDrawn());
}

TEST_F(AssistantPageViewTest, ShouldDismissGreetingLabelAfterQuery) {
ShowAssistantUi();

MockTextInteraction().WithTextResponse("The response");

EXPECT_FALSE(greeting_label()->GetVisible());
EXPECT_FALSE(greeting_label()->IsDrawn());
}

TEST_F(AssistantPageViewTest, ShouldShowGreetingLabelAgainAfterReopening) {
ShowAssistantUi();

// Cause the label to be hidden.
MockTextInteraction().WithTextResponse("The response");
ASSERT_FALSE(greeting_label()->GetVisible());
ASSERT_FALSE(greeting_label()->IsDrawn());

// Close and reopen the Assistant UI.
CloseAssistantUi();
ShowAssistantUi();

EXPECT_TRUE(greeting_label()->GetVisible());
EXPECT_TRUE(greeting_label()->IsDrawn());
}

TEST_F(AssistantPageViewTest,
ShouldNotShowGreetingLabelWhenOpeningFromSearchResult) {
ShowAssistantUi(AssistantEntryPoint::kLauncherSearchResult);

EXPECT_FALSE(greeting_label()->GetVisible());
EXPECT_FALSE(greeting_label()->IsDrawn());
}

TEST_F(AssistantPageViewTest, ShouldFocusMicViewWhenPressingVoiceInputToggle) {
Expand Down
2 changes: 2 additions & 0 deletions ash/assistant/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ component("ui") {
"main_stage/assistant_ui_element_view.h",
"main_stage/assistant_ui_element_view_factory.cc",
"main_stage/assistant_ui_element_view_factory.h",
"main_stage/assistant_zero_state_view.cc",
"main_stage/assistant_zero_state_view.h",
"main_stage/element_animator.cc",
"main_stage/element_animator.h",
"main_stage/suggestion_chip_view.cc",
Expand Down
1 change: 1 addition & 0 deletions ash/assistant/ui/assistant_view_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum AssistantViewID {
kQueryView,
kSuggestionContainer,
kUiElementContainer,
kZeroStateView,
};

} // namespace ash
Expand Down
57 changes: 57 additions & 0 deletions ash/assistant/ui/main_stage/assistant_zero_state_view.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/assistant/ui/main_stage/assistant_zero_state_view.h"

#include <memory>

#include "ash/assistant/ui/assistant_ui_constants.h"
#include "ash/assistant/ui/assistant_view_ids.h"
#include "ash/strings/grit/ash_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/background.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"

namespace ash {

AssistantZeroStateView::AssistantZeroStateView() {
SetID(AssistantViewID::kZeroStateView);
InitLayout();
}

AssistantZeroStateView::~AssistantZeroStateView() = default;

const char* AssistantZeroStateView::GetClassName() const {
return "AssistantZeroStateView";
}

gfx::Size AssistantZeroStateView::CalculatePreferredSize() const {
return gfx::Size(INT_MAX, GetHeightForWidth(INT_MAX));
}

void AssistantZeroStateView::ChildPreferredSizeChanged(views::View* child) {
PreferredSizeChanged();
}

void AssistantZeroStateView::InitLayout() {
SetLayoutManager(std::make_unique<views::FillLayout>());

// Greeting label.
auto greeting_label = std::make_unique<views::Label>(
l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_PROMPT_DEFAULT));
greeting_label->SetID(AssistantViewID::kGreetingLabel);
greeting_label->SetAutoColorReadabilityEnabled(false);
greeting_label->SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
greeting_label->SetEnabledColor(kTextColorPrimary);
greeting_label->SetFontList(assistant::ui::GetDefaultFontList()
.DeriveWithSizeDelta(8)
.DeriveWithWeight(gfx::Font::Weight::MEDIUM));
greeting_label->SetHorizontalAlignment(
gfx::HorizontalAlignment::ALIGN_CENTER);
greeting_label->SetMultiLine(true);
AddChildView(std::move(greeting_label));
}

} // namespace ash
Loading

0 comments on commit 784ed21

Please sign in to comment.