| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/system/phonehub/phone_hub_app_loading_icon.h" |
| |
| #include "ash/style/ash_color_provider.h" |
| #include "ui/base/metadata/metadata_impl_macros.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/image/canvas_image_source.h" |
| #include "ui/views/animation/animation_builder.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Constants for loading animation |
| constexpr float kAnimationOpacityHigh = 1.0f; |
| constexpr float kAnimationOpacityLow = 0.5f; |
| constexpr int kAnimationFadeDownDurationInMs = 500; |
| constexpr int kAnimationFadeUpDurationInMs = 500; |
| |
| class LoadingCircle : public gfx::CanvasImageSource { |
| public: |
| explicit LoadingCircle(int size) |
| : CanvasImageSource(AppIcon::GetRecommendedImageSize(size)) {} |
| |
| LoadingCircle(const LoadingCircle&) = delete; |
| LoadingCircle& operator=(const LoadingCircle&) = delete; |
| |
| void Draw(gfx::Canvas* canvas) override { |
| float radius = size().width() / 2.0f; |
| cc::PaintFlags flags; |
| flags.setStyle(cc::PaintFlags::kFill_Style); |
| flags.setAntiAlias(true); |
| flags.setColor(AshColorProvider::Get()->GetControlsLayerColor( |
| AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive)); |
| canvas->DrawCircle(gfx::PointF(radius, radius), radius, flags); |
| } |
| }; |
| |
| } // namespace |
| |
| AppLoadingIcon::AppLoadingIcon(int size) |
| : AppIcon(gfx::Image( |
| gfx::CanvasImageSource::MakeImageSkia<LoadingCircle>(size)), |
| size) { |
| SetPaintToLayer(); |
| layer()->SetFillsBoundsOpaquely(false); |
| layer()->SetFillsBoundsCompletely(false); |
| } |
| |
| AppLoadingIcon::~AppLoadingIcon() = default; |
| |
| void AppLoadingIcon::StartLoadingAnimation( |
| std::optional<base::TimeDelta> initial_delay) { |
| if (initial_delay) { |
| animation_initial_delay_timer_.Start( |
| FROM_HERE, *initial_delay, |
| base::BindOnce(&AppLoadingIcon::StartLoadingAnimation, |
| base::Unretained(this), |
| /*initial_delay=*/std::nullopt)); |
| return; |
| } |
| |
| views::AnimationBuilder builder; |
| animation_abort_handle_ = builder.GetAbortHandle(); |
| builder.Repeatedly() |
| .SetDuration(base::Milliseconds(kAnimationFadeDownDurationInMs)) |
| .SetOpacity(this, kAnimationOpacityLow, gfx::Tween::ACCEL_30_DECEL_20_85) |
| .Then() |
| .SetDuration(base::Milliseconds(kAnimationFadeUpDurationInMs)) |
| .SetOpacity(this, kAnimationOpacityHigh, gfx::Tween::LINEAR); |
| } |
| |
| void AppLoadingIcon::StopLoadingAnimation() { |
| animation_abort_handle_.reset(); |
| animation_initial_delay_timer_.Stop(); |
| } |
| |
| BEGIN_METADATA(AppLoadingIcon) |
| END_METADATA |
| |
| } // namespace ash |