Commit 92346b15 authored by David Black's avatar David Black Committed by Commit Bot

Implement AssistantProgressIndicator motion spec.

Still missing tweens. Need to discuss with UX about potentially revising
specs to use pre-defined tweens.

See bug for demo.

Bug: b:111573788
Change-Id: I7d94416afa834d83aafa7e1e5f8eb9d6efe44333
Reviewed-on: https://chromium-review.googlesource.com/1144197
Commit-Queue: David Black <dmblack@google.com>
Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577765}
parent ff77dbed
......@@ -36,6 +36,8 @@ constexpr int kIconSizeDip = 24;
constexpr int kPreferredHeightDip = 48;
// Animation.
constexpr base::TimeDelta kAnimationFadeInDelay =
base::TimeDelta::FromMilliseconds(83);
constexpr base::TimeDelta kAnimationFadeInDuration =
base::TimeDelta::FromMilliseconds(100);
constexpr base::TimeDelta kAnimationFadeOutDuration =
......@@ -258,11 +260,13 @@ void DialogPlate::OnInputModalityChanged(InputModality input_modality) {
gfx::Transform(), kAnimationTransformInDuration,
gfx::Tween::Type::FAST_OUT_SLOW_IN_2)),
// Animate opacity to 100% with delay.
assistant::util::CreateLayerAnimationSequenceWithDelay(
assistant::util::CreateLayerAnimationSequence(
ui::LayerAnimationElement::CreatePauseElement(
ui::LayerAnimationElement::AnimatableProperty::OPACITY,
kAnimationFadeInDelay),
assistant::util::CreateOpacityElement(
1.f, kAnimationFadeInDuration,
gfx::Tween::Type::FAST_OUT_LINEAR_IN),
/*delay=*/kAnimationFadeOutDuration)});
gfx::Tween::Type::FAST_OUT_LINEAR_IN))});
// When switching to keyboard input modality, we focus the textfield.
textfield_->RequestFocus();
......@@ -290,11 +294,13 @@ void DialogPlate::OnInputModalityChanged(InputModality input_modality) {
gfx::Transform(), kAnimationTransformInDuration,
gfx::Tween::Type::FAST_OUT_SLOW_IN_2)),
// Animate opacity to 100% with delay.
assistant::util::CreateLayerAnimationSequenceWithDelay(
assistant::util::CreateLayerAnimationSequence(
ui::LayerAnimationElement::CreatePauseElement(
ui::LayerAnimationElement::AnimatableProperty::OPACITY,
kAnimationFadeInDelay),
assistant::util::CreateOpacityElement(
1.f, kAnimationFadeInDuration,
gfx::Tween::Type::FAST_OUT_LINEAR_IN),
/*delay=*/kAnimationFadeOutDuration)});
gfx::Tween::Type::FAST_OUT_LINEAR_IN))});
break;
}
case InputModality::kStylus:
......
......@@ -4,47 +4,61 @@
#include "ash/assistant/ui/main_stage/assistant_progress_indicator.h"
#include <memory>
#include "ash/assistant/util/animation_util.h"
#include "base/bind.h"
#include "base/time/time.h"
#include "ui/compositor/layer_animation_element.h"
#include "ui/compositor/layer_animator.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"
namespace ash {
namespace {
// Appearance.
constexpr int kDotCount = 3;
constexpr int kDotSizeDip = 6;
constexpr float kDotLargeSizeDip = 9.f;
constexpr float kDotSmallSizeDip = 6.f;
constexpr int kSpacingDip = 4;
// DotView ---------------------------------------------------------------------
// Animation.
constexpr base::TimeDelta kAnimationOffsetDuration =
base::TimeDelta::FromMilliseconds(216);
constexpr base::TimeDelta kAnimationPauseDuration =
base::TimeDelta::FromMilliseconds(500);
constexpr base::TimeDelta kAnimationScaleUpDuration =
base::TimeDelta::FromMilliseconds(266);
constexpr base::TimeDelta kAnimationScaleDownDuration =
base::TimeDelta::FromMilliseconds(450);
class DotView : public views::View {
public:
DotView() = default;
~DotView() override = default;
// Transformation.
constexpr float kScaleFactor = kDotLargeSizeDip / kDotSmallSizeDip;
constexpr float kTranslationDip = -(kDotLargeSizeDip - kDotSmallSizeDip) / 2.f;
// views::View:
gfx::Size CalculatePreferredSize() const override {
return gfx::Size(kDotSizeDip, GetHeightForWidth(kDotSizeDip));
}
// DotBackground ---------------------------------------------------------------
int GetHeightForWidth(int width) const override { return kDotSizeDip; }
class DotBackground : public views::Background {
public:
DotBackground() = default;
~DotBackground() override = default;
void OnPaint(gfx::Canvas* canvas) override {
void Paint(gfx::Canvas* canvas, views::View* view) const override {
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setColor(gfx::kGoogleGrey300);
const gfx::Rect& b = GetContentsBounds();
const gfx::Rect& b = view->GetContentsBounds();
const gfx::Point center = gfx::Point(b.width() / 2, b.height() / 2);
const int radius = std::min(b.width() / 2, b.height() / 2);
canvas->DrawCircle(center, kDotSizeDip / 2, flags);
canvas->DrawCircle(center, radius, flags);
}
private:
DISALLOW_COPY_AND_ASSIGN(DotView);
DISALLOW_COPY_AND_ASSIGN(DotBackground);
};
} // namespace
......@@ -61,9 +75,72 @@ void AssistantProgressIndicator::InitLayout() {
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), kSpacingDip));
// Dots.
for (int i = 0; i < kDotCount; ++i)
AddChildView(new DotView());
// Initialize dots.
for (int i = 0; i < kDotCount; ++i) {
views::View* dot_view = new views::View();
dot_view->SetBackground(std::make_unique<DotBackground>());
dot_view->SetPreferredSize(gfx::Size(kDotSmallSizeDip, kDotSmallSizeDip));
// Dots will animate on their own layers.
dot_view->SetPaintToLayer();
dot_view->layer()->SetFillsBoundsOpaquely(false);
AddChildView(dot_view);
}
}
void AssistantProgressIndicator::AddedToWidget() {
VisibilityChanged(/*starting_from=*/this, /*is_visible=*/visible());
}
void AssistantProgressIndicator::RemovedFromWidget() {
VisibilityChanged(/*starting_from=*/this, /*is_visible=*/false);
}
void AssistantProgressIndicator::VisibilityChanged(views::View* starting_from,
bool is_visible) {
if (!is_visible) {
// Stop all animations.
for (int i = 0; i < child_count(); ++i) {
child_at(i)->layer()->GetAnimator()->StopAnimating();
}
return;
}
using namespace assistant::util;
// The animation performs scaling on the child views. In order to give the
// illusion that scaling is being performed about the center of the view as
// the transformation origin, we also need to perform a translation.
gfx::Transform transform;
transform.Translate(kTranslationDip, kTranslationDip);
transform.Scale(kScaleFactor, kScaleFactor);
for (int i = 0; i < child_count(); ++i) {
views::View* view = child_at(i);
if (i > 0) {
// Schedule the animations to start after an offset.
view->layer()->GetAnimator()->SchedulePauseForProperties(
i * kAnimationOffsetDuration,
ui::LayerAnimationElement::AnimatableProperty::TRANSFORM);
}
// Schedule transformation animation.
view->layer()->GetAnimator()->ScheduleAnimation(
CreateLayerAnimationSequence(
// Animate scale up.
CreateTransformElement(transform, kAnimationScaleUpDuration),
// Animate scale down.
CreateTransformElement(gfx::Transform(),
kAnimationScaleDownDuration),
// Pause before next iteration.
ui::LayerAnimationElement::CreatePauseElement(
ui::LayerAnimationElement::AnimatableProperty::TRANSFORM,
kAnimationPauseDuration),
// Animation parameters.
{.is_cyclic = true}));
}
}
} // namespace ash
\ No newline at end of file
......@@ -5,6 +5,8 @@
#ifndef ASH_ASSISTANT_UI_MAIN_STAGE_ASSISTANT_PROGRESS_INDICATOR_H_
#define ASH_ASSISTANT_UI_MAIN_STAGE_ASSISTANT_PROGRESS_INDICATOR_H_
#include <memory>
#include "base/macros.h"
#include "ui/views/view.h"
......@@ -15,6 +17,11 @@ class AssistantProgressIndicator : public views::View {
AssistantProgressIndicator();
~AssistantProgressIndicator() override;
// views::View:
void AddedToWidget() override;
void RemovedFromWidget() override;
void VisibilityChanged(views::View* starting_from, bool is_visible) override;
private:
void InitLayout();
......
......@@ -14,7 +14,34 @@ namespace util {
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> a,
std::unique_ptr<ui::LayerAnimationElement> b) {
const LayerAnimationSequenceParams& params) {
return CreateLayerAnimationSequence(std::move(a), nullptr, nullptr, nullptr,
params);
}
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> a,
std::unique_ptr<ui::LayerAnimationElement> b,
const LayerAnimationSequenceParams& params) {
return CreateLayerAnimationSequence(std::move(a), std::move(b), nullptr,
nullptr, params);
}
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> a,
std::unique_ptr<ui::LayerAnimationElement> b,
std::unique_ptr<ui::LayerAnimationElement> c,
const LayerAnimationSequenceParams& params) {
return CreateLayerAnimationSequence(std::move(a), std::move(b), std::move(c),
nullptr, params);
}
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> a,
std::unique_ptr<ui::LayerAnimationElement> b,
std::unique_ptr<ui::LayerAnimationElement> c,
std::unique_ptr<ui::LayerAnimationElement> d,
const LayerAnimationSequenceParams& params) {
ui::LayerAnimationSequence* layer_animation_sequence =
new ui::LayerAnimationSequence();
......@@ -23,24 +50,13 @@ ui::LayerAnimationSequence* CreateLayerAnimationSequence(
if (b)
layer_animation_sequence->AddElement(std::move(b));
return layer_animation_sequence;
}
ui::LayerAnimationSequence* CreateLayerAnimationSequenceWithDelay(
std::unique_ptr<ui::LayerAnimationElement> layer_animation_element,
const base::TimeDelta& delay) {
DCHECK(delay.InMilliseconds() >= 0);
ui::LayerAnimationSequence* layer_animation_sequence =
new ui::LayerAnimationSequence();
if (c)
layer_animation_sequence->AddElement(std::move(c));
if (!delay.is_zero()) {
layer_animation_sequence->AddElement(
ui::LayerAnimationElement::CreatePauseElement(
layer_animation_element->properties(), delay));
}
if (d)
layer_animation_sequence->AddElement(std::move(d));
layer_animation_sequence->AddElement(std::move(layer_animation_element));
layer_animation_sequence->set_is_cyclic(params.is_cyclic);
return layer_animation_sequence;
}
......
......@@ -22,19 +22,45 @@ namespace ash {
namespace assistant {
namespace util {
// Parameters for a LayerAnimationSequence.
struct LayerAnimationSequenceParams {
// True if the animation sequence should loop endlessly, false otherwise.
bool is_cyclic = false;
};
// Creates a LayerAnimationSequence containing the specified
// LayerAnimationElements with the given |params|. The method caller assumes
// ownership of the returned pointer.
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> a,
const LayerAnimationSequenceParams& params = {});
// Creates a LayerAnimationSequence containing the specified
// LayerAnimationElements. The method caller assumes ownership of the
// returned pointer.
// LayerAnimationElements with the given |params|. The method caller assumes
// ownership of the returned pointer.
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> a,
std::unique_ptr<ui::LayerAnimationElement> b = nullptr);
std::unique_ptr<ui::LayerAnimationElement> b,
const LayerAnimationSequenceParams& params = {});
// Creates a LayerAnimationSequence containing the specified
// |layer_animation_element| to be started after the given |delay|. The method
// caller assumes ownership of the returned pointer.
ui::LayerAnimationSequence* CreateLayerAnimationSequenceWithDelay(
std::unique_ptr<ui::LayerAnimationElement> layer_animation_element,
const base::TimeDelta& delay);
// LayerAnimationElements with the given |params|. The method caller assumes
// ownership of the returned pointer.
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> a,
std::unique_ptr<ui::LayerAnimationElement> b,
std::unique_ptr<ui::LayerAnimationElement> c,
const LayerAnimationSequenceParams& params = {});
// Creates a LayerAnimationSequence containing the specified
// LayerAnimationElements with the given |params|. The method caller assumes
// ownership of the returned pointer.
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> a,
std::unique_ptr<ui::LayerAnimationElement> b,
std::unique_ptr<ui::LayerAnimationElement> c,
std::unique_ptr<ui::LayerAnimationElement> d,
const LayerAnimationSequenceParams& params = {});
// Creates a LayerAnimationElement to animate opacity with the given parameters.
std::unique_ptr<ui::LayerAnimationElement> CreateOpacityElement(
......
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