1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/system/message_center/notification_swipe_control_view.h"
6
7 #include "ash/system/message_center/message_center_style.h"
8 #include "ash/system/message_center/metrics_utils.h"
9 #include "ui/base/l10n/l10n_util.h"
10 #include "ui/events/event.h"
11 #include "ui/gfx/color_palette.h"
12 #include "ui/gfx/paint_vector_icon.h"
13 #include "ui/message_center/vector_icons.h"
14 #include "ui/message_center/views/message_view.h"
15 #include "ui/message_center/views/notification_background_painter.h"
16 #include "ui/message_center/views/notification_control_buttons_view.h"
17 #include "ui/strings/grit/ui_strings.h"
18 #include "ui/views/background.h"
19 #include "ui/views/layout/box_layout.h"
20
21 namespace ash {
22
23 const char NotificationSwipeControlView::kViewClassName[] =
24 "NotificationSwipeControlView";
25
NotificationSwipeControlView(message_center::MessageView * message_view)26 NotificationSwipeControlView::NotificationSwipeControlView(
27 message_center::MessageView* message_view)
28 : message_view_(message_view) {
29 auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
30 views::BoxLayout::Orientation::kHorizontal,
31 gfx::Insets(message_center_style::kSwipeControlButtonVerticalMargin,
32 message_center_style::kSwipeControlButtonHorizontalMargin),
33 message_center_style::kSwipeControlButtonHorizontalMargin));
34 layout->set_cross_axis_alignment(
35 views::BoxLayout::CrossAxisAlignment::kStart);
36 layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kEnd);
37
38 // Draw on its own layer to round corners
39 SetPaintToLayer();
40 layer()->SetFillsBoundsOpaquely(false);
41 }
42
43 NotificationSwipeControlView::~NotificationSwipeControlView() = default;
44
ShowButtons(ButtonPosition button_position,bool show_settings,bool show_snooze)45 void NotificationSwipeControlView::ShowButtons(ButtonPosition button_position,
46 bool show_settings,
47 bool show_snooze) {
48 views::BoxLayout* layout = static_cast<views::BoxLayout*>(GetLayoutManager());
49 if ((button_position == ButtonPosition::RIGHT) != base::i18n::IsRTL()) {
50 layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kEnd);
51 } else {
52 layout->set_main_axis_alignment(
53 views::BoxLayout::MainAxisAlignment::kStart);
54 }
55 ShowSettingsButton(show_settings);
56 ShowSnoozeButton(show_snooze);
57 Layout();
58 }
59
HideButtons()60 void NotificationSwipeControlView::HideButtons() {
61 ShowSettingsButton(false);
62 ShowSnoozeButton(false);
63 Layout();
64 }
65
UpdateButtonsVisibility()66 void NotificationSwipeControlView::UpdateButtonsVisibility() {
67 float gesture_amount = message_view_->GetSlideAmount();
68 if (gesture_amount == 0) {
69 HideButtons();
70 return;
71 }
72
73 NotificationSwipeControlView::ButtonPosition button_position =
74 gesture_amount < 0 ? NotificationSwipeControlView::ButtonPosition::RIGHT
75 : NotificationSwipeControlView::ButtonPosition::LEFT;
76 message_center::NotificationControlButtonsView* buttons =
77 message_view_->GetControlButtonsView();
78 // Ignore when GetControlButtonsView() returns null.
79 if (!buttons)
80 return;
81 bool has_settings_button = buttons->settings_button();
82 bool has_snooze_button = buttons->snooze_button();
83 ShowButtons(button_position, has_settings_button, has_snooze_button);
84
85 int control_button_count =
86 (has_settings_button ? 1 : 0) + (has_snooze_button ? 1 : 0);
87 int control_button_width =
88 message_center_style::kSwipeControlButtonSize * control_button_count +
89 message_center_style::kSwipeControlButtonHorizontalMargin *
90 (control_button_count ? control_button_count + 1 : 0);
91 message_view_->SetSlideButtonWidth(control_button_width);
92
93 // Update opacity based on the swipe progress. The swipe controls should
94 // gradually disappear as the user swipes the notification away.
95 float full_opacity_width =
96 message_center_style::kSwipeControlFullOpacityRatio *
97 control_button_width;
98 float fade_out_width = message_view_->width() - full_opacity_width;
99 DCHECK(fade_out_width > 0);
100 float swipe_progress = std::max(
101 0.0f, (fabs(gesture_amount) - full_opacity_width) / fade_out_width);
102 float opacity = std::max(0.0f, 1.0f - swipe_progress);
103
104 layer()->SetOpacity(opacity);
105 }
106
UpdateCornerRadius(int top_radius,int bottom_radius)107 void NotificationSwipeControlView::UpdateCornerRadius(int top_radius,
108 int bottom_radius) {
109 SetBackground(views::CreateBackgroundFromPainter(
110 std::make_unique<message_center::NotificationBackgroundPainter>(
111 top_radius, bottom_radius,
112 message_center_style::kSwipeControlBackgroundColor)));
113 SchedulePaint();
114 }
115
ShowSettingsButton(bool show)116 void NotificationSwipeControlView::ShowSettingsButton(bool show) {
117 if (show && !settings_button_) {
118 settings_button_ = new views::ImageButton(
119 base::BindRepeating(&NotificationSwipeControlView::ButtonPressed,
120 base::Unretained(this), ButtonId::kSettings));
121 settings_button_->SetImage(
122 views::Button::STATE_NORMAL,
123 gfx::CreateVectorIcon(
124 message_center::kNotificationSettingsButtonIcon,
125 message_center_style::kSwipeControlButtonImageSize,
126 gfx::kChromeIconGrey));
127 settings_button_->SetImageHorizontalAlignment(
128 views::ImageButton::ALIGN_CENTER);
129 settings_button_->SetImageVerticalAlignment(
130 views::ImageButton::ALIGN_MIDDLE);
131 settings_button_->SetPreferredSize(
132 gfx::Size(message_center_style::kSwipeControlButtonSize,
133 message_center_style::kSwipeControlButtonSize));
134
135 settings_button_->SetAccessibleName(l10n_util::GetStringUTF16(
136 IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
137 settings_button_->SetTooltipText(l10n_util::GetStringUTF16(
138 IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
139 settings_button_->SetBackground(
140 views::CreateSolidBackground(SK_ColorTRANSPARENT));
141 settings_button_->SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
142
143 AddChildView(settings_button_);
144 Layout();
145 } else if (!show && settings_button_) {
146 DCHECK(Contains(settings_button_));
147 delete settings_button_;
148 settings_button_ = nullptr;
149 }
150 }
151
ShowSnoozeButton(bool show)152 void NotificationSwipeControlView::ShowSnoozeButton(bool show) {
153 if (show && !snooze_button_) {
154 snooze_button_ = new views::ImageButton(
155 base::BindRepeating(&NotificationSwipeControlView::ButtonPressed,
156 base::Unretained(this), ButtonId::kSnooze));
157 snooze_button_->SetImage(
158 views::Button::STATE_NORMAL,
159 gfx::CreateVectorIcon(
160 message_center::kNotificationSnoozeButtonIcon,
161 message_center_style::kSwipeControlButtonImageSize,
162 gfx::kChromeIconGrey));
163 snooze_button_->SetImageHorizontalAlignment(
164 views::ImageButton::ALIGN_CENTER);
165 snooze_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
166 snooze_button_->SetPreferredSize(
167 gfx::Size(message_center_style::kSwipeControlButtonSize,
168 message_center_style::kSwipeControlButtonSize));
169
170 snooze_button_->SetAccessibleName(l10n_util::GetStringUTF16(
171 IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
172 snooze_button_->SetTooltipText(l10n_util::GetStringUTF16(
173 IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
174 snooze_button_->SetBackground(
175 views::CreateSolidBackground(SK_ColorTRANSPARENT));
176 snooze_button_->SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
177
178 AddChildViewAt(snooze_button_, 0);
179 Layout();
180 } else if (!show && snooze_button_) {
181 DCHECK(Contains(snooze_button_));
182 delete snooze_button_;
183 snooze_button_ = nullptr;
184 }
185 }
186
GetClassName() const187 const char* NotificationSwipeControlView::GetClassName() const {
188 return kViewClassName;
189 }
190
ButtonPressed(ButtonId button,const ui::Event & event)191 void NotificationSwipeControlView::ButtonPressed(ButtonId button,
192 const ui::Event& event) {
193 auto weak_this = weak_factory_.GetWeakPtr();
194
195 const std::string notification_id = message_view_->notification_id();
196 if (button == ButtonId::kSettings) {
197 message_view_->OnSettingsButtonPressed(event);
198 metrics_utils::LogSettingsShown(notification_id,
199 /*is_slide_controls=*/true,
200 /*is_popup=*/false);
201 } else {
202 message_view_->OnSnoozeButtonPressed(event);
203 metrics_utils::LogSnoozed(notification_id,
204 /*is_slide_controls=*/true,
205 /*is_popup=*/false);
206 }
207
208 // Button handlers of |message_view_| may have closed |this|.
209 if (!weak_this)
210 return;
211
212 HideButtons();
213
214 // Closing the swipe control is done in these button pressed handlers.
215 // Otherwise, handlers might not work.
216 message_view_->CloseSwipeControl();
217 }
218
219 } // namespace ash
220