#include "ui/message_center/views/notification_view_base.h"
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <utility>
#include "ash/constants/ash_features.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/i18n/case_conversion.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/observer_list.h"
#include "base/strings/string_util.h"
#include "build/chromeos_buildflags.h"
#include "components/url_formatter/elide_url.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/base/class_property.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/color/color_id.h"
#include "ui/color/color_provider.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/text_constants.h"
#include "ui/gfx/text_elider.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification_list.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_types.h"
#include "ui/message_center/vector_icons.h"
#include "ui/message_center/views/large_image_view.h"
#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/message_center/views/notification_header_view.h"
#include "ui/message_center/views/proportional_image_view.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/progress_bar.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/style/typography.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace message_center {
namespace {
constexpr int kActionsRowHorizontalSpacing = 8;
constexpr auto kStatusTextPadding = gfx::Insets::TLBR(4, 0, 0, 0);
constexpr gfx::Insets kActionsRowPadding(8);
constexpr int kLargeImageMaxHeight = 218;
constexpr int kCompactTitleMessageViewSpacing = 12;
constexpr int kProgressBarHeight = 4;
constexpr double kProgressNotificationMessageRatio = 0.7;
class ClickActivator : public ui::EventHandler {
public:
explicit ClickActivator(NotificationViewBase* owner) : owner_(owner) {}
ClickActivator(const ClickActivator&) = delete;
ClickActivator& operator=(const ClickActivator&) = delete;
~ClickActivator() override = default;
private:
void OnEvent(ui::Event* event) override {
if (event->type() == ui::ET_MOUSE_PRESSED ||
event->type() == ui::ET_GESTURE_TAP) {
owner_->Activate();
}
}
const raw_ptr<NotificationViewBase> owner_;
};
std::unique_ptr<views::View> CreateItemView(const NotificationItem& item) {
auto view = std::make_unique<views::View>();
view->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), 0));
auto* title = view->AddChildView(std::make_unique<views::Label>(
item.title, views::style::CONTEXT_DIALOG_BODY_TEXT));
title->SetCollapseWhenHidden(true);
title->SetHorizontalAlignment(gfx::ALIGN_LEFT);
auto* message = view->AddChildView(std::make_unique<views::Label>(
l10n_util::GetStringFUTF16(
IDS_MESSAGE_CENTER_LIST_NOTIFICATION_MESSAGE_WITH_DIVIDER,
item.message),
views::style::CONTEXT_DIALOG_BODY_TEXT, views::style::STYLE_SECONDARY));
message->SetCollapseWhenHidden(true);
message->SetHorizontalAlignment(gfx::ALIGN_LEFT);
return view;
}
bool IsForAshNotification() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
return true;
#else
return false;
#endif
}
}
CompactTitleMessageView::~CompactTitleMessageView() = default;
const char* CompactTitleMessageView::GetClassName() const {
return "CompactTitleMessageView";
}
CompactTitleMessageView::CompactTitleMessageView() {
title_ = AddChildView(std::make_unique<views::Label>(
std::u16string(), views::style::CONTEXT_DIALOG_BODY_TEXT));
title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
message_ = AddChildView(std::make_unique<views::Label>(
std::u16string(), views::style::CONTEXT_DIALOG_BODY_TEXT,
views::style::STYLE_SECONDARY));
message_->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
}
gfx::Size CompactTitleMessageView::CalculatePreferredSize() const {
gfx::Size title_size = title_->GetPreferredSize();
gfx::Size message_size = message_->GetPreferredSize();
return gfx::Size(title_size.width() + message_size.width() +
kCompactTitleMessageViewSpacing,
std::max(title_size.height(), message_size.height()));
}
void CompactTitleMessageView::Layout() {
const int message_width = std::min(
message_->GetPreferredSize().width(),
title_->GetPreferredSize().width() > 0
? static_cast<int>(kProgressNotificationMessageRatio * width())
: width());
const int title_width =
std::max(0, width() - message_width - kCompactTitleMessageViewSpacing);
title_->SetBounds(0, 0, title_width, height());
message_->SetBounds(width() - message_width, 0, message_width, height());
}
void CompactTitleMessageView::set_title(const std::u16string& title) {
title_->SetText(title);
}
void CompactTitleMessageView::set_message(const std::u16string& message) {
message_->SetText(message);
}
void NotificationViewBase::CreateOrUpdateViews(
const Notification& notification) {
left_content_count_ = 0;
CreateOrUpdateHeaderView(notification);
CreateOrUpdateTitleView(notification);
CreateOrUpdateMessageLabel(notification);
CreateOrUpdateCompactTitleMessageView(notification);
CreateOrUpdateProgressViews(notification);
CreateOrUpdateListItemViews(notification);
CreateOrUpdateIconView(notification);
CreateOrUpdateSmallIconView(notification);
CreateOrUpdateImageView(notification);
CreateOrUpdateInlineSettingsViews(notification);
UpdateViewForExpandedState(expanded_);
CreateOrUpdateActionButtonViews(notification);
}
NotificationViewBase::NotificationViewBase(const Notification& notification)
: MessageView(notification), for_ash_notification_(IsForAshNotification()) {
SetNotifyEnterExitOnChild(true);
click_activator_ = std::make_unique<ClickActivator>(this);
AddPreTargetHandler(click_activator_.get());
DCHECK(views::FocusRing::Get(this));
views::FocusRing::Get(this)->SetPathGenerator(
std::make_unique<MessageView::HighlightPathGenerator>());
UpdateCornerRadius(kNotificationCornerRadius, kNotificationCornerRadius);
}
NotificationViewBase::~NotificationViewBase() {
RemovePreTargetHandler(click_activator_.get());
}
void NotificationViewBase::Layout() {
MessageView::Layout();
SetExpandButtonEnabled(IsExpandable());
header_row_->Layout();
if (actions_row_->GetVisible()) {
constexpr SkScalar kCornerRadius = SkIntToScalar(kNotificationCornerRadius);
SkPath path;
gfx::Rect bounds = actions_row_->GetLocalBounds();
bounds.set_y(bounds.y() - bounds.height());
bounds.set_height(bounds.height() * 2);
path.addRoundRect(gfx::RectToSkRect(bounds), kCornerRadius, kCornerRadius);
action_buttons_row_->SetClipPath(path);
if (inline_reply_)
inline_reply_->SetClipPath(path);
}
}
void NotificationViewBase::OnFocus() {
MessageView::OnFocus();
ScrollRectToVisible(GetLocalBounds());
}
bool NotificationViewBase::OnMousePressed(const ui::MouseEvent& event) {
last_mouse_pressed_timestamp_ = base::TimeTicks(event.time_stamp());
return true;
}
bool NotificationViewBase::OnMouseDragged(const ui::MouseEvent& event) {
return true;
}
void NotificationViewBase::OnMouseReleased(const ui::MouseEvent& event) {
if (!event.IsOnlyLeftMouseButton())
return;
if (ui::EventTimeStampToSeconds(event.time_stamp()) -
ui::EventTimeStampToSeconds(last_mouse_pressed_timestamp_) >
ui::GetGestureProviderConfig(
ui::GestureProviderConfigType::CURRENT_PLATFORM)
.gesture_detector_config.longpress_timeout.InSecondsF()) {
ToggleInlineSettings(event);
return;
}
if (expanded_) {
DCHECK(actions_row_);
gfx::Point point_in_child = event.location();
ConvertPointToTarget(this, actions_row_, &point_in_child);
if (actions_row_->HitTestPoint(point_in_child))
return;
}
if (settings_row_->GetVisible())
return;
MessageView::OnMouseReleased(event);
}
void NotificationViewBase::OnMouseEvent(ui::MouseEvent* event) {
switch (event->type()) {
case ui::ET_MOUSE_ENTERED:
UpdateControlButtonsVisibility();
break;
case ui::ET_MOUSE_EXITED:
UpdateControlButtonsVisibility();
break;
default:
break;
}
View::OnMouseEvent(event);
}
void NotificationViewBase::OnGestureEvent(ui::GestureEvent* event) {
if (event->type() == ui::ET_GESTURE_LONG_TAP) {
ToggleInlineSettings(*event);
return;
}
MessageView::OnGestureEvent(event);
}
void NotificationViewBase::UpdateWithNotification(
const Notification& notification) {
MessageView::UpdateWithNotification(notification);
UpdateControlButtonsVisibilityWithNotification(notification);
CreateOrUpdateViews(notification);
Layout();
SchedulePaint();
}
void NotificationViewBase::OnNotificationInputSubmit(
size_t index,
const std::u16string& text) {
MessageCenter::Get()->ClickOnNotificationButtonWithReply(notification_id(),
index, text);
}
bool NotificationViewBase::IsIconViewShown() const {
return icon_view_ && (!hide_icon_on_expanded_ || !expanded_);
}
views::Builder<NotificationControlButtonsView>
NotificationViewBase::CreateControlButtonsBuilder() {
DCHECK(!control_buttons_view_);
return views::Builder<NotificationControlButtonsView>()
.CopyAddressTo(&control_buttons_view_)
.SetMessageView(this);
}
views::Builder<NotificationHeaderView>
NotificationViewBase::CreateHeaderRowBuilder() {
DCHECK(!header_row_);
auto header_row_builder = views::Builder<NotificationHeaderView>()
.SetID(kHeaderRow)
.CopyAddressTo(&header_row_);
return header_row_builder;
}
views::Builder<views::BoxLayoutView>
NotificationViewBase::CreateLeftContentBuilder() {
DCHECK(!left_content_);
return views::Builder<views::BoxLayoutView>()
.CopyAddressTo(&left_content_)
.SetOrientation(views::BoxLayout::Orientation::kVertical);
}
views::Builder<views::View> NotificationViewBase::CreateRightContentBuilder() {
DCHECK(!right_content_);
return views::Builder<views::View>()
.CopyAddressTo(&right_content_)
.SetUseDefaultFillLayout(true);
}
views::Builder<views::View> NotificationViewBase::CreateContentRowBuilder() {
DCHECK(!content_row_);
return views::Builder<views::View>()
.SetID(kContentRow)
.CopyAddressTo(&content_row_);
}
views::Builder<views::BoxLayoutView>
NotificationViewBase::CreateInlineSettingsBuilder() {
DCHECK(!settings_row_);
return views::Builder<views::BoxLayoutView>()
.CopyAddressTo(&settings_row_)
.SetVisible(false);
}
views::Builder<views::View>
NotificationViewBase::CreateImageContainerBuilder() {
DCHECK(!image_container_view_);
return views::Builder<views::View>()
.CopyAddressTo(&image_container_view_)
.SetUseDefaultFillLayout(true);
}
std::unique_ptr<views::View> NotificationViewBase::CreateActionsRow(
std::unique_ptr<views::LayoutManager> layout_manager) {
DCHECK(!actions_row_);
auto actions_row = std::make_unique<views::View>();
actions_row->SetVisible(false);
actions_row->SetLayoutManager(std::move(layout_manager));
DCHECK(!action_buttons_row_);
auto action_buttons_row = std::make_unique<views::View>();
action_buttons_row->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, kActionsRowPadding,
kActionsRowHorizontalSpacing));
action_buttons_row->SetVisible(false);
action_buttons_row->SetID(kActionButtonsRow);
action_buttons_row_ =
actions_row->AddChildView(std::move(action_buttons_row));
DCHECK(!inline_reply_);
auto inline_reply = GenerateNotificationInputContainer();
inline_reply->Init();
inline_reply->SetVisible(false);
inline_reply->SetID(kInlineReply);
inline_reply_ = actions_row->AddChildView(std::move(inline_reply));
actions_row_ = actions_row.get();
return actions_row;
}
std::unique_ptr<views::Label> NotificationViewBase::GenerateTitleView(
const std::u16string& title) {
auto title_view = std::make_unique<views::Label>(
title, views::style::CONTEXT_DIALOG_BODY_TEXT);
title_view->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
title_view->SetAllowCharacterBreak(true);
return title_view;
}
std::unique_ptr<NotificationInputContainer>
NotificationViewBase::GenerateNotificationInputContainer() {
return std::make_unique<NotificationInputContainer>(this);
}
void NotificationViewBase::CreateOrUpdateHeaderView(
const Notification& notification) {
header_row_->SetTimestamp(notification.timestamp());
header_row_->SetAppNameElideBehavior(gfx::ELIDE_TAIL);
std::u16string app_name;
if (notification.notifier_id().title.has_value()) {
app_name = notification.notifier_id().title.value();
} else if (notification.UseOriginAsContextMessage()) {
app_name = url_formatter::FormatUrlForSecurityDisplay(
notification.origin_url(),
url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
header_row_->SetAppNameElideBehavior(gfx::ELIDE_HEAD);
} else if (notification.display_source().empty() &&
notification.notifier_id().type ==
NotifierType::SYSTEM_COMPONENT) {
app_name = MessageCenter::Get()->GetSystemNotificationAppName();
} else if (!notification.context_message().empty()) {
app_name = notification.context_message();
} else {
app_name = notification.display_source();
}
header_row_->SetAppName(app_name);
}
void NotificationViewBase::CreateOrUpdateCompactTitleMessageView(
const Notification& notification) {
if (notification.type() != NOTIFICATION_TYPE_PROGRESS) {
DCHECK(!compact_title_message_view_ ||
left_content_->Contains(compact_title_message_view_));
delete compact_title_message_view_;
compact_title_message_view_ = nullptr;
return;
}
if (!compact_title_message_view_) {
auto compact_title_message_view =
std::make_unique<CompactTitleMessageView>();
compact_title_message_view_ =
AddViewToLeftContent(std::move(compact_title_message_view));
} else {
ReorderViewInLeftContent(compact_title_message_view_);
}
compact_title_message_view_->set_title(notification.title());
compact_title_message_view_->set_message(notification.message());
left_content_->InvalidateLayout();
}
void NotificationViewBase::CreateOrUpdateProgressBarView(
const Notification& notification) {
if (notification.type() != NOTIFICATION_TYPE_PROGRESS) {
DCHECK(!progress_bar_view_ || left_content_->Contains(progress_bar_view_));
delete progress_bar_view_;
progress_bar_view_ = nullptr;
return;
}
DCHECK(left_content_);
if (!progress_bar_view_) {
auto progress_bar_view =
std::make_unique<views::ProgressBar>(kProgressBarHeight,
false);
progress_bar_view->SetBorder(views::CreateEmptyBorder(
gfx::Insets::TLBR(kProgressBarTopPadding, 0, 0, 0)));
progress_bar_view_ = AddViewToLeftContent(std::move(progress_bar_view));
} else {
ReorderViewInLeftContent(progress_bar_view_);
}
progress_bar_view_->SetValue(notification.progress() / 100.0);
progress_bar_view_->SetVisible(notification.items().empty());
if (0 <= notification.progress() && notification.progress() <= 100)
header_row_->SetProgress(notification.progress());
}
void NotificationViewBase::CreateOrUpdateProgressStatusView(
const Notification& notification) {
if (notification.type() != NOTIFICATION_TYPE_PROGRESS ||
notification.progress_status().empty()) {
if (!status_view_)
return;
DCHECK(left_content_->Contains(status_view_));
delete status_view_;
status_view_ = nullptr;
return;
}
if (!status_view_) {
auto status_view = std::make_unique<views::Label>(
std::u16string(), views::style::CONTEXT_DIALOG_BODY_TEXT,
views::style::STYLE_SECONDARY);
status_view->SetHorizontalAlignment(gfx::ALIGN_LEFT);
status_view->SetBorder(views::CreateEmptyBorder(kStatusTextPadding));
status_view_ = AddViewToLeftContent(std::move(status_view));
} else {
ReorderViewInLeftContent(status_view_);
}
status_view_->SetText(notification.progress_status());
}
void NotificationViewBase::CreateOrUpdateMessageLabel(
const Notification& notification) {
if (notification.type() == NOTIFICATION_TYPE_PROGRESS ||
notification.message().empty()) {
delete message_label_;
message_label_ = nullptr;
return;
}
const std::u16string& text = gfx::TruncateString(
notification.message(), kMessageCharacterLimit, gfx::WORD_BREAK);
if (!message_label_) {
auto message_label = std::make_unique<views::Label>(
text, views::style::CONTEXT_DIALOG_BODY_TEXT,
views::style::STYLE_SECONDARY);
message_label->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
message_label->SetAllowCharacterBreak(true);
message_label_ = AddViewToLeftContent(std::move(message_label));
} else {
message_label_->SetText(text);
ReorderViewInLeftContent(message_label_);
}
message_label_->SetVisible(notification.items().empty());
}
void NotificationViewBase::CreateOrUpdateProgressViews(
const Notification& notification) {
CreateOrUpdateProgressBarView(notification);
CreateOrUpdateProgressStatusView(notification);
}
void NotificationViewBase::CreateOrUpdateListItemViews(
const Notification& notification) {
for (auto* item_view : item_views_)
delete item_view;
item_views_.clear();
const std::vector<NotificationItem>& items = notification.items();
for (size_t i = 0; i < items.size() && i < kMaxLinesForExpandedMessageLabel;
++i) {
std::unique_ptr<views::View> item_view = CreateItemView(items[i]);
item_views_.push_back(AddViewToLeftContent(std::move(item_view)));
}
list_items_count_ = items.size();
if (!item_views_.empty())
left_content_->InvalidateLayout();
}
void NotificationViewBase::CreateOrUpdateIconView(
const Notification& notification) {
const bool use_image_for_icon = notification.icon().IsEmpty();
ui::ImageModel icon = use_image_for_icon
? ui::ImageModel::FromImage(notification.image())
: notification.icon();
if (notification.type() == NOTIFICATION_TYPE_PROGRESS ||
notification.type() == NOTIFICATION_TYPE_MULTIPLE || icon.IsEmpty()) {
DCHECK(!icon_view_ || right_content_->Contains(icon_view_));
delete icon_view_;
icon_view_ = nullptr;
return;
}
if (!icon_view_) {
icon_view_ = new ProportionalImageView(GetIconViewSize());
right_content_->AddChildView(icon_view_.get());
}
bool apply_rounded_corners = false;
#if BUILDFLAG(IS_CHROMEOS_ASH)
apply_rounded_corners = for_ash_notification_;
#endif
icon_view_->SetImage(icon, icon.Size(), apply_rounded_corners);
hide_icon_on_expanded_ = use_image_for_icon;
}
void NotificationViewBase::CreateOrUpdateImageView(
const Notification& notification) {
if (notification.image().IsEmpty()) {
image_container_view_->RemoveAllChildViews();
image_container_view_->SetVisible(false);
return;
}
if (image_container_view_->children().empty()) {
image_container_view_->AddChildView(std::make_unique<LargeImageView>(
gfx::Size(GetLargeImageViewMaxWidth(), kLargeImageMaxHeight)));
image_container_view_->SetVisible(true);
}
static_cast<LargeImageView*>(image_container_view_->children().front())
->SetImage(notification.image().AsImageSkia());
}
void NotificationViewBase::CreateOrUpdateActionButtonViews(
const Notification& notification) {
const std::vector<ButtonInfo>& buttons = notification.buttons();
bool new_buttons = action_buttons_.size() != buttons.size();
if (new_buttons || buttons.empty()) {
for (auto* item : action_buttons_)
delete item;
action_buttons_.clear();
actions_row_->SetVisible(expanded_ && !buttons.empty());
}
if (inline_reply_ && inline_reply_->GetVisible() &&
!HasInlineReply(notification)) {
action_buttons_row_->SetVisible(true);
inline_reply_->SetVisible(false);
}
for (size_t i = 0; i < buttons.size(); ++i) {
ButtonInfo button_info = buttons[i];
std::u16string label = for_ash_notification_
? button_info.title
: base::i18n::ToUpper(button_info.title);
if (new_buttons) {
action_buttons_.push_back(
action_buttons_row_->AddChildView(GenerateNotificationLabelButton(
base::BindRepeating(&NotificationViewBase::ActionButtonPressed,
base::Unretained(this), i),
label)));
action_button_to_placeholder_map_[action_buttons_.back()] =
button_info.placeholder;
action_buttons_row_->InvalidateLayout();
} else {
action_buttons_[i]->SetText(label);
action_button_to_placeholder_map_[action_buttons_[i]] =
button_info.placeholder;
}
bool use_accent_color =
!for_ash_notification_ &&
!notification.rich_notification_data().ignore_accent_color_for_text;
if (use_accent_color) {
action_buttons_[i]->SetEnabledTextColors(notification.accent_color());
}
}
if (new_buttons && expanded_) {
views::Widget* widget = GetWidget();
if (widget && !widget->IsClosed()) {
Layout();
widget->SetSize(widget->GetContentsView()->GetPreferredSize());
widget->SynthesizeMouseMoveEvent();
}
}
}
void NotificationViewBase::ReorderViewInLeftContent(views::View* view) {
left_content_->ReorderChildView(view, left_content_count_++);
}
void NotificationViewBase::ActionButtonPressed(size_t index,
const ui::Event& event) {
const absl::optional<std::u16string>& placeholder =
action_button_to_placeholder_map_[action_buttons_[index]];
if (placeholder && inline_reply_) {
inline_reply_->SetTextfieldIndex(static_cast<int>(index));
inline_reply_->SetPlaceholderText(placeholder);
inline_reply_->AnimateBackground(event);
inline_reply_->SetVisible(true);
action_buttons_row_->SetVisible(false);
inline_reply_->textfield()->RequestFocus();
Layout();
SchedulePaint();
OnInlineReplyUpdated();
return;
}
MessageCenter::Get()->ClickOnNotificationButton(notification_id(),
static_cast<int>(index));
}
void NotificationViewBase::OnInlineReplyUpdated() {
}
bool NotificationViewBase::HasInlineReply(
const Notification& notification) const {
if (!inline_reply_)
return false;
auto buttons = notification.buttons();
const size_t index = inline_reply_->GetTextfieldIndex();
return index < buttons.size() && buttons[index].placeholder.has_value();
}
void NotificationViewBase::SetExpandButtonEnabled(bool enabled) {
if (!for_ash_notification_)
header_row_->SetExpandButtonEnabled(enabled);
}
void NotificationViewBase::UpdateViewForExpandedState(bool expanded) {
if (!for_ash_notification_)
header_row_->SetExpanded(expanded);
if (!image_container_view_->children().empty())
image_container_view_->SetVisible(expanded);
actions_row_->SetVisible(expanded &&
!action_buttons_row_->children().empty());
if (!expanded) {
action_buttons_row_->SetVisible(true);
if (inline_reply_)
inline_reply_->SetVisible(false);
}
for (size_t i = kMaxLinesForMessageLabel; i < item_views_.size(); ++i) {
item_views_[i]->SetVisible(expanded);
}
if (status_view_)
status_view_->SetVisible(expanded);
int max_items = expanded ? item_views_.size() : kMaxLinesForMessageLabel;
if (!for_ash_notification_ && list_items_count_ > max_items)
header_row_->SetOverflowIndicator(list_items_count_ - max_items);
else if (!item_views_.empty())
header_row_->SetSummaryText(std::u16string());
bool has_icon = IsIconViewShown();
right_content_->SetVisible(has_icon);
content_row_->InvalidateLayout();
}
void NotificationViewBase::ToggleInlineSettings(const ui::Event& event) {
bool inline_settings_visible = !settings_row_->GetVisible();
settings_row_->SetVisible(inline_settings_visible);
header_row_->SetDetailViewsVisible(!inline_settings_visible);
SetSettingMode(inline_settings_visible);
{
auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
SetExpanded(!inline_settings_visible);
if (!weak_ptr)
return;
}
}
NotificationControlButtonsView* NotificationViewBase::GetControlButtonsView()
const {
return control_buttons_view_;
}
bool NotificationViewBase::IsExpanded() const {
return expanded_;
}
void NotificationViewBase::SetExpanded(bool expanded) {
if (expanded_ == expanded)
return;
expanded_ = expanded;
UpdateViewForExpandedState(expanded_);
PreferredSizeChanged();
}
bool NotificationViewBase::IsManuallyExpandedOrCollapsed() const {
return MessageCenter::Get()->GetNotificationExpandState(notification_id()) !=
ExpandState::DEFAULT;
}
void NotificationViewBase::SetManuallyExpandedOrCollapsed(ExpandState state) {
MessageCenter::Get()->SetNotificationExpandState(notification_id(), state);
}
void NotificationViewBase::OnSettingsButtonPressed(const ui::Event& event) {
for (auto& observer : *observers())
observer.OnSettingsButtonPressed(notification_id());
if (inline_settings_enabled_)
ToggleInlineSettings(event);
else
MessageView::OnSettingsButtonPressed(event);
}
void NotificationViewBase::Activate() {
GetWidget()->widget_delegate()->SetCanActivate(true);
GetWidget()->Activate();
}
void NotificationViewBase::InkDropAnimationStarted() {
header_row_->SetSubpixelRenderingEnabled(false);
}
void NotificationViewBase::InkDropRippleAnimationEnded(
views::InkDropState ink_drop_state) {
if (ink_drop_state == views::InkDropState::HIDDEN)
header_row_->SetSubpixelRenderingEnabled(true);
}
}