1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
|
// 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.
#ifndef ASH_SYSTEM_UNIFIED_FEATURE_TILE_H_
#define ASH_SYSTEM_UNIFIED_FEATURE_TILE_H_
#include "ash/ash_export.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/color/color_id.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/button.h"
namespace gfx {
struct VectorIcon;
class Insets;
} // namespace gfx
namespace views {
class FlexLayoutView;
class ImageButton;
class ImageView;
class InkDropContainerView;
class Label;
} // namespace views
namespace ash {
// The main button used in FeatureTilesContainerView, which acts as an entry
// point for features in QuickSettingsView.
//
// Note: Once http://b/298692153 is complete then this will be the type of tile
// used in the VC controls bubble as well.
//
// There are two TileTypes: Primary and Compact.
//
// The primary tile has an icon and title, and may have a subtitle. The icon may
// or may not be separately clickable. The tile has one of the following
// behaviors:
// 1. Launch surface (e.g. Screen Capture)
// 2. Toggle (e.g. Toggle Dark Theme)
// 3. Drill-in (e.g. Go to Accessibility detailed view)
// 4. Toggle with drill-in (e.g. Toggle Wi-Fi | Go to Network details)
// 5. Togglable tile with decorative drill-in (e.g. Selecting a VPN network)
//
// The compact tile has an icon and a single title, which may be
// multi-line. They are always placed in pairs side by side to take up the
// space of a regular FeatureTile. Regular tiles may switch to their compact
// version when necessary, e.g. when entering TabletMode. It presents one
// of the following behaviors:
// 1. Launch surface (e.g. Screen Capture)
// 2. Toggle (e.g. Toggle Auto-rotate)
// 3. Drill-in (e.g. Go to Cast detailed view)
//
// Support for download UI is in the process of being added. This will allow a
// compact tile to indicate the progress of a download it is associated with.
// The initial use-case will be DLC downloading for the "Live caption" feature
// tile in the VC controls bubble, though the API for setting download state
// should be general enough that it can be used for anything download-related.
// See http://b/298692153 for details.
class ASH_EXPORT FeatureTile : public views::Button {
METADATA_HEADER(FeatureTile, views::Button)
public:
// Used in the FeatureTile constructor to set the tile view type.
enum class TileType {
kPrimary = 0,
kCompact = 1,
kMaxValue = kCompact,
};
// The possible states the download progress UI can be in. The download
// progress UI is currently only supported for compact tiles.
//
// TODO(b/315188874): Add full support for all download states.
enum class DownloadState {
kNone, // The default state, e.g. this tile is not associated
// with a download. If this tile is of type
// `TileType::kPrimary` then it should always be in this
// download state.
kPending, // The download has not yet started. The tile's label is
// changed to "Download pending". The tile is not
// interactable while in this state.
kDownloading, // The download is in progress. The tile's label is changed
// to "Downloading X%" and a download progress indicator is
// made visible. The tile is not interactable while in this
// state.
kDownloaded, // The download finished successfully.
kError, // The download finished with an error. The tile is not
// interactable while in this state.
};
// Constructor for FeatureTiles. `callback` will be called when interacting
// with the main part of the button, which accounts for the whole tile.
// If the icon is not separately clickable (the default), `callback` will
// also be called when clicking on the icon.
explicit FeatureTile(PressedCallback callback,
bool is_togglable = true,
TileType type = TileType::kPrimary);
FeatureTile(const FeatureTile&) = delete;
FeatureTile& operator=(const FeatureTile&) = delete;
~FeatureTile() override;
// Implement this class to get notified of certain state changes to this tile.
// Currently this only exists for testing purposes.
class Observer : public base::CheckedObserver {
public:
// Called when this tile's download state changes. `download_state` is the
// new download state, and `progress` is the new download progress
// (currently only meaningful when the download state is
// `DownloadState::kDownloading`).
virtual void OnDownloadStateChanged(DownloadState download_state,
int progress) = 0;
};
// Adds/removes an observer of this tile.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Sets whether the icon on the left is clickable, separate from clicking on
// the tile itself. Use SetIconClickCallback() to set the callback. This
// function is separate from SetIconClickCallback() because it's likely that
// FeatureTile users will want to set the callback once but may want to switch
// the icon between being clickable or not (e.g. the network icon based on
// Ethernet vs. Wi-Fi).
void SetIconClickable(bool clickable);
// Sets the `callback` for clicks on `icon_button_`.
void SetIconClickCallback(base::RepeatingCallback<void()> callback);
// Sets the `on_title_container_bounds_changed_` callback.
void SetOnTitleBoundsChangedCallback(
base::RepeatingCallback<void()> callback);
// Creates a decorative `drill_in_arrow_` on the right side of the tile. This
// indicates to the user that the tile shows a detailed view when pressed.
void CreateDecorativeDrillInArrow();
// Updates the colors of the background and elements of the button.
void UpdateColors();
// Updates the `toggled_` state of the tile. If the tile is not togglable,
// `toggled_` will always be false.
void SetToggled(bool toggled);
bool IsToggled() const;
// Sets the vector icon.
void SetVectorIcon(const gfx::VectorIcon& icon);
// Sets margins for 'title_container_' in the tile.
void SetTitleContainerMargins(const gfx::Insets& insets);
// Setters to apply custom background colors.
void SetBackgroundColorId(ui::ColorId background_color_id);
void SetBackgroundToggledColorId(ui::ColorId background_toggled_color_id);
void SetBackgroundDisabledColorId(ui::ColorId background_disabled_color_id);
// Sets the radius determining the tile's curved edges.
void SetButtonCornerRadius(const int radius);
// Setters to apply custom foreground colors.
void SetForegroundColorId(ui::ColorId foreground_color_id);
void SetForegroundToggledColorId(ui::ColorId foreground_toggled_color_id);
void SetForegroundDisabledColorId(ui::ColorId foreground_disabled_color_id);
void SetForegroundOptionalColorId(ui::ColorId foreground_optional_color_id);
void SetForegroundOptionalToggledColorId(
ui::ColorId foreground_optional_toggled_color_id);
// Sets a custom color for the tile's ink drop, when its toggled.
void SetInkDropToggledBaseColorId(ui::ColorId ink_drop_toggled_base_color_id);
// Sets the tile icon from an ImageSkia.
void SetImage(gfx::ImageSkia image);
// Sets the tooltip text of `icon_button_`.
void SetIconButtonTooltipText(const std::u16string& text);
// Sets the text of `label_`. If `VcDlcUi` is enabled and there is an on-going
// download associated with this tile then the new label won't be reflected in
// the UI until the download finishes. Also note that download-related labels
// (like "Downloading 7%" or "Download pending") should not be specified using
// this method - those labels are automatically set when the download state
// changes.
void SetLabel(const std::u16string& label);
// Returns the maximum width for `sub_label_`.
int GetSubLabelMaxWidth() const;
// Sets the text of the `sub_label_`.
void SetSubLabel(const std::u16string& sub_label);
// Sets visibility of `sub_label_`.
void SetSubLabelVisibility(bool visible);
// Sets the state of this tile's download progress UI. See the documentation
// for the `DownloadState` enum for more details on how a particular download
// state affects the tile. `progress` is an integer in the range [0, 100], and
// is ignored when `state` is not `DownloadState::kDownloading`.
void SetDownloadState(DownloadState state, int progress);
// views::View:
void AddLayerToRegion(ui::Layer* layer, views::LayerRegion region) override;
void RemoveLayerFromRegions(ui::Layer* layer) override;
// views::ViewObserver:
void OnViewBoundsChanged(views::View* observed_view) override;
base::WeakPtr<FeatureTile> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
TileType tile_type() { return type_; }
bool is_icon_clickable() const { return is_icon_clickable_; }
views::ImageButton* icon_button() { return icon_button_; }
views::Label* label() { return label_; }
views::Label* sub_label() { return sub_label_; }
views::ImageView* drill_in_arrow() { return drill_in_arrow_; }
int corner_radius() const { return corner_radius_; }
DownloadState download_state_for_testing() const { return download_state_; }
int download_progress_for_testing() const {
return download_progress_percent_;
}
private:
friend class BluetoothFeaturePodControllerTest;
friend class HotspotFeaturePodControllerTest;
friend class NotificationCounterViewTest;
// A `views::Background` that visually indicates download progress.
// Automatically handles both LTR and RTL layouts.
class ProgressBackground : public views::Background {
public:
ProgressBackground(ui::ColorId progress_color_id,
ui::ColorId background_color_id);
ProgressBackground(const ProgressBackground&) = delete;
ProgressBackground& operator=(const ProgressBackground&) = delete;
~ProgressBackground() override = default;
// views::Background:
void Paint(gfx::Canvas* canvas, views::View* view) const override;
private:
// The `ui::ColorId`s for both the progress- and non-progress-(i.e.
// "background-") portions of the background.
const ui::ColorId progress_color_id_;
const ui::ColorId background_color_id_;
};
// views::Button:
void OnSetTooltipText(const std::u16string& tooltip_text) override;
// Creates child views of Feature Tile. The constructed view will vary
// depending on the button's `type_`.
void CreateChildViews();
// Returns the color id to use for the `icon_button_` and `drill_in_arrow_`
// based on the tile's enabled and toggled state.
ui::ColorId GetIconColorId() const;
// Updates the ink drop hover color and ripple color for `icon_button_`.
void UpdateIconButtonRippleColors();
// Updates the focus ring color for `icon_button_` for better visibility.
void UpdateIconButtonFocusRingColor();
// Updates the color of `drill_in_arrow_` for better visibility.
void UpdateDrillInArrowColor();
// Updates the accessibility properties directly in the cache, like the role
// and the toggle state.
void UpdateAccessibilityProperties();
// Updates `label_` attributes depending on whether a sub-label will be
// visible.
void SetCompactTileLabelPreferences(bool has_sub_label);
// Sets the tile's label to its download-related version (e.g. "Downloading
// 7%" or "Download pending"). This is different from `SetLabel()` because
// `SetLabel()` is intended to be used externally for setting the tile's
// non-download-related label (i.e. the "client-specified" label), whereas
// this method is only used internally by this class to temporarily switch to
// a different label during download. An optional tooltip can be included if
// the tooltip should differ from the `download_label`.
void SetDownloadLabel(const std::u16string& download_label,
std::optional<std::u16string> tooltip = std::nullopt);
// Updates the tile's label according to the current download state. Note that
// this method assumes the download-related state (e.g. `download_state_` and
// `download_progress_percent_`) is current, so it is up to the client to
// perform any download-related state changes prior to calling this.
void UpdateLabelForDownloadState();
// Notifies all observers of this tile's current download state. Should only
// be called when the download state actually changes.
void NotifyDownloadStateChanged();
// A list of this tile's observers.
base::ObserverList<Observer> observers_;
// Ensures the ink drop is painted above the button's background.
raw_ptr<views::InkDropContainerView> ink_drop_container_ = nullptr;
// The vector icon for the tile, if one is set.
raw_ptr<const gfx::VectorIcon> vector_icon_ = nullptr;
// Customized value for the tile's background color and foreground color.
std::optional<ui::ColorId> background_color_;
std::optional<ui::ColorId> background_toggled_color_;
std::optional<ui::ColorId> background_disabled_color_;
std::optional<ui::ColorId> foreground_color_;
std::optional<ui::ColorId> foreground_toggled_color_;
std::optional<ui::ColorId> foreground_optional_color_;
std::optional<ui::ColorId> foreground_optional_toggled_color_;
std::optional<ui::ColorId> foreground_disabled_color_;
// Customized value for the tile's ink drop color.
std::optional<ui::ColorId> ink_drop_toggled_base_color_;
// Owned by views hierarchy.
raw_ptr<views::ImageButton> icon_button_ = nullptr;
raw_ptr<views::Label> label_ = nullptr;
raw_ptr<views::Label> sub_label_ = nullptr;
raw_ptr<views::ImageView> drill_in_arrow_ = nullptr;
raw_ptr<views::FlexLayoutView> title_container_ = nullptr;
// The radius of the tile's curved edges.
int corner_radius_;
// Whether the icon is separately clickable.
bool is_icon_clickable_ = false;
// Whether this button is togglable.
const bool is_togglable_ = false;
// Whether the button is currently toggled.
bool toggled_ = false;
// The non-download-related (a.k.a. "client-specified") text of this tile's
// label/tooltip. The tile's label/tooltip may change when its downloading
// state changes, so this is used to store the original, client-specified
// label/tooltip for later reference (e.g. when a download finishes and the
// tile needs to show the original label again).
std::u16string client_specified_label_text_;
std::u16string client_specified_tooltip_text_;
// The type of the feature tile that determines how it lays out its view.
TileType type_;
// Used to update tile colors and to set the drill-in button enabled state
// when the button state changes.
base::CallbackListSubscription enabled_changed_subscription_;
// The download state this tile is in. A tile is not associated with a
// download by default.
DownloadState download_state_ = DownloadState::kNone;
// True when `UpdateLabelForDownloadState()` is happening.
bool updating_download_state_labels_ = false;
// The download progress, as an integer percentage in the range [0, 100]. Only
// has meaning when the tile is in an active download state.
int download_progress_percent_ = 0;
// Runs when `title_container_`'s bounds is changed.
base::RepeatingClosure on_title_container_bounds_changed_;
base::WeakPtrFactory<FeatureTile> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_SYSTEM_UNIFIED_FEATURE_TILE_H_
|