chromium/ash/system/brightness/display_detailed_view.cc

// 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/brightness/display_detailed_view.h"

#include <memory>

#include "ash/public/cpp/ash_view_ids.h"
#include "ash/public/cpp/system_tray_client.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/brightness/unified_brightness_slider_controller.h"
#include "ash/system/dark_mode/dark_mode_feature_pod_controller.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/system/night_light/night_light_feature_pod_controller.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/tray/detailed_view_delegate.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_popup_utils.h"
#include "ash/system/unified/feature_tile.h"
#include "ash/system/unified/unified_system_tray.h"
#include "ash/system/unified/unified_system_tray_controller.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/border.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/flex_layout_types.h"
#include "ui/views/layout/flex_layout_view.h"
#include "ui/views/view.h"
#include "ui/views/view_class_properties.h"

namespace ash {

namespace {

constexpr auto kScrollViewMargin = gfx::Insets::TLBR(0, 12, 16, 12);
constexpr auto kSliderBorder = gfx::Insets(4);
constexpr auto kSliderPadding = gfx::Insets::TLBR(0, 0, 4, 0);
constexpr auto kTileContainerMargins = gfx::Insets::TLBR(4, 4, 12, 4);

}  // namespace

DisplayDetailedView::DisplayDetailedView(
    DetailedViewDelegate* delegate,
    UnifiedSystemTrayController* tray_controller)
    : TrayDetailedView(delegate),
      unified_system_tray_controller_(tray_controller) {
  CreateScrollableList();
  CreateTitleRow(IDS_ASH_STATUS_TRAY_DISPLAY);
  // Sets the margin for `ScrollView` to leave some space for the focus ring.
  scroller()->SetProperty(views::kMarginsKey, kScrollViewMargin);

  auto night_light_controller =
      std::make_unique<NightLightFeaturePodController>(
          unified_system_tray_controller_);
  auto dark_mode_controller = std::make_unique<DarkModeFeaturePodController>(
      unified_system_tray_controller_);

  auto tile_container =
      views::Builder<views::FlexLayoutView>()
          .SetID(VIEW_ID_QS_DISPLAY_TILE_CONTAINER)
          .SetPreferredSize(
              gfx::Size(GetPreferredSize().width(),
                        kFeatureTileHeight + kTileContainerMargins.height()))
          .CustomConfigure(base::BindOnce([](views::FlexLayoutView* layout) {
            layout->SetDefault(views::kMarginsKey, kTileContainerMargins);
          }))
          .Build();

  tile_container->AddChildView(night_light_controller->CreateTile());
  tile_container->AddChildView(dark_mode_controller->CreateTile());

  bool has_visible_tiles = false;

  // Set `PreferredSize` to (1,1) so the `FlexLayout` allocates the same width
  // for the child tiles based on their equal weights.
  for (auto tile : tile_container->children()) {
    tile->SetPreferredSize(gfx::Size(1, 1));
    if (tile->GetVisible()) {
      has_visible_tiles = true;
    }
  }

  if (!has_visible_tiles) {
    tile_container->SetVisible(false);
  }

  // Transfer ownership so the controllers won't die while the page is open.
  feature_tile_controllers_.push_back(std::move(night_light_controller));
  feature_tile_controllers_.push_back(std::move(dark_mode_controller));

  scroll_content()->AddChildView(std::move(tile_container));

  brightness_slider_controller_ =
      std::make_unique<UnifiedBrightnessSliderController>(
          Shell::GetPrimaryRootWindowController()
              ->GetStatusAreaWidget()
              ->unified_system_tray()
              ->model(),
          views::Button::PressedCallback());
  auto unified_brightness_view =
      brightness_slider_controller_->CreateBrightnessSlider();
  // Sets the ID for testing.
  unified_brightness_view->SetID(VIEW_ID_QS_DISPLAY_BRIGHTNESS_SLIDER);
  unified_brightness_view->slider()->SetBorder(
      views::CreateEmptyBorder(kSliderBorder));
  auto* slider_layout = unified_brightness_view->SetLayoutManager(
      std::make_unique<views::BoxLayout>(
          views::BoxLayout::Orientation::kHorizontal, kSliderPadding,
          /*between_child_spacing=*/0));
  slider_layout->SetFlexForView(unified_brightness_view->slider(),
                                /*flex=*/1);
  scroll_content()->AddChildView(std::move(unified_brightness_view));
  // Sets the ID for testing.
  scroll_content()->SetID(VIEW_ID_QS_DISPLAY_SCROLL_CONTENT);
}

DisplayDetailedView::~DisplayDetailedView() = default;

views::View* DisplayDetailedView::GetScrollContentForTest() {
  // Provides access to the protected scroll_content() in the base class.
  return scroll_content();
}

void DisplayDetailedView::CreateExtraTitleRowButtons() {
  CHECK(!settings_button_);

  tri_view()->SetContainerVisible(TriView::Container::END, /*visible=*/true);

  settings_button_ = CreateSettingsButton(
      base::BindRepeating(&DisplayDetailedView::OnSettingsClicked,
                          weak_factory_.GetWeakPtr()),
      IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_SETTINGS_TOOLTIP);
  settings_button_->SetState(TrayPopupUtils::CanOpenWebUISettings()
                                 ? views::Button::STATE_NORMAL
                                 : views::Button::STATE_DISABLED);
  tri_view()->AddView(TriView::Container::END, settings_button_);
}

void DisplayDetailedView::OnSettingsClicked() {
  if (TrayPopupUtils::CanOpenWebUISettings()) {
    CloseBubble();
    Shell::Get()->system_tray_model()->client()->ShowDisplaySettings();
  }
}

BEGIN_METADATA(DisplayDetailedView)
END_METADATA

}  // namespace ash