Skip to content

Commit

Permalink
Feature Tile View
Browse files Browse the repository at this point in the history
Implement the view of the primary button to be used in Quick Settings to
toggle and access features and their settings. Has a Primary and Compact
version. Implemented functional buttons for Accessibility and Screen
Capture in its compact version, along with other placeholder tiles.

Screenshot: https://screenshot.googleplex.com/3RMGPYZNZNhLYJD.png

Bug: b:251724644
Change-Id: I61490a504c2c17d829c834d65189cdda3dbd2844
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3964650
Reviewed-by: Alex Newcomer <newcomer@chromium.org>
Commit-Queue: Kevin Radtke <kradtke@chromium.org>
Reviewed-by: James Cook <jamescook@chromium.org>
Reviewed-by: Jiaming Cheng <jiamingc@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1073436}
  • Loading branch information
Kevin Radtke authored and Chromium LUCI CQ committed Nov 18, 2022
1 parent 1021f2a commit 148adb5
Show file tree
Hide file tree
Showing 17 changed files with 847 additions and 101 deletions.
3 changes: 3 additions & 0 deletions ash/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1835,6 +1835,8 @@ component("ash") {
"system/unified/feature_pod_controller_base.h",
"system/unified/feature_pods_container_view.cc",
"system/unified/feature_pods_container_view.h",
"system/unified/feature_tile.cc",
"system/unified/feature_tile.h",
"system/unified/feature_tiles_container_view.cc",
"system/unified/feature_tiles_container_view.h",
"system/unified/ime_mode_view.cc",
Expand Down Expand Up @@ -3091,6 +3093,7 @@ test("ash_unittests") {
"system/unified/camera_mic_tray_item_view_unittest.cc",
"system/unified/date_tray_unittest.cc",
"system/unified/feature_pods_container_view_unittest.cc",
"system/unified/feature_tile_unittest.cc",
"system/unified/feature_tiles_container_view_unittest.cc",
"system/unified/notification_counter_view_unittest.cc",
"system/unified/notification_icons_controller_unittest.cc",
Expand Down
14 changes: 14 additions & 0 deletions ash/capture_mode/capture_mode_feature_pod_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/unified/feature_pod_button.h"
#include "ash/system/unified/feature_pod_controller_base.h"
#include "ash/system/unified/feature_tile.h"
#include "ash/system/unified/quick_settings_metrics_util.h"
#include "ash/system/unified/unified_system_tray_controller.h"
#include "ui/base/l10n/l10n_util.h"
Expand Down Expand Up @@ -45,6 +46,19 @@ FeaturePodButton* CaptureModeFeaturePodController::CreateButton() {
return button_;
}

std::unique_ptr<FeatureTile> CaptureModeFeaturePodController::CreateTile() {
DCHECK(features::IsQsRevampEnabled());
auto feature_tile = std::make_unique<FeatureTile>(
/*controller=*/this, /*is_togglable=*/false,
FeatureTile::TileType::kCompact);
feature_tile->SetVectorIcon(kCaptureModeIcon);
const auto label_text =
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAPTURE_MODE_BUTTON_LABEL);
feature_tile->SetLabel(label_text);
feature_tile->SetTooltipText(label_text);
return feature_tile;
}

QsFeatureCatalogName CaptureModeFeaturePodController::GetCatalogName() {
return QsFeatureCatalogName::kCaptureMode;
}
Expand Down
6 changes: 5 additions & 1 deletion ash/capture_mode/capture_mode_feature_pod_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
#ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_FEATURE_POD_CONTROLLER_H_
#define ASH_CAPTURE_MODE_CAPTURE_MODE_FEATURE_POD_CONTROLLER_H_

#include <memory>

#include "ash/constants/quick_settings_catalogs.h"
#include "ash/system/unified/feature_pod_controller_base.h"

namespace ash {

class FeatureTile;
class UnifiedSystemTrayController;

// Controller of a feature pod button that toggles night light mode.
// Controller of a feature pod button that launches screen capture.
class CaptureModeFeaturePodController : public FeaturePodControllerBase {
public:
explicit CaptureModeFeaturePodController(
Expand All @@ -25,6 +28,7 @@ class CaptureModeFeaturePodController : public FeaturePodControllerBase {

// FeaturePodControllerBase:
FeaturePodButton* CreateButton() override;
std::unique_ptr<FeatureTile> CreateTile() override;
QsFeatureCatalogName GetCatalogName() override;
void OnIconPressed() override;

Expand Down
16 changes: 16 additions & 0 deletions ash/system/accessibility/accessibility_feature_pod_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/unified/feature_pod_button.h"
#include "ash/system/unified/feature_tile.h"
#include "ash/system/unified/quick_settings_metrics_util.h"
#include "ash/system/unified/unified_system_tray_controller.h"
#include "ui/base/l10n/l10n_util.h"
Expand Down Expand Up @@ -48,6 +49,21 @@ FeaturePodButton* AccessibilityFeaturePodController::CreateButton() {
return button;
}

std::unique_ptr<FeatureTile> AccessibilityFeaturePodController::CreateTile() {
DCHECK(features::IsQsRevampEnabled());
auto feature_tile = std::make_unique<FeatureTile>(/*controller=*/this,
/*is_togglable=*/false);
feature_tile->SetVectorIcon(kUnifiedMenuAccessibilityIcon);
feature_tile->SetLabel(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY));
feature_tile->SetSubLabelVisibility(false);
const std::u16string tooltip_text =
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TOOLTIP);
feature_tile->SetTooltipText(tooltip_text);
feature_tile->SetDrillInButtonTooltipText(tooltip_text);
return feature_tile;
}

QsFeatureCatalogName AccessibilityFeaturePodController::GetCatalogName() {
return QsFeatureCatalogName::kAccessibility;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
#ifndef ASH_SYSTEM_ACCESSIBILITY_ACCESSIBILITY_FEATURE_POD_CONTROLLER_H_
#define ASH_SYSTEM_ACCESSIBILITY_ACCESSIBILITY_FEATURE_POD_CONTROLLER_H_

#include <memory>

#include "ash/ash_export.h"
#include "ash/constants/quick_settings_catalogs.h"
#include "ash/system/unified/feature_pod_controller_base.h"

namespace ash {

class FeatureTile;
class UnifiedSystemTrayController;

// Controller of accessibility feature pod button.
Expand All @@ -29,6 +32,7 @@ class ASH_EXPORT AccessibilityFeaturePodController

// FeaturePodControllerBase:
FeaturePodButton* CreateButton() override;
std::unique_ptr<FeatureTile> CreateTile() override;
QsFeatureCatalogName GetCatalogName() override;
void OnIconPressed() override;

Expand Down
8 changes: 8 additions & 0 deletions ash/system/unified/feature_pod_controller_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@

#include "ash/system/unified/feature_pod_controller_base.h"

#include "ash/system/unified/feature_pod_button.h"
#include "ash/system/unified/feature_tile.h"
#include "ash/system/unified/quick_settings_metrics_util.h"

namespace ash {

// TODO(b/252871301): Remove after implementing every FeatureTile and making
// this function pure virtual.
std::unique_ptr<FeatureTile> FeaturePodControllerBase::CreateTile() {
return std::make_unique<FeatureTile>();
}

void FeaturePodControllerBase::OnLabelPressed() {
return OnIconPressed();
}
Expand Down
8 changes: 8 additions & 0 deletions ash/system/unified/feature_pod_controller_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
#ifndef ASH_SYSTEM_UNIFIED_FEATURE_POD_CONTROLLER_BASE_H_
#define ASH_SYSTEM_UNIFIED_FEATURE_POD_CONTROLLER_BASE_H_

#include <memory>

#include "ash/ash_export.h"
#include "ash/constants/quick_settings_catalogs.h"

namespace ash {

class FeaturePodButton;
class FeatureTile;

// Base class for controllers of feature pod buttons.
// To add a new feature pod button, implement this class, and add to the list in
Expand All @@ -25,6 +28,11 @@ class ASH_EXPORT FeaturePodControllerBase {
// this).
virtual FeaturePodButton* CreateButton() = 0;

// Creates FeatureTile view.
// TODO(b/252871301): Make this function pure virtual after implementing
// every feature tile.
virtual std::unique_ptr<FeatureTile> CreateTile();

// Returns the feature catalog name which is used for UMA tracking. Please
// remember to call the corresponding tracking method (`TrackToggleUMA` and
// `TrackDiveInUMA`) in the `OnIconPressed` and `OnLabelPressed`
Expand Down
219 changes: 219 additions & 0 deletions ash/system/unified/feature_tile.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
// Copyright 2022 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/unified/feature_tile.h"

#include "ash/constants/ash_features.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_id.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/unified/feature_pod_controller_base.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/background.h"
#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/flex_layout_view.h"

using views::FlexLayout;
using views::FlexLayoutView;

namespace ash {

namespace {

// Tile constants
constexpr int kIconSize = 20;
constexpr int kButtonRadius = 16;

// Primary tile constants
constexpr int kPrimarySubtitleLineHeight = 18;
constexpr gfx::Size kDefaultSize(200, kFeatureTileHeight);
constexpr gfx::Size kIconContainerSize(48, kFeatureTileHeight);
constexpr gfx::Size kTitlesContainerSize(112, kFeatureTileHeight);
constexpr gfx::Size kDrillContainerSize(40, kFeatureTileHeight);

// Compact tile constants
constexpr int kCompactWidth = 96;
constexpr int kCompactTitleLineHeight = 14;
constexpr gfx::Size kCompactSize(kCompactWidth, kFeatureTileHeight);
constexpr gfx::Size kCompactIconContainerSize(kCompactWidth, 30);
constexpr gfx::Size kCompactTitleContainerSize(kCompactWidth, 34);
constexpr gfx::Size kCompactTitleLabelSize(kCompactWidth - 32,
kCompactTitleLineHeight * 2);
constexpr gfx::Insets kCompactIconContainerInteriorMargin(
gfx::Insets::TLBR(0, 0, 4, 0));

} // namespace

// Constructor for prototype tile without a controller.
// TODO(b/252871301): Remove when applying controllers to each feature tile.
FeatureTile::FeatureTile(TileType type)
: Button(PressedCallback()), type_(type) {
UpdateColors();
views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(),
kButtonRadius);
SetAccessibleName(u"Placeholder Tile");

CreateChildViews();
if (type == TileType::kPrimary) {
label_->SetText(u"Title");
sub_label_->SetText(u"Subtitle");
} else {
label_->SetText(u"Two line\ntitle");
}
SetVectorIcon(vector_icons::kDogfoodIcon);
}

FeatureTile::FeatureTile(FeaturePodControllerBase* controller,
bool is_togglable,
TileType type)
: Button(base::BindRepeating(&FeaturePodControllerBase::OnIconPressed,
base::Unretained(controller))),
is_togglable_(is_togglable),
type_(type) {
DCHECK(controller);
UpdateColors();
views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(),
kButtonRadius);
CreateChildViews();

if (type == TileType::kCompact)
return;

drill_container_ = AddChildView(std::make_unique<views::LabelButton>(
base::BindRepeating(&FeaturePodControllerBase::OnLabelPressed,
base::Unretained(controller))));
drill_container_->SetLayoutManager(std::make_unique<FlexLayout>())
->SetMainAxisAlignment(views::LayoutAlignment::kCenter)
.SetCrossAxisAlignment(views::LayoutAlignment::kCenter);
drill_container_->SetPreferredSize(kDrillContainerSize);
drill_container_->SetFocusBehavior(FocusBehavior::NEVER);
// TODO(b/259280052): Make the `drill_in_button_` an ImageView so we do not
// receive a callback since it is already applied to `drill_container_`.
// Apply focus to the view only when the button type is "Toggle + Drill-in".
drill_in_button_ =
drill_container_->AddChildView(std::make_unique<IconButton>(
base::BindRepeating(&FeaturePodControllerBase::OnLabelPressed,
base::Unretained(controller)),
IconButton::Type::kXSmall, &kQuickSettingsRightArrowIcon,
/*togglable=*/false,
/*has_border=*/false));
}

void FeatureTile::CreateChildViews() {
const bool is_compact = type_ == TileType::kCompact;

auto* layout_manager = SetLayoutManager(std::make_unique<FlexLayout>());
layout_manager->SetOrientation(is_compact
? views::LayoutOrientation::kVertical
: views::LayoutOrientation::kHorizontal);
// Since the focus ring doesn't set a LayoutManager it won't get drawn unless
// excluded by the tile's LayoutManager.
// TODO(crbug/1385946): Modify LayoutManagerBase and FocusRing to always
// exclude focus ring from the layout.
layout_manager->SetChildViewIgnoredByLayout(views::FocusRing::Get(this),
true);

SetPreferredSize(is_compact ? kCompactSize : kDefaultSize);

auto* icon_container = AddChildView(std::make_unique<FlexLayoutView>());
icon_container->SetMainAxisAlignment(views::LayoutAlignment::kCenter);
icon_container->SetCrossAxisAlignment(is_compact
? views::LayoutAlignment::kEnd
: views::LayoutAlignment::kCenter);
icon_container->SetPreferredSize(is_compact ? kCompactIconContainerSize
: kIconContainerSize);
if (is_compact)
icon_container->SetInteriorMargin(kCompactIconContainerInteriorMargin);
icon_ = icon_container->AddChildView(std::make_unique<views::ImageView>());

auto* title_container = AddChildView(std::make_unique<FlexLayoutView>());
title_container->SetOrientation(is_compact
? views::LayoutOrientation::kHorizontal
: views::LayoutOrientation::kVertical);
title_container->SetMainAxisAlignment(views::LayoutAlignment::kCenter);
title_container->SetCrossAxisAlignment(views::LayoutAlignment::kStart);
title_container->SetPreferredSize(is_compact ? kCompactTitleContainerSize
: kTitlesContainerSize);

label_ = AddChildView(std::make_unique<views::Label>());
title_container->AddChildView(label_);

if (is_compact) {
label_->SetPreferredSize(kCompactTitleLabelSize);
// TODO(b/259459827): verify multi-line text is rendering correctly, not
// clipping and center aligned.
label_->SetMultiLine(true);
label_->SetLineHeight(kCompactTitleLineHeight);
// TODO(b/252873172): update FontList.
label_->SetFontList(views::Label::GetDefaultFontList().Derive(
-1, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL));
} else {
sub_label_ = AddChildView(std::make_unique<views::Label>());
// TODO(b/252873172): update FontList.
sub_label_->SetFontList(views::Label::GetDefaultFontList().Derive(
-1, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL));
sub_label_->SetLineHeight(kPrimarySubtitleLineHeight);
title_container->AddChildView(sub_label_);
}
}

void FeatureTile::UpdateColors() {
ui::ColorId background_color_id =
toggled_ ? cros_tokens::kCrosSysSystemPrimaryContainer
: cros_tokens::kCrosSysSystemOnBase;

SetBackground(views::CreateThemedRoundedRectBackground(background_color_id,
kButtonRadius));
}

void FeatureTile::SetToggled(bool toggled) {
if (!is_togglable_ || toggled_ == toggled)
return;

toggled_ = toggled;

UpdateColors();
}

bool FeatureTile::IsToggled() const {
return toggled_;
}

void FeatureTile::SetVectorIcon(const gfx::VectorIcon& icon) {
icon_->SetImage(ui::ImageModel::FromVectorIcon(
icon, cros_tokens::kCrosSysOnSurface, kIconSize));
}

void FeatureTile::SetLabel(const std::u16string& label) {
label_->SetText(label);
}

void FeatureTile::SetSubLabel(const std::u16string& sub_label) {
sub_label_->SetText(sub_label);
}

void FeatureTile::SetSubLabelVisibility(bool visible) {
sub_label_->SetVisible(visible);
}

void FeatureTile::SetDrillInButtonTooltipText(const std::u16string& text) {
// Only primary tiles have a drill-in button.
DCHECK(drill_in_button_);
drill_container_->SetTooltipText(text);
drill_in_button_->SetTooltipText(text);
}

void FeatureTile::SetDrillInButtonVisibility(bool visible) {
DCHECK(drill_in_button_);
drill_container_->SetVisible(visible);
}

BEGIN_METADATA(FeatureTile, views::Button)
END_METADATA

} // namespace ash

0 comments on commit 148adb5

Please sign in to comment.