[go: nahoru, domu]

blob: 950018359922e355bff2811f90ec968d70324569 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/message_center/notifier_settings_view.h"
#include <stddef.h>
#include <set>
#include <string>
#include <utility>
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/public/cpp/notifier_metadata.h"
#include "ash/public/cpp/notifier_settings_controller.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ash/system/machine_learning/user_settings_event_logger.h"
#include "ash/system/message_center/message_center_controller.h"
#include "ash/system/message_center/message_center_style.h"
#include "ash/system/tray/tray_popup_utils.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "components/prefs/pref_service.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_features.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/skia_paint_util.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/message_center/vector_icons.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/controls/button/toggle_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/link.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
#include "ui/views/controls/separator.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/painter.h"
#include "ui/views/widget/widget.h"
namespace ash {
using message_center::MessageCenter;
using message_center::NotifierId;
using ContentLayerType = AshColorProvider::ContentLayerType;
namespace {
const int kNotifierButtonWrapperHeight = 48;
const int kHorizontalMargin = 12;
const int kEntryIconSize = 20;
const int kInternalHorizontalSpacing = 16;
const int kSmallerInternalHorizontalSpacing = 12;
const int kCheckboxSizeWithPadding = 28;
// The width of the settings pane in pixels.
const int kWidth = 360;
// The minimum height of the settings pane in pixels.
const int kMinimumHeight = 480;
// Checkboxes have some built-in right padding blank space.
const int kInnateCheckboxRightPadding = 2;
// Spec defines the checkbox size; the innate padding throws this measurement
// off so we need to compute a slightly different area for the checkbox to
// inhabit.
constexpr int kComputedCheckboxSize =
kCheckboxSizeWithPadding - kInnateCheckboxRightPadding;
constexpr gfx::Insets kTopLabelPadding(16, 18, 15, 18);
const int kToggleButtonRowViewSpacing = 18;
constexpr gfx::Insets kToggleButtonRowViewPadding(0, 18, 0, 0);
constexpr gfx::Insets kToggleButtonRowLabelPadding(16, 0, 15, 0);
constexpr SkColor kTopBorderColor = SkColorSetA(SK_ColorBLACK, 0x1F);
const int kLabelFontSizeDelta = 1;
void LogUserQuietModeEvent(const bool enabled) {
auto* logger = ml::UserSettingsEventLogger::Get();
if (logger) {
logger->LogQuietModeUkmEvent(enabled);
}
}
// NotifierButtonWrapperView ---------------------------------------------------
// A wrapper view of NotifierButton to guarantee the fixed height
// |kNotifierButtonWrapperHeight|. The button is placed in the middle of
// the wrapper view by giving padding to the top and the bottom.
// The view is focusable and provides focus painter. When the button is disabled
// (NotifierMetadata.enforced), it also applies filter to make the color of the
// button dim.
class NotifierButtonWrapperView : public views::View {
public:
explicit NotifierButtonWrapperView(views::View* contents);
~NotifierButtonWrapperView() override;
// views::View:
void Layout() override;
gfx::Size CalculatePreferredSize() const override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
void OnFocus() override;
bool OnKeyPressed(const ui::KeyEvent& event) override;
bool OnKeyReleased(const ui::KeyEvent& event) override;
bool OnMousePressed(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
void OnPaint(gfx::Canvas* canvas) override;
void OnBlur() override;
const char* GetClassName() const override;
private:
std::unique_ptr<views::Painter> focus_painter_;
// NotifierButton to wrap.
views::View* contents_;
DISALLOW_COPY_AND_ASSIGN(NotifierButtonWrapperView);
};
NotifierButtonWrapperView::NotifierButtonWrapperView(views::View* contents)
: focus_painter_(TrayPopupUtils::CreateFocusPainter()),
contents_(contents) {
AddChildView(contents);
}
NotifierButtonWrapperView::~NotifierButtonWrapperView() = default;
void NotifierButtonWrapperView::Layout() {
int contents_width = width();
int contents_height = contents_->GetHeightForWidth(contents_width);
int y = std::max((height() - contents_height) / 2, 0);
contents_->SetBounds(0, y, contents_width, contents_height);
SetFocusBehavior(contents_->GetEnabled() ? FocusBehavior::ALWAYS
: FocusBehavior::NEVER);
}
gfx::Size NotifierButtonWrapperView::CalculatePreferredSize() const {
return gfx::Size(kWidth, kNotifierButtonWrapperHeight);
}
void NotifierButtonWrapperView::GetAccessibleNodeData(
ui::AXNodeData* node_data) {
contents_->GetAccessibleNodeData(node_data);
}
void NotifierButtonWrapperView::OnFocus() {
views::View::OnFocus();
ScrollRectToVisible(GetLocalBounds());
// We render differently when focused.
SchedulePaint();
}
bool NotifierButtonWrapperView::OnKeyPressed(const ui::KeyEvent& event) {
return contents_->OnKeyPressed(event);
}
bool NotifierButtonWrapperView::OnKeyReleased(const ui::KeyEvent& event) {
return contents_->OnKeyReleased(event);
}
bool NotifierButtonWrapperView::OnMousePressed(const ui::MouseEvent& event) {
return contents_->OnMousePressed(event);
}
void NotifierButtonWrapperView::OnMouseReleased(const ui::MouseEvent& event) {
contents_->OnMouseReleased(event);
}
void NotifierButtonWrapperView::OnPaint(gfx::Canvas* canvas) {
View::OnPaint(canvas);
views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
}
void NotifierButtonWrapperView::OnBlur() {
View::OnBlur();
// We render differently when focused.
SchedulePaint();
}
const char* NotifierButtonWrapperView::GetClassName() const {
return "NotifierButtonWrapperView";
}
// ScrollContentsView ----------------------------------------------------------
class ScrollContentsView : public views::View {
public:
ScrollContentsView() = default;
// views::View:
const char* GetClassName() const override { return "ScrollContentsView"; }
private:
void PaintChildren(const views::PaintInfo& paint_info) override {
views::View::PaintChildren(paint_info);
if (y() == 0)
return;
// Draw a shadow at the top of the viewport when scrolled.
const ui::PaintContext& context = paint_info.context();
gfx::Rect shadowed_area(0, 0, width(), -y());
ui::PaintRecorder recorder(context, size());
gfx::Canvas* canvas = recorder.canvas();
gfx::ShadowValues shadow;
shadow.emplace_back(
gfx::Vector2d(0, message_center_style::kScrollShadowOffsetY),
message_center_style::kScrollShadowBlur,
message_center_style::kScrollShadowColor);
cc::PaintFlags flags;
flags.setLooper(gfx::CreateShadowDrawLooper(shadow));
flags.setAntiAlias(true);
canvas->ClipRect(shadowed_area, SkClipOp::kDifference);
canvas->DrawRect(shadowed_area, flags);
}
DISALLOW_COPY_AND_ASSIGN(ScrollContentsView);
};
// EmptyNotifierView -----------------------------------------------------------
class EmptyNotifierView : public views::View {
public:
EmptyNotifierView() {
const SkColor text_color = AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kTextColorPrimary);
auto layout = std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, gfx::Insets(), 0);
layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
SetLayoutManager(std::move(layout));
views::ImageView* icon = new views::ImageView();
icon->SetImage(gfx::CreateVectorIcon(kNotificationCenterEmptyIcon,
message_center_style::kEmptyIconSize,
text_color));
icon->SetBorder(
views::CreateEmptyBorder(message_center_style::kEmptyIconPadding));
AddChildView(icon);
views::Label* label = new views::Label(
l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_NO_NOTIFIERS));
label->SetEnabledColor(text_color);
label->SetAutoColorReadabilityEnabled(false);
label->SetSubpixelRenderingEnabled(false);
// "Roboto-Medium, 12sp" is specified in the mock.
label->SetFontList(
gfx::FontList().DeriveWithWeight(gfx::Font::Weight::MEDIUM));
AddChildView(label);
}
// views::View:
const char* GetClassName() const override { return "EmptyNotifierView"; }
private:
DISALLOW_COPY_AND_ASSIGN(EmptyNotifierView);
};
class NotifierViewCheckbox : public views::Checkbox {
public:
using views::Checkbox::Checkbox;
private:
// views::Checkbox:
SkColor GetIconImageColor(int icon_state) const override {
if (icon_state & IconState::CHECKED) {
return AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kIconColorProminent);
}
return views::Checkbox::GetIconImageColor(icon_state);
}
};
} // namespace
// NotifierSettingsView::NotifierButton ---------------------------------------
// We do not use views::Checkbox class directly because it doesn't support
// showing 'icon'.
NotifierSettingsView::NotifierButton::NotifierButton(
const NotifierMetadata& notifier)
: views::Button(PressedCallback()), notifier_id_(notifier.notifier_id) {
SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY);
auto icon_view = std::make_unique<views::ImageView>();
auto name_view = std::make_unique<views::Label>(notifier.name);
auto checkbox = std::make_unique<NotifierViewCheckbox>(
std::u16string(),
base::BindRepeating(
[](NotifierButton* button, const ui::Event& event) {
// The checkbox state has already changed at this point, but we'll
// update the state on NotifierSettingsView::NotifierButtonPressed()
// too, so here change back to the previous state.
button->checkbox_->SetChecked(!button->checkbox_->GetChecked());
button->NotifyClick(event);
},
this));
name_view->SetAutoColorReadabilityEnabled(false);
name_view->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kTextColorPrimary));
name_view->SetSubpixelRenderingEnabled(false);
// "Roboto-Regular, 13sp" is specified in the mock.
name_view->SetFontList(
gfx::FontList().DeriveWithSizeDelta(kLabelFontSizeDelta));
checkbox->SetChecked(notifier.enabled);
checkbox->SetFocusBehavior(FocusBehavior::NEVER);
checkbox->SetAccessibleName(notifier.name);
if (notifier.enforced) {
Button::SetEnabled(false);
checkbox->SetEnabled(false);
icon_view->SetPaintToLayer();
icon_view->layer()->SetFillsBoundsOpaquely(false);
icon_view->layer()->SetOpacity(gfx::kDisabledControlAlpha / float{0xFF});
name_view->SetEnabledColor(
SkColorSetA(name_view->GetEnabledColor(), gfx::kDisabledControlAlpha));
}
// Add the views before the layout is assigned. Because GridChanged() may be
// called multiple times, these views should already be child views.
checkbox_ = AddChildView(std::move(checkbox));
icon_view_ = AddChildView(std::move(icon_view));
name_view_ = AddChildView(std::move(name_view));
UpdateIconImage(notifier.icon);
}
NotifierSettingsView::NotifierButton::~NotifierButton() = default;
void NotifierSettingsView::NotifierButton::UpdateIconImage(
const gfx::ImageSkia& icon) {
if (icon.isNull()) {
icon_view_->SetImage(
gfx::CreateVectorIcon(message_center::kProductIcon, kEntryIconSize,
AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kIconColorPrimary)));
} else {
icon_view_->SetImage(icon);
icon_view_->SetImageSize(gfx::Size(kEntryIconSize, kEntryIconSize));
}
GridChanged();
}
void NotifierSettingsView::NotifierButton::SetChecked(bool checked) {
checkbox_->SetChecked(checked);
}
bool NotifierSettingsView::NotifierButton::GetChecked() const {
return checkbox_->GetChecked();
}
const char* NotifierSettingsView::NotifierButton::GetClassName() const {
return "NotifierButton";
}
void NotifierSettingsView::NotifierButton::GetAccessibleNodeData(
ui::AXNodeData* node_data) {
static_cast<views::View*>(checkbox_)->GetAccessibleNodeData(node_data);
}
void NotifierSettingsView::NotifierButton::GridChanged() {
using views::ColumnSet;
using views::GridLayout;
GridLayout* layout = SetLayoutManager(std::make_unique<GridLayout>());
ColumnSet* cs = layout->AddColumnSet(0);
// Add a column for the checkbox.
cs->AddPaddingColumn(0, kInnateCheckboxRightPadding);
cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
GridLayout::ColumnSize::kFixed, kComputedCheckboxSize, 0);
cs->AddPaddingColumn(0, kInternalHorizontalSpacing);
// Add a column for the icon.
cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
GridLayout::ColumnSize::kFixed, kEntryIconSize, 0);
cs->AddPaddingColumn(0, kSmallerInternalHorizontalSpacing);
// Add a column for the name.
cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
GridLayout::ColumnSize::kUsePreferred, 0, 0);
// Add a padding column which contains expandable blank space.
cs->AddPaddingColumn(1, 0);
layout->StartRow(0, 0);
layout->AddExistingView(checkbox_);
layout->AddExistingView(icon_view_);
layout->AddExistingView(name_view_);
if (!GetEnabled()) {
auto policy_enforced_icon = std::make_unique<views::ImageView>();
policy_enforced_icon->SetImage(
gfx::CreateVectorIcon(kSystemMenuBusinessIcon, kEntryIconSize,
AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kIconColorPrimary)));
cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
GridLayout::ColumnSize::kFixed, kEntryIconSize, 0);
layout->AddView(std::move(policy_enforced_icon));
}
Layout();
}
// NotifierSettingsView -------------------------------------------------------
NotifierSettingsView::NotifierSettingsView() {
SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
auto header_view = std::make_unique<views::View>();
header_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, gfx::Insets(), 0));
header_view->SetBorder(
views::CreateSolidSidedBorder(0, 0, 4, 0, kTopBorderColor));
const SkColor text_color = AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kTextColorPrimary);
const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kIconColorPrimary);
const SkColor separator_color = AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kSeparatorColor);
if (features::IsNotificationIndicatorEnabled()) {
// Row for the app badging toggle button.
auto app_badging_icon = std::make_unique<views::ImageView>();
app_badging_icon->SetImage(gfx::CreateVectorIcon(
kSystemTrayAppBadgingIcon, kMenuIconSize, icon_color));
auto app_badging_label =
std::make_unique<views::Label>(l10n_util::GetStringUTF16(
IDS_ASH_MESSAGE_CENTER_APP_BADGING_BUTTON_TOOLTIP));
auto app_badging_toggle = base::WrapUnique<views::ToggleButton>(
TrayPopupUtils::CreateToggleButton(
base::BindRepeating(&NotifierSettingsView::AppBadgingTogglePressed,
base::Unretained(this)),
IDS_ASH_MESSAGE_CENTER_APP_BADGING_BUTTON_TOOLTIP));
app_badging_toggle_ = app_badging_toggle.get();
SessionControllerImpl* session_controller =
Shell::Get()->session_controller();
PrefService* prefs = session_controller->GetLastActiveUserPrefService();
if (prefs) {
app_badging_toggle_->SetIsOn(
prefs->GetBoolean(prefs::kAppNotificationBadgingEnabled));
}
auto app_badging_view = CreateToggleButtonRow(
std::move(app_badging_icon), std::move(app_badging_label),
std::move(app_badging_toggle));
app_badging_view->SetBorder(
views::CreateSolidSidedBorder(0, 0, 0, 1, kTopBorderColor));
header_view->AddChildView(std::move(app_badging_view));
// Separator between toggle button rows.
auto separator = std::make_unique<views::Separator>();
separator->SetColor(separator_color);
header_view->AddChildView(std::move(separator));
}
// Row for the quiet mode toggle button.
auto quiet_mode_icon = std::make_unique<views::ImageView>();
quiet_mode_icon_ = quiet_mode_icon.get();
auto quiet_mode_label =
std::make_unique<views::Label>(l10n_util::GetStringUTF16(
IDS_ASH_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP));
auto quiet_mode_toggle =
base::WrapUnique<views::ToggleButton>(TrayPopupUtils::CreateToggleButton(
base::BindRepeating(&NotifierSettingsView::QuietModeTogglePressed,
base::Unretained(this)),
IDS_ASH_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP));
quiet_mode_toggle_ = quiet_mode_toggle.get();
auto quiet_mode_view = CreateToggleButtonRow(std::move(quiet_mode_icon),
std::move(quiet_mode_label),
std::move(quiet_mode_toggle));
SetQuietModeState(MessageCenter::Get()->IsQuietMode());
header_view->AddChildView(std::move(quiet_mode_view));
auto top_label = std::make_unique<views::Label>(l10n_util::GetStringUTF16(
IDS_ASH_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION));
top_label->SetBorder(views::CreateEmptyBorder(kTopLabelPadding));
// "Roboto-Medium, 13sp" is specified in the mock.
top_label->SetFontList(gfx::FontList().Derive(
kLabelFontSizeDelta, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
top_label->SetAutoColorReadabilityEnabled(false);
top_label->SetEnabledColor(text_color);
top_label->SetSubpixelRenderingEnabled(false);
top_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
top_label->SetMultiLine(true);
top_label_ = header_view->AddChildView(std::move(top_label));
header_view_ = AddChildView(std::move(header_view));
auto scroller = std::make_unique<views::ScrollView>();
scroller->SetBackgroundColor(base::nullopt);
scroll_bar_ = scroller->SetVerticalScrollBar(
std::make_unique<views::OverlayScrollBar>(/*horizontal=*/false));
scroller->SetDrawOverflowIndicator(false);
scroller_ = AddChildView(std::move(scroller));
no_notifiers_view_ = AddChildView(std::make_unique<EmptyNotifierView>());
OnNotifiersUpdated({});
NotifierSettingsController::Get()->AddNotifierSettingsObserver(this);
NotifierSettingsController::Get()->GetNotifiers();
}
NotifierSettingsView::~NotifierSettingsView() {
NotifierSettingsController::Get()->RemoveNotifierSettingsObserver(this);
}
bool NotifierSettingsView::IsScrollable() {
return scroller_->height() < scroller_->contents()->height();
}
void NotifierSettingsView::SetQuietModeState(bool is_quiet_mode) {
quiet_mode_toggle_->SetIsOn(is_quiet_mode);
const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kIconColorPrimary);
if (is_quiet_mode) {
quiet_mode_icon_->SetImage(gfx::CreateVectorIcon(
kSystemTrayDoNotDisturbIcon, kMenuIconSize, icon_color));
} else {
quiet_mode_icon_->SetImage(gfx::CreateVectorIcon(
kDoNotDisturbDisabledIcon, kMenuIconSize, icon_color));
}
}
void NotifierSettingsView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kList;
node_data->SetName(l10n_util::GetStringUTF16(
IDS_ASH_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION));
}
const char* NotifierSettingsView::GetClassName() const {
return "NotifierSettingsView";
}
void NotifierSettingsView::OnNotifiersUpdated(
const std::vector<NotifierMetadata>& notifiers) {
// TODO(tetsui): currently notifier settings list doesn't update after once
// it's loaded, in order to retain scroll position.
if (scroller_->contents() && buttons_.size() > 0)
return;
buttons_.clear();
auto contents_view = std::make_unique<ScrollContentsView>();
contents_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical,
gfx::Insets(0, kHorizontalMargin)));
for (const auto& notifier : notifiers) {
NotifierButton* button = new NotifierButton(notifier);
button->SetCallback(
base::BindRepeating(&NotifierSettingsView::NotifierButtonPressed,
base::Unretained(this), button));
NotifierButtonWrapperView* wrapper = new NotifierButtonWrapperView(button);
wrapper->SetFocusBehavior(FocusBehavior::ALWAYS);
contents_view->AddChildView(wrapper);
buttons_.insert(button);
}
top_label_->SetVisible(!buttons_.empty());
no_notifiers_view_->SetVisible(buttons_.empty());
top_label_->InvalidateLayout();
auto* contents_view_ptr = scroller_->SetContents(std::move(contents_view));
contents_view_ptr->SetBoundsRect(
gfx::Rect(contents_view_ptr->GetPreferredSize()));
Layout();
}
void NotifierSettingsView::OnNotifierIconUpdated(const NotifierId& notifier_id,
const gfx::ImageSkia& icon) {
for (auto* button : buttons_) {
if (button->notifier_id() == notifier_id) {
button->UpdateIconImage(icon);
return;
}
}
}
void NotifierSettingsView::Layout() {
int original_scroll_position = scroller_->GetVisibleRect().y();
int header_height = header_view_->GetHeightForWidth(width());
header_view_->SetBounds(0, 0, width(), header_height);
views::View* contents_view = scroller_->contents();
int content_width = width();
int content_height = contents_view->GetHeightForWidth(content_width);
if (header_height + content_height > height()) {
content_width -= scroller_->GetScrollBarLayoutWidth();
content_height = contents_view->GetHeightForWidth(content_width);
}
contents_view->SetBounds(0, 0, content_width, content_height);
scroller_->SetBounds(0, header_height, width(), height() - header_height);
no_notifiers_view_->SetBounds(0, header_height, width(),
height() - header_height);
// The scroll position may have changed after the layout.
scroller_->ScrollToPosition(scroll_bar_, original_scroll_position);
}
gfx::Size NotifierSettingsView::GetMinimumSize() const {
gfx::Size size(kWidth, kMinimumHeight);
int total_height = header_view_->GetPreferredSize().height() +
scroller_->contents()->GetPreferredSize().height();
if (total_height > kMinimumHeight)
size.Enlarge(scroller_->GetScrollBarLayoutWidth(), 0);
return size;
}
gfx::Size NotifierSettingsView::CalculatePreferredSize() const {
gfx::Size header_size = header_view_->GetPreferredSize();
gfx::Size content_size = scroller_->contents()->GetPreferredSize();
int no_notifiers_height = 0;
if (no_notifiers_view_->GetVisible())
no_notifiers_height = no_notifiers_view_->GetPreferredSize().height();
return gfx::Size(
std::max(header_size.width(), content_size.width()),
std::max(kMinimumHeight, header_size.height() + content_size.height() +
no_notifiers_height));
}
bool NotifierSettingsView::OnKeyPressed(const ui::KeyEvent& event) {
if (event.key_code() == ui::VKEY_ESCAPE) {
GetWidget()->Close();
return true;
}
return scroller_->OnKeyPressed(event);
}
bool NotifierSettingsView::OnMouseWheel(const ui::MouseWheelEvent& event) {
return scroller_->OnMouseWheel(event);
}
std::unique_ptr<views::View> NotifierSettingsView::CreateToggleButtonRow(
std::unique_ptr<views::ImageView> icon,
std::unique_ptr<views::Label> label,
std::unique_ptr<views::ToggleButton> toggle_button) {
auto row_view = std::make_unique<views::View>();
auto* row_layout =
row_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal,
kToggleButtonRowViewPadding, kToggleButtonRowViewSpacing));
icon->SetBorder(views::CreateEmptyBorder(kToggleButtonRowLabelPadding));
row_view->AddChildView(std::move(icon));
const SkColor text_color = AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kTextColorPrimary);
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
// "Roboto-Regular, 13sp" is specified in the mock.
label->SetFontList(gfx::FontList().DeriveWithSizeDelta(kLabelFontSizeDelta));
label->SetAutoColorReadabilityEnabled(false);
label->SetEnabledColor(text_color);
label->SetSubpixelRenderingEnabled(false);
label->SetBorder(views::CreateEmptyBorder(kToggleButtonRowLabelPadding));
auto* label_ptr = row_view->AddChildView(std::move(label));
row_layout->SetFlexForView(label_ptr, 1);
toggle_button->SetFlipCanvasOnPaintForRTLUI(true);
row_view->AddChildView(std::move(toggle_button));
return row_view;
}
void NotifierSettingsView::AppBadgingTogglePressed() {
SessionControllerImpl* session_controller =
Shell::Get()->session_controller();
PrefService* prefs = session_controller->GetLastActiveUserPrefService();
if (prefs) {
prefs->SetBoolean(prefs::kAppNotificationBadgingEnabled,
app_badging_toggle_->GetIsOn());
}
}
void NotifierSettingsView::QuietModeTogglePressed() {
LogUserQuietModeEvent(quiet_mode_toggle_->GetIsOn());
MessageCenter::Get()->SetQuietMode(quiet_mode_toggle_->GetIsOn());
}
void NotifierSettingsView::NotifierButtonPressed(NotifierButton* button) {
button->SetChecked(!button->GetChecked());
NotifierSettingsController::Get()->SetNotifierEnabled(button->notifier_id(),
button->GetChecked());
NotifierSettingsController::Get()->GetNotifiers();
}
} // namespace ash