chromium/ash/ambient/ui/ambient_shield_view.cc

// Copyright 2021 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/ambient/ui/ambient_shield_view.h"

#include <array>

#include "ash/ambient/ui/ambient_view_ids.h"
#include "ash/style/dark_light_mode_controller_impl.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/compositor/layer_delegate.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/skia_paint_util.h"
#include "ui/views/background.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/flex_layout_types.h"
#include "ui/views/view.h"
#include "ui/views/view_class_properties.h"

namespace ash {

namespace {

// Gray gradient from 5% to 50%.
constexpr std::array<SkColor, 2> kDarkModeColors{
    SkColorSetA(gfx::kGoogleGrey900, 12),
    SkColorSetA(gfx::kGoogleGrey900, 128)};

// Gray gradient from 0% to 20%.
constexpr std::array<SkColor, 2> kLightModeColors{
    SkColorSetA(gfx::kGoogleGrey900, 0), SkColorSetA(gfx::kGoogleGrey900, 51)};

class GradientBackground : public views::Background {
 public:
  enum class Orientation {
    kHorizontal,
    kVertical,
    kDiagonalAscending,
    kDiagonalDescending
  };

  GradientBackground(Orientation orientation,
                     SkColor start_color,
                     SkColor end_color)
      : orientation_(orientation),
        start_color_(start_color),
        end_color_(end_color) {}

  GradientBackground(const GradientBackground&) = delete;
  GradientBackground& operator=(const GradientBackground&) = delete;

  ~GradientBackground() override = default;

  // views::Background:
  void Paint(gfx::Canvas* canvas, views::View* view) const override {
    const auto& bounds = view->GetContentsBounds();
    const auto& points = GetPoints(bounds);

    cc::PaintFlags flags;
    flags.setBlendMode(SkBlendMode::kSrcOver);
    flags.setShader(gfx::CreateGradientShader(points.front(), points.back(),
                                              start_color_, end_color_));

    canvas->DrawRect(bounds, flags);
  }

 private:
  const std::array<gfx::Point, 2> GetPoints(const gfx::Rect& bounds) const {
    switch (orientation_) {
      case Orientation::kHorizontal:
        return {bounds.left_center(), bounds.right_center()};
      case Orientation::kVertical:
        return {bounds.top_center(), bounds.bottom_center()};
      case Orientation::kDiagonalAscending:
        return {bounds.bottom_left(), bounds.top_right()};
      case Orientation::kDiagonalDescending:
        return {bounds.origin(), bounds.bottom_right()};
    }
  }

  const Orientation orientation_;
  const SkColor start_color_;
  const SkColor end_color_;
};

std::unique_ptr<GradientBackground> CreateGradientBackground(
    GradientBackground::Orientation orientation,
    const std::array<SkColor, 2> colors) {
  return std::make_unique<GradientBackground>(orientation, colors.front(),
                                              colors.back());
}

}  // namespace

AmbientShieldView::AmbientShieldView() {
  SetID(AmbientViewID::kAmbientShieldView);
  InitLayout();
}

AmbientShieldView::~AmbientShieldView() = default;

void AmbientShieldView::InitLayout() {
  const views::FlexSpecification kScaleUnbounded(
      views::MinimumFlexSizeRule::kPreferred,
      views::MaximumFlexSizeRule::kUnbounded);

  views::FlexLayout* layout =
      SetLayoutManager(std::make_unique<views::FlexLayout>());
  layout->SetOrientation(views::LayoutOrientation::kVertical);
  layout->SetMainAxisAlignment(views::LayoutAlignment::kCenter);
  layout->SetCrossAxisAlignment(views::LayoutAlignment::kStretch);

  views::View* top = AddChildView(std::make_unique<views::View>());
  views::View* bottom = AddChildView(std::make_unique<views::View>());

  for (auto* view : {top, bottom})
    view->SetProperty(views::kFlexBehaviorKey, kScaleUnbounded);

  // TODO(b/223270660): Listen for dark/light mode changes.
  bool dark_mode = DarkLightModeControllerImpl::Get()->IsDarkModeEnabled();
  const auto& colors = dark_mode ? kDarkModeColors : kLightModeColors;

  top->SetBackground(views::CreateSolidBackground(colors.front()));
  bottom->SetBackground(CreateGradientBackground(
      GradientBackground::Orientation::kVertical, colors));
}

BEGIN_METADATA(AmbientShieldView)
END_METADATA

}  // namespace ash