Commit 0135e496 authored by David Black's avatar David Black Committed by Commit Bot

Implement DialogPlate motion spec (part 2).

This builds off of DialogPlate motion spec part 1:
https://chromium-review.googlesource.com/c/chromium/src/+/1137843

This CL:
- Fixes issue which caused settings to fade in/out. Previously we used
  two settings buttons, now we use a single button which exists outside
  of the layout containers being animated.
- Implements translation phase of the animation.

See bug for spec/demo.

Bug: b:111500701
Change-Id: I269666dafa815018e0cf65df299aa734eaf80b79
Reviewed-on: https://chromium-review.googlesource.com/1139031
Commit-Queue: David Black <dmblack@google.com>
Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#575901}
parent d8235928
......@@ -40,20 +40,9 @@ constexpr base::TimeDelta kAnimationFadeInDuration =
base::TimeDelta::FromMilliseconds(100);
constexpr base::TimeDelta kAnimationFadeOutDuration =
base::TimeDelta::FromMilliseconds(83);
// Helpers ---------------------------------------------------------------------
// Creates a settings button. Caller takes ownership.
views::ImageButton* CreateSettingsButton(DialogPlate* dialog_plate) {
views::ImageButton* settings_button = new views::ImageButton(dialog_plate);
settings_button->set_id(static_cast<int>(DialogPlateButtonId::kSettings));
settings_button->SetImage(
views::Button::ButtonState::STATE_NORMAL,
gfx::CreateVectorIcon(kNotificationSettingsIcon, kIconSizeDip,
gfx::kGoogleGrey600));
settings_button->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
return settings_button;
}
constexpr base::TimeDelta kAnimationTransformInDuration =
base::TimeDelta::FromMilliseconds(333);
constexpr int kAnimationTranslationDip = 30;
} // namespace
......@@ -100,10 +89,37 @@ void DialogPlate::ChildVisibilityChanged(views::View* child) {
void DialogPlate::InitLayout() {
SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
SetLayoutManager(std::make_unique<views::FillLayout>());
InitKeyboardLayoutContainer();
InitVoiceLayoutContainer();
views::BoxLayout* layout_manager =
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal,
gfx::Insets(0, 0, 0, kPaddingDip)));
layout_manager->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
// Input modality layout container.
views::View* input_modality_layout_container = new views::View();
input_modality_layout_container->SetLayoutManager(
std::make_unique<views::FillLayout>());
input_modality_layout_container->SetPaintToLayer();
input_modality_layout_container->layer()->SetMasksToBounds(true);
InitKeyboardLayoutContainer(input_modality_layout_container);
InitVoiceLayoutContainer(input_modality_layout_container);
layout_manager->SetFlexForView(input_modality_layout_container, 1);
AddChildView(input_modality_layout_container);
// Settings.
views::ImageButton* settings_button = new views::ImageButton(this);
settings_button->set_id(static_cast<int>(DialogPlateButtonId::kSettings));
settings_button->SetImage(
views::Button::ButtonState::STATE_NORMAL,
gfx::CreateVectorIcon(kNotificationSettingsIcon, kIconSizeDip,
gfx::kGoogleGrey600));
settings_button->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
AddChildView(settings_button);
// Artificially trigger event to set initial state.
OnInputModalityChanged(assistant_controller_->interaction_controller()
......@@ -111,10 +127,12 @@ void DialogPlate::InitLayout() {
->input_modality());
}
void DialogPlate::InitKeyboardLayoutContainer() {
void DialogPlate::InitKeyboardLayoutContainer(
views::View* input_modality_layout_container) {
keyboard_layout_container_ = new views::View();
keyboard_layout_container_->SetPaintToLayer();
keyboard_layout_container_->layer()->SetFillsBoundsOpaquely(false);
keyboard_layout_container_->layer()->SetOpacity(0.f);
views::BoxLayout* layout_manager =
keyboard_layout_container_->SetLayoutManager(
......@@ -144,48 +162,42 @@ void DialogPlate::InitKeyboardLayoutContainer() {
layout_manager->SetFlexForView(textfield_, 1);
// Voice input toggle.
voice_input_toggle_ = new views::ImageButton(this);
voice_input_toggle_->set_id(
views::ImageButton* voice_input_toggle = new views::ImageButton(this);
voice_input_toggle->set_id(
static_cast<int>(DialogPlateButtonId::kVoiceInputToggle));
voice_input_toggle_->SetImage(views::Button::ButtonState::STATE_NORMAL,
gfx::CreateVectorIcon(kMicIcon, kIconSizeDip));
voice_input_toggle_->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
keyboard_layout_container_->AddChildView(voice_input_toggle_);
// Spacer.
views::View* spacer = new views::View();
spacer->SetPreferredSize(gfx::Size(kSpacingDip, kSpacingDip));
keyboard_layout_container_->AddChildView(spacer);
// Settings.
keyboard_layout_container_->AddChildView(CreateSettingsButton(this));
voice_input_toggle->SetImage(views::Button::ButtonState::STATE_NORMAL,
gfx::CreateVectorIcon(kMicIcon, kIconSizeDip));
voice_input_toggle->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
keyboard_layout_container_->AddChildView(voice_input_toggle);
AddChildView(keyboard_layout_container_);
input_modality_layout_container->AddChildView(keyboard_layout_container_);
}
void DialogPlate::InitVoiceLayoutContainer() {
void DialogPlate::InitVoiceLayoutContainer(
views::View* input_modality_layout_container) {
voice_layout_container_ = new views::View();
voice_layout_container_->SetPaintToLayer();
voice_layout_container_->layer()->SetFillsBoundsOpaquely(false);
voice_layout_container_->layer()->SetOpacity(0.f);
views::BoxLayout* layout_manager = voice_layout_container_->SetLayoutManager(
std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal,
gfx::Insets(0, kPaddingDip)));
gfx::Insets(0, kPaddingDip, 0, 0)));
layout_manager->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
// Keyboard input toggle.
keyboard_input_toggle_ = new views::ImageButton(this);
keyboard_input_toggle_->set_id(
views::ImageButton* keyboard_input_toggle = new views::ImageButton(this);
keyboard_input_toggle->set_id(
static_cast<int>(DialogPlateButtonId::kKeyboardInputToggle));
keyboard_input_toggle_->SetImage(
keyboard_input_toggle->SetImage(
views::Button::ButtonState::STATE_NORMAL,
gfx::CreateVectorIcon(kKeyboardIcon, kIconSizeDip, gfx::kGoogleGrey600));
keyboard_input_toggle_->SetPreferredSize(
keyboard_input_toggle->SetPreferredSize(
gfx::Size(kIconSizeDip, kIconSizeDip));
voice_layout_container_->AddChildView(keyboard_input_toggle_);
voice_layout_container_->AddChildView(keyboard_input_toggle);
// Spacer.
views::View* spacer = new views::View();
......@@ -203,10 +215,7 @@ void DialogPlate::InitVoiceLayoutContainer() {
layout_manager->SetFlexForView(spacer, 1);
// Settings.
voice_layout_container_->AddChildView(CreateSettingsButton(this));
AddChildView(voice_layout_container_);
input_modality_layout_container->AddChildView(voice_layout_container_);
}
void DialogPlate::OnActionPressed() {
......@@ -226,37 +235,67 @@ void DialogPlate::OnButtonPressed(DialogPlateButtonId id) {
void DialogPlate::OnInputModalityChanged(InputModality input_modality) {
switch (input_modality) {
case InputModality::kKeyboard:
case InputModality::kKeyboard: {
// Animate voice layout container opacity to 0%.
voice_layout_container_->layer()->GetAnimator()->StartAnimation(
assistant::util::CreateLayerAnimationSequence(
ui::LayerAnimationElement::CreateOpacityElement(
0.f, kAnimationFadeOutDuration)));
// Animate keyboard layout container opacity to 100% with delay.
keyboard_layout_container_->layer()->GetAnimator()->StartAnimation(
assistant::util::CreateLayerAnimationSequenceWithDelay(
ui::LayerAnimationElement::CreateOpacityElement(
1.f, kAnimationFadeInDuration),
/*delay=*/kAnimationFadeOutDuration));
assistant::util::CreateOpacityElement(
0.f, kAnimationFadeOutDuration,
gfx::Tween::Type::FAST_OUT_LINEAR_IN)));
// Apply a pre-transformation on the keyboard layout container so that it
// can be animated into place.
gfx::Transform transform;
transform.Translate(-kAnimationTranslationDip, 0);
keyboard_layout_container_->layer()->SetTransform(transform);
// Animate keyboard layout container.
keyboard_layout_container_->layer()->GetAnimator()->StartTogether(
{// Animate transformation.
assistant::util::CreateLayerAnimationSequence(
assistant::util::CreateTransformElement(
gfx::Transform(), kAnimationTransformInDuration,
gfx::Tween::Type::FAST_OUT_SLOW_IN_2)),
// Animate opacity to 100% with delay.
assistant::util::CreateLayerAnimationSequenceWithDelay(
assistant::util::CreateOpacityElement(
1.f, kAnimationFadeInDuration,
gfx::Tween::Type::FAST_OUT_LINEAR_IN),
/*delay=*/kAnimationFadeOutDuration)});
// When switching to keyboard input modality, we focus the textfield.
textfield_->RequestFocus();
break;
case InputModality::kVoice:
}
case InputModality::kVoice: {
// Animate keyboard layout container opacity to 0%.
keyboard_layout_container_->layer()->GetAnimator()->StartAnimation(
assistant::util::CreateLayerAnimationSequence(
ui::LayerAnimationElement::CreateOpacityElement(
0.f, kAnimationFadeOutDuration)));
// Animate voice layout container opacity to 100% with delay;
voice_layout_container_->layer()->GetAnimator()->StartAnimation(
assistant::util::CreateLayerAnimationSequenceWithDelay(
ui::LayerAnimationElement::CreateOpacityElement(
1.f, kAnimationFadeInDuration),
/*delay=*/kAnimationFadeOutDuration));
assistant::util::CreateOpacityElement(
0.f, kAnimationFadeOutDuration,
gfx::Tween::Type::FAST_OUT_LINEAR_IN)));
// Apply a pre-transformation on the voice layout container so that it can
// be animated into place.
gfx::Transform transform;
transform.Translate(kAnimationTranslationDip, 0);
voice_layout_container_->layer()->SetTransform(transform);
// Animate voice layout container.
voice_layout_container_->layer()->GetAnimator()->StartTogether(
{// Animate transformation.
assistant::util::CreateLayerAnimationSequence(
assistant::util::CreateTransformElement(
gfx::Transform(), kAnimationTransformInDuration,
gfx::Tween::Type::FAST_OUT_SLOW_IN_2)),
// Animate opacity to 100% with delay.
assistant::util::CreateLayerAnimationSequenceWithDelay(
assistant::util::CreateOpacityElement(
1.f, kAnimationFadeInDuration,
gfx::Tween::Type::FAST_OUT_LINEAR_IN),
/*delay=*/kAnimationFadeOutDuration)});
break;
}
case InputModality::kStylus:
// No action necessary.
break;
......
......@@ -16,10 +16,6 @@
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/view.h"
namespace views {
class ImageButton;
} // namespace views
namespace ash {
class AssistantController;
......@@ -92,18 +88,17 @@ class DialogPlate : public views::View,
private:
void InitLayout();
void InitKeyboardLayoutContainer();
void InitVoiceLayoutContainer();
void InitKeyboardLayoutContainer(
views::View* input_modality_layout_container);
void InitVoiceLayoutContainer(views::View* input_modality_layout_container);
void OnButtonPressed(DialogPlateButtonId id);
AssistantController* const assistant_controller_; // Owned by Shell.
views::ImageButton* keyboard_input_toggle_; // Owned by view hierarchy.
views::View* keyboard_layout_container_; // Owned by view hierarchy.
views::Textfield* textfield_; // Owned by view hierarchy.
views::ImageButton* voice_input_toggle_; // Owned by view hierarchy.
views::View* voice_layout_container_; // Owned by view hierarchy.
views::Textfield* textfield_; // Owned by view hierarchy.
base::ObserverList<DialogPlateObserver> observers_;
......
......@@ -13,15 +13,22 @@ namespace assistant {
namespace util {
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> layer_animation_element) {
return CreateLayerAnimationSequenceWithDelay(
std::move(layer_animation_element),
/*delay=*/base::TimeDelta());
std::unique_ptr<ui::LayerAnimationElement> a,
std::unique_ptr<ui::LayerAnimationElement> b) {
ui::LayerAnimationSequence* layer_animation_sequence =
new ui::LayerAnimationSequence();
layer_animation_sequence->AddElement(std::move(a));
if (b)
layer_animation_sequence->AddElement(std::move(b));
return layer_animation_sequence;
}
ui::LayerAnimationSequence* CreateLayerAnimationSequenceWithDelay(
std::unique_ptr<ui::LayerAnimationElement> layer_animation_element,
base::TimeDelta delay) {
const base::TimeDelta& delay) {
DCHECK(delay.InMilliseconds() >= 0);
ui::LayerAnimationSequence* layer_animation_sequence =
......@@ -38,6 +45,26 @@ ui::LayerAnimationSequence* CreateLayerAnimationSequenceWithDelay(
return layer_animation_sequence;
}
std::unique_ptr<ui::LayerAnimationElement> CreateOpacityElement(
float opacity,
const base::TimeDelta& duration,
const gfx::Tween::Type& tween) {
std::unique_ptr<ui::LayerAnimationElement> layer_animation_element =
ui::LayerAnimationElement::CreateOpacityElement(opacity, duration);
layer_animation_element->set_tween_type(tween);
return layer_animation_element;
}
std::unique_ptr<ui::LayerAnimationElement> CreateTransformElement(
const gfx::Transform& transform,
const base::TimeDelta& duration,
const gfx::Tween::Type& tween) {
std::unique_ptr<ui::LayerAnimationElement> layer_animation_element =
ui::LayerAnimationElement::CreateTransformElement(transform, duration);
layer_animation_element->set_tween_type(tween);
return layer_animation_element;
}
} // namespace util
} // namespace assistant
} // namespace ash
......@@ -7,6 +7,8 @@
#include <memory>
#include "ui/gfx/animation/tween.h"
namespace base {
class TimeDelta;
} // namespace base
......@@ -21,17 +23,31 @@ namespace assistant {
namespace util {
// Creates a LayerAnimationSequence containing the specified
// |layer_animation_element|. The method caller assumes ownership of the
// LayerAnimationElements. The method caller assumes ownership of the
// returned pointer.
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> layer_animation_element);
std::unique_ptr<ui::LayerAnimationElement> a,
std::unique_ptr<ui::LayerAnimationElement> b = nullptr);
// 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,
base::TimeDelta delay);
const base::TimeDelta& delay);
// Creates a LayerAnimationElement to animate opacity with the given parameters.
std::unique_ptr<ui::LayerAnimationElement> CreateOpacityElement(
float opacity,
const base::TimeDelta& duration,
const gfx::Tween::Type& tween = gfx::Tween::Type::LINEAR);
// Creates a LayerAnimationElement to animate transform with the given
// parameters.
std::unique_ptr<ui::LayerAnimationElement> CreateTransformElement(
const gfx::Transform& transform,
const base::TimeDelta& duration,
const gfx::Tween::Type& tween = gfx::Tween::Type::LINEAR);
} // namespace util
} // namespace assistant
......
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