Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/message_center/views/notification_view_md.h" | 5 #include "ui/message_center/views/notification_view_md.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
| 10 #include "ui/base/cursor/cursor.h" | 10 #include "ui/base/cursor/cursor.h" |
| 11 #include "ui/base/l10n/l10n_util.h" | 11 #include "ui/base/l10n/l10n_util.h" |
| 12 #include "ui/gfx/geometry/size.h" | 12 #include "ui/gfx/geometry/size.h" |
| 13 #include "ui/gfx/image/image_skia_operations.h" | 13 #include "ui/gfx/image/image_skia_operations.h" |
| 14 #include "ui/gfx/paint_vector_icon.h" | 14 #include "ui/gfx/paint_vector_icon.h" |
| 15 #include "ui/gfx/skia_util.h" | 15 #include "ui/gfx/skia_util.h" |
| 16 #include "ui/gfx/text_elider.h" | 16 #include "ui/gfx/text_elider.h" |
| 17 #include "ui/message_center/message_center.h" | 17 #include "ui/message_center/message_center.h" |
| 18 #include "ui/message_center/message_center_style.h" | 18 #include "ui/message_center/message_center_style.h" |
| 19 #include "ui/message_center/notification.h" | 19 #include "ui/message_center/notification.h" |
| 20 #include "ui/message_center/notification_types.h" | 20 #include "ui/message_center/notification_types.h" |
| 21 #include "ui/message_center/vector_icons.h" | 21 #include "ui/message_center/vector_icons.h" |
| 22 #include "ui/message_center/views/bounded_label.h" | 22 #include "ui/message_center/views/bounded_label.h" |
| 23 #include "ui/message_center/views/constants.h" | 23 #include "ui/message_center/views/constants.h" |
| 24 #include "ui/message_center/views/message_center_controller.h" | 24 #include "ui/message_center/views/message_center_controller.h" |
| 25 #include "ui/message_center/views/notification_button.h" | 25 #include "ui/message_center/views/notification_header_view.h" |
| 26 #include "ui/message_center/views/padded_button.h" | 26 #include "ui/message_center/views/padded_button.h" |
| 27 #include "ui/message_center/views/proportional_image_view.h" | |
| 27 #include "ui/strings/grit/ui_strings.h" | 28 #include "ui/strings/grit/ui_strings.h" |
| 28 #include "ui/views/background.h" | 29 #include "ui/views/background.h" |
| 29 #include "ui/views/border.h" | 30 #include "ui/views/border.h" |
| 31 #include "ui/views/controls/button/label_button.h" | |
| 30 #include "ui/views/controls/image_view.h" | 32 #include "ui/views/controls/image_view.h" |
| 31 #include "ui/views/controls/label.h" | 33 #include "ui/views/controls/label.h" |
| 32 #include "ui/views/focus/focus_manager.h" | 34 #include "ui/views/focus/focus_manager.h" |
| 33 #include "ui/views/layout/box_layout.h" | 35 #include "ui/views/layout/box_layout.h" |
| 36 #include "ui/views/layout/fill_layout.h" | |
| 34 #include "ui/views/native_cursor.h" | 37 #include "ui/views/native_cursor.h" |
| 35 #include "ui/views/view_targeter.h" | 38 #include "ui/views/view_targeter.h" |
| 39 #include "ui/views/widget/widget.h" | |
| 36 | 40 |
| 37 namespace message_center { | 41 namespace message_center { |
| 38 | 42 |
| 39 namespace { | 43 namespace { |
| 40 | 44 |
| 41 // Dimensions. | 45 // Dimensions. |
| 42 constexpr int kNotificationRightPadding = 13; | 46 constexpr gfx::Insets kContentRowPadding(4, 12, 12, 12); |
| 43 constexpr int kNotificationLeftPadding = 13; | 47 constexpr gfx::Insets kActionsRowPadding(8, 8, 8, 8); |
| 44 constexpr int kNotificationTopPadding = 6; | 48 constexpr int kActionsRowHorizontalSpacing = 8; |
| 45 constexpr int kNotificationBottomPadding = 10; | |
| 46 constexpr gfx::Insets kNotificationPadding(kNotificationTopPadding, | |
| 47 kNotificationLeftPadding, | |
| 48 kNotificationBottomPadding, | |
| 49 kNotificationRightPadding); | |
| 50 | |
| 51 constexpr int kMaxContextTitleLines = 1; | |
| 52 | 49 |
| 53 // Foreground of small icon image. | 50 // Foreground of small icon image. |
| 54 constexpr SkColor kSmallImageBackgroundColor = SK_ColorWHITE; | 51 constexpr SkColor kSmallImageBackgroundColor = SK_ColorWHITE; |
| 55 // Background of small icon image. | 52 // Background of small icon image. |
| 56 const SkColor kSmallImageColor = SkColorSetRGB(0x43, 0x43, 0x43); | 53 const SkColor kSmallImageColor = SkColorSetRGB(0x43, 0x43, 0x43); |
| 54 // Background of inline actions area. | |
| 55 const SkColor kActionsRowBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee); | |
| 56 | |
| 57 // Max number of lines for message_view_. | |
| 58 constexpr int kMaxLinesForMessageView = 1; | |
| 59 constexpr int kMaxLinesForExpandedMessageView = 4; | |
| 57 | 60 |
| 58 const gfx::ImageSkia CreateSolidColorImage(int width, | 61 const gfx::ImageSkia CreateSolidColorImage(int width, |
| 59 int height, | 62 int height, |
| 60 SkColor color) { | 63 SkColor color) { |
| 61 SkBitmap bitmap; | 64 SkBitmap bitmap; |
| 62 bitmap.allocN32Pixels(width, height); | 65 bitmap.allocN32Pixels(width, height); |
| 63 bitmap.eraseColor(color); | 66 bitmap.eraseColor(color); |
| 64 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); | 67 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); |
| 65 } | 68 } |
| 66 | 69 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 | 101 |
| 99 // TODO(tdanderson): Modify this function to support rect-based event | 102 // TODO(tdanderson): Modify this function to support rect-based event |
| 100 // targeting. Using the center point of |rect| preserves this function's | 103 // targeting. Using the center point of |rect| preserves this function's |
| 101 // expected behavior for the time being. | 104 // expected behavior for the time being. |
| 102 gfx::Point point = rect.CenterPoint(); | 105 gfx::Point point = rect.CenterPoint(); |
| 103 | 106 |
| 104 // Want to return this for underlying views, otherwise GetCursor is not | 107 // Want to return this for underlying views, otherwise GetCursor is not |
| 105 // called. But buttons are exceptions, they'll have their own event handlings. | 108 // called. But buttons are exceptions, they'll have their own event handlings. |
| 106 std::vector<views::View*> buttons(action_buttons_.begin(), | 109 std::vector<views::View*> buttons(action_buttons_.begin(), |
| 107 action_buttons_.end()); | 110 action_buttons_.end()); |
| 108 if (settings_button_) | 111 if (header_row_->settings_button()) |
| 109 buttons.push_back(settings_button_.get()); | 112 buttons.push_back(header_row_->settings_button()); |
| 110 if (close_button_) | 113 if (header_row_->close_button()) |
| 111 buttons.push_back(close_button_.get()); | 114 buttons.push_back(header_row_->close_button()); |
| 115 if (header_row_->expand_button()) | |
| 116 buttons.push_back(header_row_->expand_button()); | |
| 117 buttons.push_back(header_row_); | |
| 112 | 118 |
| 113 for (size_t i = 0; i < buttons.size(); ++i) { | 119 for (size_t i = 0; i < buttons.size(); ++i) { |
| 114 gfx::Point point_in_child = point; | 120 gfx::Point point_in_child = point; |
| 115 ConvertPointToTarget(this, buttons[i], &point_in_child); | 121 ConvertPointToTarget(this, buttons[i], &point_in_child); |
| 116 if (buttons[i]->HitTestPoint(point_in_child)) | 122 if (buttons[i]->HitTestPoint(point_in_child)) |
| 117 return buttons[i]->GetEventHandlerForPoint(point_in_child); | 123 return buttons[i]->GetEventHandlerForPoint(point_in_child); |
| 118 } | 124 } |
| 119 | 125 |
| 120 return root; | 126 return root; |
| 121 } | 127 } |
| 122 | 128 |
| 123 void NotificationViewMD::CreateOrUpdateViews(const Notification& notification) { | 129 void NotificationViewMD::CreateOrUpdateViews(const Notification& notification) { |
| 124 CreateOrUpdateContextTitleView(notification); | 130 CreateOrUpdateContextTitleView(notification); |
| 125 CreateOrUpdateTitleView(notification); | 131 CreateOrUpdateTitleView(notification); |
| 126 CreateOrUpdateMessageView(notification); | 132 CreateOrUpdateMessageView(notification); |
| 127 CreateOrUpdateProgressBarView(notification); | 133 CreateOrUpdateProgressBarView(notification); |
| 128 CreateOrUpdateListItemViews(notification); | 134 CreateOrUpdateListItemViews(notification); |
| 129 CreateOrUpdateIconView(notification); | 135 CreateOrUpdateIconView(notification); |
| 130 CreateOrUpdateSmallIconView(notification); | 136 CreateOrUpdateSmallIconView(notification); |
| 131 CreateOrUpdateImageView(notification); | 137 CreateOrUpdateImageView(notification); |
| 132 CreateOrUpdateActionButtonViews(notification); | 138 CreateOrUpdateActionButtonViews(notification); |
| 133 CreateOrUpdateCloseButtonView(notification); | 139 CreateOrUpdateCloseButtonView(notification); |
| 134 CreateOrUpdateSettingsButtonView(notification); | 140 CreateOrUpdateSettingsButtonView(notification); |
| 141 UpdateViewForExpandedState(expanded_); | |
| 135 } | 142 } |
| 136 | 143 |
| 137 NotificationViewMD::NotificationViewMD(MessageCenterController* controller, | 144 NotificationViewMD::NotificationViewMD(MessageCenterController* controller, |
| 138 const Notification& notification) | 145 const Notification& notification) |
| 139 : MessageView(controller, notification), | 146 : MessageView(controller, notification), |
| 140 clickable_(notification.clickable()) { | 147 clickable_(notification.clickable()) { |
| 141 layout_ = new views::BoxLayout(views::BoxLayout::kVertical, gfx::Insets(), 2); | 148 SetLayoutManager( |
| 142 layout_->set_inside_border_insets(kNotificationPadding); | 149 new views::BoxLayout(views::BoxLayout::kVertical, gfx::Insets(), 0)); |
| 143 SetLayoutManager(layout_); | |
| 144 | 150 |
| 145 // Create the top_view_, which collects into a vertical box all content | 151 // |header_row_| contains app_icon, app_name, control buttons, etc... |
| 146 // at the top of the notification (to the right of the icon) except for the | 152 header_row_ = new NotificationHeaderView(this); |
| 147 // close button. | 153 AddChildView(header_row_); |
| 148 top_view_ = new views::View(); | |
| 149 views::BoxLayout* top_box_layout = | |
| 150 new views::BoxLayout(views::BoxLayout::kHorizontal, gfx::Insets(1, 0), 5); | |
| 151 top_box_layout->set_cross_axis_alignment( | |
| 152 views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); | |
| 153 top_view_->SetLayoutManager(top_box_layout); | |
| 154 AddChildView(top_view_); | |
| 155 | 154 |
| 156 main_view_ = new views::View(); | 155 // |content_row_| contains title, message, image, progressbar, etc... |
| 157 main_view_->SetLayoutManager( | 156 content_row_ = new views::View(); |
| 158 new views::BoxLayout(views::BoxLayout::kVertical)); | 157 views::BoxLayout* content_row_layout = new views::BoxLayout( |
| 159 AddChildView(main_view_); | 158 views::BoxLayout::kHorizontal, kContentRowPadding, 0); |
| 159 content_row_layout->set_cross_axis_alignment( | |
| 160 views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); | |
| 161 content_row_->SetLayoutManager(content_row_layout); | |
| 162 AddChildView(content_row_); | |
| 160 | 163 |
| 161 // Create the bottom_view_, which collects notification icon. | 164 // |left_content_| contains most contents like title, message, etc... |
| 162 bottom_view_ = new views::View(); | 165 left_content_ = new views::View(); |
| 163 bottom_view_->SetLayoutManager( | 166 left_content_->SetLayoutManager( |
| 164 new views::BoxLayout(views::BoxLayout::kVertical)); | 167 new views::BoxLayout(views::BoxLayout::kVertical, gfx::Insets(), 0)); |
| 165 AddChildView(bottom_view_); | 168 content_row_layout->SetFlexForView(left_content_, 1); |
| 169 content_row_->AddChildView(left_content_); | |
| 166 | 170 |
| 167 views::ImageView* small_image_view = new views::ImageView(); | 171 // |right_content_| contains notification icon and small image. |
| 168 small_image_view->SetImageSize(gfx::Size(kSmallImageSize, kSmallImageSize)); | 172 right_content_ = new views::View(); |
| 169 small_image_view->set_owned_by_client(); | 173 right_content_->SetLayoutManager(new views::FillLayout()); |
| 170 small_image_view_.reset(small_image_view); | 174 content_row_->AddChildView(right_content_); |
| 171 top_view_->AddChildView(small_image_view_.get()); | 175 |
| 176 // |action_row_| contains inline action button. | |
| 177 actions_row_ = new views::View(); | |
| 178 actions_row_->SetLayoutManager( | |
| 179 new views::BoxLayout(views::BoxLayout::kHorizontal, kActionsRowPadding, | |
| 180 kActionsRowHorizontalSpacing)); | |
| 181 actions_row_->SetBackground( | |
| 182 views::CreateSolidBackground(kActionsRowBackgroundColor)); | |
| 183 actions_row_->SetVisible(false); | |
| 184 AddChildView(actions_row_); | |
| 172 | 185 |
| 173 CreateOrUpdateViews(notification); | 186 CreateOrUpdateViews(notification); |
| 174 | 187 |
| 175 SetEventTargeter( | 188 SetEventTargeter( |
| 176 std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); | 189 std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); |
| 177 } | 190 } |
| 178 | 191 |
| 179 NotificationViewMD::~NotificationViewMD() {} | 192 NotificationViewMD::~NotificationViewMD() {} |
| 180 | 193 |
| 181 void NotificationViewMD::Layout() { | 194 void NotificationViewMD::Layout() { |
| 182 MessageView::Layout(); | 195 MessageView::Layout(); |
| 183 | 196 |
| 184 // Before any resizing, set or adjust the number of message lines. | 197 // We need to call IsExpandable() at the end of Layout() call, since whether |
| 185 int title_lines = 0; | 198 // we should show expand button or not depends on the current view layout. |
| 186 if (title_view_) { | 199 // (e.g. Show expand button when |message_view_| exceeds one line.) |
| 187 title_lines = title_view_->GetLinesForWidthAndLimit(title_view_->width(), | 200 header_row_->SetExpandButtonEnabled(IsExpandable()); |
| 188 kMaxTitleLines); | |
| 189 } | |
| 190 if (message_view_) { | |
| 191 message_view_->SetLineLimit( | |
| 192 std::max(0, message_center::kMessageExpandedLineLimit - title_lines)); | |
| 193 } | |
| 194 | |
| 195 // Settings & Bottom views. | |
| 196 if (settings_button_) { | |
| 197 gfx::Rect content_bounds = GetContentsBounds(); | |
| 198 const gfx::Size settings_size(settings_button_->GetPreferredSize()); | |
| 199 int marginFromRight = settings_size.width() + kControlButtonPadding; | |
| 200 if (close_button_) | |
| 201 marginFromRight += close_button_->GetPreferredSize().width(); | |
| 202 gfx::Rect settings_rect(content_bounds.right() - marginFromRight, | |
| 203 GetContentsBounds().y() + kControlButtonPadding, | |
| 204 settings_size.width(), settings_size.height()); | |
| 205 settings_button_->SetBoundsRect(settings_rect); | |
| 206 } | |
| 207 | |
| 208 // Close button. | |
| 209 if (close_button_) { | |
| 210 gfx::Rect content_bounds = GetContentsBounds(); | |
| 211 gfx::Size close_size(close_button_->GetPreferredSize()); | |
| 212 gfx::Rect close_rect( | |
| 213 content_bounds.right() - close_size.width() - kControlButtonPadding, | |
| 214 content_bounds.y() + kControlButtonPadding, close_size.width(), | |
| 215 close_size.height()); | |
| 216 close_button_->SetBoundsRect(close_rect); | |
| 217 } | |
| 218 } | 201 } |
| 219 | 202 |
| 220 void NotificationViewMD::OnFocus() { | 203 void NotificationViewMD::OnFocus() { |
| 221 MessageView::OnFocus(); | 204 MessageView::OnFocus(); |
| 222 ScrollRectToVisible(GetLocalBounds()); | 205 ScrollRectToVisible(GetLocalBounds()); |
| 223 } | 206 } |
| 224 | 207 |
| 225 void NotificationViewMD::ScrollRectToVisible(const gfx::Rect& rect) { | 208 void NotificationViewMD::ScrollRectToVisible(const gfx::Rect& rect) { |
| 226 // Notification want to show the whole notification when a part of it (like | 209 // Notification want to show the whole notification when a part of it (like |
| 227 // a button) gets focused. | 210 // a button) gets focused. |
| 228 views::View::ScrollRectToVisible(GetLocalBounds()); | 211 views::View::ScrollRectToVisible(GetLocalBounds()); |
| 229 } | 212 } |
| 230 | 213 |
| 231 gfx::NativeCursor NotificationViewMD::GetCursor(const ui::MouseEvent& event) { | 214 gfx::NativeCursor NotificationViewMD::GetCursor(const ui::MouseEvent& event) { |
| 232 if (!clickable_ || !controller()->HasClickedListener(notification_id())) | 215 if (!clickable_ || !controller()->HasClickedListener(notification_id())) |
| 233 return views::View::GetCursor(event); | 216 return views::View::GetCursor(event); |
| 234 | 217 |
| 235 return views::GetNativeHandCursor(); | 218 return views::GetNativeHandCursor(); |
| 236 } | 219 } |
| 237 | 220 |
| 221 void NotificationViewMD::OnMouseMoved(const ui::MouseEvent& event) { | |
| 222 MessageView::OnMouseMoved(event); | |
| 223 UpdateControlButtonsVisibility(); | |
| 224 } | |
| 225 | |
| 238 void NotificationViewMD::OnMouseEntered(const ui::MouseEvent& event) { | 226 void NotificationViewMD::OnMouseEntered(const ui::MouseEvent& event) { |
| 239 MessageView::OnMouseEntered(event); | 227 MessageView::OnMouseEntered(event); |
| 240 UpdateControlButtonsVisibility(); | 228 UpdateControlButtonsVisibility(); |
| 241 } | 229 } |
| 242 | 230 |
| 243 void NotificationViewMD::OnMouseExited(const ui::MouseEvent& event) { | 231 void NotificationViewMD::OnMouseExited(const ui::MouseEvent& event) { |
| 244 MessageView::OnMouseExited(event); | 232 MessageView::OnMouseExited(event); |
| 245 UpdateControlButtonsVisibility(); | 233 UpdateControlButtonsVisibility(); |
| 246 } | 234 } |
| 247 | 235 |
| 248 void NotificationViewMD::UpdateWithNotification( | 236 void NotificationViewMD::UpdateWithNotification( |
| 249 const Notification& notification) { | 237 const Notification& notification) { |
| 250 MessageView::UpdateWithNotification(notification); | 238 MessageView::UpdateWithNotification(notification); |
| 251 | 239 |
| 252 CreateOrUpdateViews(notification); | 240 CreateOrUpdateViews(notification); |
| 253 Layout(); | 241 Layout(); |
| 254 SchedulePaint(); | 242 SchedulePaint(); |
| 255 } | 243 } |
| 256 | 244 |
| 257 void NotificationViewMD::ButtonPressed(views::Button* sender, | 245 void NotificationViewMD::ButtonPressed(views::Button* sender, |
| 258 const ui::Event& event) { | 246 const ui::Event& event) { |
| 259 // Certain operations can cause |this| to be destructed, so copy the members | 247 // Certain operations can cause |this| to be destructed, so copy the members |
| 260 // we send to other parts of the code. | 248 // we send to other parts of the code. |
| 261 // TODO(dewittj): Remove this hack. | 249 // TODO(dewittj): Remove this hack. |
| 262 std::string id(notification_id()); | 250 std::string id(notification_id()); |
| 263 | 251 |
| 264 if (close_button_ && sender == close_button_.get()) { | 252 if (header_row_->IsCloseButtonEnabled() && |
| 253 sender == header_row_->close_button()) { | |
| 265 // Warning: This causes the NotificationViewMD itself to be deleted, so | 254 // Warning: This causes the NotificationViewMD itself to be deleted, so |
| 266 // don't do anything afterwards. | 255 // don't do anything afterwards. |
| 267 OnCloseButtonPressed(); | 256 OnCloseButtonPressed(); |
| 268 return; | 257 return; |
| 269 } | 258 } |
| 270 | 259 |
| 271 if (sender == settings_button_.get()) { | 260 if (header_row_->IsSettingsButtonEnabled() && |
| 261 sender == header_row_->settings_button()) { | |
| 272 controller()->ClickOnSettingsButton(id); | 262 controller()->ClickOnSettingsButton(id); |
| 273 return; | 263 return; |
| 274 } | 264 } |
| 275 | 265 |
| 266 // Tapping anywhere on |header_row_| can expand the notification, though only | |
| 267 // |expand_button| can be focused by TAB. | |
| 268 if (IsExpandable() && | |
| 269 (sender == header_row_ || sender == header_row_->expand_button())) { | |
| 270 ToggleExpanded(); | |
| 271 Layout(); | |
| 272 SchedulePaint(); | |
| 273 return; | |
| 274 } | |
| 275 | |
| 276 // See if the button pressed was an action button. | 276 // See if the button pressed was an action button. |
| 277 for (size_t i = 0; i < action_buttons_.size(); ++i) { | 277 for (size_t i = 0; i < action_buttons_.size(); ++i) { |
| 278 if (sender == action_buttons_[i]) { | 278 if (sender == action_buttons_[i]) { |
| 279 controller()->ClickOnNotificationButton(id, i); | 279 controller()->ClickOnNotificationButton(id, i); |
| 280 return; | 280 return; |
| 281 } | 281 } |
| 282 } | 282 } |
| 283 } | 283 } |
| 284 | 284 |
| 285 bool NotificationViewMD::IsCloseButtonFocused() const { | 285 bool NotificationViewMD::IsCloseButtonFocused() const { |
| 286 if (!close_button_) | 286 if (!header_row_->IsCloseButtonEnabled()) |
| 287 return false; | 287 return false; |
| 288 | 288 |
| 289 const views::FocusManager* focus_manager = GetFocusManager(); | 289 const views::FocusManager* focus_manager = GetFocusManager(); |
| 290 return focus_manager && | 290 return focus_manager && |
| 291 focus_manager->GetFocusedView() == close_button_.get(); | 291 focus_manager->GetFocusedView() == header_row_->close_button(); |
| 292 } | 292 } |
| 293 | 293 |
| 294 void NotificationViewMD::RequestFocusOnCloseButton() { | 294 void NotificationViewMD::RequestFocusOnCloseButton() { |
| 295 if (close_button_) | 295 if (header_row_->IsCloseButtonEnabled()) |
| 296 close_button_->RequestFocus(); | 296 header_row_->close_button()->RequestFocus(); |
| 297 } | 297 } |
| 298 | 298 |
| 299 void NotificationViewMD::CreateOrUpdateContextTitleView( | 299 void NotificationViewMD::CreateOrUpdateContextTitleView( |
| 300 const Notification& notification) { | 300 const Notification& notification) { |
| 301 DCHECK(top_view_); | 301 header_row_->SetAppName(notification.display_source()); |
| 302 | |
| 303 const gfx::FontList& font_list = views::Label().font_list().Derive( | |
| 304 -2, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL); | |
| 305 | |
| 306 base::string16 sub_title = notification.display_source(); | |
| 307 if (!context_title_view_) { | |
| 308 context_title_view_ = new BoundedLabel(sub_title, font_list); | |
| 309 context_title_view_->SetLineHeight(kTitleLineHeight); | |
| 310 context_title_view_->SetLineLimit(kMaxContextTitleLines); | |
| 311 top_view_->AddChildView(context_title_view_); | |
| 312 } else { | |
| 313 context_title_view_->SetText(sub_title); | |
| 314 } | |
| 315 } | 302 } |
| 316 | 303 |
| 317 void NotificationViewMD::CreateOrUpdateTitleView( | 304 void NotificationViewMD::CreateOrUpdateTitleView( |
| 318 const Notification& notification) { | 305 const Notification& notification) { |
| 319 DCHECK(top_view_ != NULL); | |
| 320 | |
| 321 const gfx::FontList& font_list = views::Label().font_list().Derive( | 306 const gfx::FontList& font_list = views::Label().font_list().Derive( |
| 322 1, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL); | 307 1, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL); |
| 323 | 308 |
| 324 int title_character_limit = | 309 int title_character_limit = |
| 325 kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacter; | 310 kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacter; |
| 326 | 311 |
| 327 base::string16 title = gfx::TruncateString( | 312 base::string16 title = gfx::TruncateString( |
| 328 notification.title(), title_character_limit, gfx::WORD_BREAK); | 313 notification.title(), title_character_limit, gfx::WORD_BREAK); |
| 329 if (!title_view_) { | 314 if (!title_view_) { |
| 330 title_view_ = new BoundedLabel(title, font_list); | 315 title_view_ = new views::Label(title); |
| 331 title_view_->SetLineHeight(kMessageLineHeight); | 316 title_view_->SetFontList(font_list); |
| 332 title_view_->SetColors(message_center::kRegularTextColor, | 317 title_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| 333 kDimTextBackgroundColor); | 318 title_view_->SetEnabledColor(message_center::kRegularTextColor); |
| 334 main_view_->AddChildView(title_view_); | 319 left_content_->AddChildView(title_view_); |
| 335 } else { | 320 } else { |
| 336 title_view_->SetText(title); | 321 title_view_->SetText(title); |
| 337 } | 322 } |
| 338 } | 323 } |
| 339 | 324 |
| 340 void NotificationViewMD::CreateOrUpdateMessageView( | 325 void NotificationViewMD::CreateOrUpdateMessageView( |
| 341 const Notification& notification) { | 326 const Notification& notification) { |
| 342 if (notification.message().empty()) { | 327 if (notification.message().empty()) { |
| 343 // Deletion will also remove |context_message_view_| from its parent. | 328 // Deletion will also remove |context_message_view_| from its parent. |
| 344 delete message_view_; | 329 delete message_view_; |
| 345 message_view_ = nullptr; | 330 message_view_ = nullptr; |
| 346 return; | 331 return; |
| 347 } | 332 } |
| 348 | 333 |
| 349 DCHECK(top_view_ != NULL); | |
| 350 | |
| 351 base::string16 text = gfx::TruncateString( | 334 base::string16 text = gfx::TruncateString( |
| 352 notification.message(), kMessageCharacterLimit, gfx::WORD_BREAK); | 335 notification.message(), kMessageCharacterLimit, gfx::WORD_BREAK); |
| 353 | 336 |
| 354 const gfx::FontList& font_list = views::Label().font_list().Derive( | 337 const gfx::FontList& font_list = views::Label().font_list().Derive( |
| 355 1, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL); | 338 1, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL); |
| 356 | 339 |
| 357 if (!message_view_) { | 340 if (!message_view_) { |
| 358 message_view_ = new BoundedLabel(text, font_list); | 341 message_view_ = new BoundedLabel(text, font_list); |
| 359 message_view_->SetLineLimit(message_center::kMessageExpandedLineLimit); | 342 message_view_->SetLineLimit(kMaxLinesForMessageView); |
| 360 message_view_->SetColors(message_center::kDimTextColor, | 343 message_view_->SetColors(message_center::kDimTextColor, |
| 361 kContextTextBackgroundColor); | 344 kContextTextBackgroundColor); |
| 362 main_view_->AddChildView(message_view_); | 345 left_content_->AddChildView(message_view_); |
| 363 } else { | 346 } else { |
| 364 message_view_->SetText(text); | 347 message_view_->SetText(text); |
| 365 } | 348 } |
| 366 } | 349 } |
| 367 | 350 |
| 368 void NotificationViewMD::CreateOrUpdateProgressBarView( | 351 void NotificationViewMD::CreateOrUpdateProgressBarView( |
| 369 const Notification& notification) { | 352 const Notification& notification) { |
| 370 // TODO(yoshiki): Implement this. | 353 // TODO(yoshiki): Implement this. |
| 371 } | 354 } |
| 372 | 355 |
| 373 void NotificationViewMD::CreateOrUpdateListItemViews( | 356 void NotificationViewMD::CreateOrUpdateListItemViews( |
| 374 const Notification& notification) { | 357 const Notification& notification) { |
| 375 // TODO(yoshiki): Implement this. | 358 // TODO(yoshiki): Implement this. |
| 376 } | 359 } |
| 377 | 360 |
| 378 void NotificationViewMD::CreateOrUpdateIconView( | 361 void NotificationViewMD::CreateOrUpdateIconView( |
| 379 const Notification& notification) { | 362 const Notification& notification) { |
| 380 // TODO(yoshiki): Implement this. | 363 gfx::Size image_view_size(30, 30); |
| 364 if (!icon_view_) { | |
| 365 icon_view_ = new ProportionalImageView(image_view_size); | |
| 366 right_content_->AddChildView(icon_view_); | |
| 367 } | |
| 368 | |
| 369 gfx::ImageSkia icon = notification.icon().AsImageSkia(); | |
| 370 icon_view_->SetImage(icon, icon.size()); | |
| 381 } | 371 } |
| 382 | 372 |
| 383 void NotificationViewMD::CreateOrUpdateSmallIconView( | 373 void NotificationViewMD::CreateOrUpdateSmallIconView( |
| 384 const Notification& notification) { | 374 const Notification& notification) { |
| 385 gfx::ImageSkia icon = | 375 gfx::ImageSkia icon = |
| 386 notification.small_image().IsEmpty() | 376 notification.small_image().IsEmpty() |
| 387 ? GetProductIcon() | 377 ? GetProductIcon() |
| 388 : GetMaskedIcon(notification.small_image().AsImageSkia()); | 378 : GetMaskedIcon(notification.small_image().AsImageSkia()); |
| 389 | 379 header_row_->SetAppIcon(icon); |
| 390 small_image_view_->SetImage(icon); | |
| 391 } | 380 } |
| 392 | 381 |
| 393 void NotificationViewMD::CreateOrUpdateImageView( | 382 void NotificationViewMD::CreateOrUpdateImageView( |
| 394 const Notification& notification) { | 383 const Notification& notification) { |
| 395 // TODO(yoshiki): Implement this. | 384 // |image_view_| is the view representing the area covered by the |
| 385 // notification's image, including background and border. Its size can be | |
| 386 // specified in advance and images will be scaled to fit including a border if | |
| 387 // necessary. | |
| 388 if (notification.image().IsEmpty()) { | |
| 389 delete image_container_; | |
|
yoshiki
2017/06/09 08:48:25
How about remote image_container_ from the parent,
fukino
2017/06/09 09:26:33
Done.
Thank you for pointing it out.
| |
| 390 image_container_ = NULL; | |
| 391 image_view_ = NULL; | |
| 392 return; | |
| 393 } | |
| 394 | |
| 395 gfx::Size ideal_size(kNotificationPreferredImageWidth, | |
| 396 kNotificationPreferredImageHeight); | |
| 397 | |
| 398 if (!image_container_) { | |
| 399 image_container_ = new views::View(); | |
| 400 image_container_->SetLayoutManager(new views::FillLayout()); | |
| 401 image_container_->SetBackground( | |
| 402 views::CreateSolidBackground(message_center::kImageBackgroundColor)); | |
| 403 | |
| 404 image_view_ = new message_center::ProportionalImageView(ideal_size); | |
| 405 image_container_->AddChildView(image_view_); | |
| 406 left_content_->AddChildView(image_container_); | |
|
yoshiki
2017/06/09 08:48:25
Shouldn't we add the image container into the left
fukino
2017/06/09 09:26:32
The big image is shown only when the notification
fukino
2017/06/12 09:07:38
According to the Android current behavior, the not
| |
| 407 } | |
| 408 | |
| 409 DCHECK(image_view_); | |
| 410 image_view_->SetImage(notification.image().AsImageSkia(), ideal_size); | |
| 396 } | 411 } |
| 397 | 412 |
| 398 void NotificationViewMD::CreateOrUpdateActionButtonViews( | 413 void NotificationViewMD::CreateOrUpdateActionButtonViews( |
| 399 const Notification& notification) { | 414 const Notification& notification) { |
| 400 // TODO(yoshiki): Implement this. | 415 std::vector<ButtonInfo> buttons = notification.buttons(); |
| 416 bool new_buttons = action_buttons_.size() != buttons.size(); | |
| 417 | |
| 418 if (new_buttons || buttons.size() == 0) { | |
| 419 for (auto* item : action_buttons_) | |
| 420 delete item; | |
| 421 action_buttons_.clear(); | |
| 422 } | |
| 423 | |
| 424 DCHECK_EQ(this, actions_row_->parent()); | |
| 425 | |
| 426 for (size_t i = 0; i < buttons.size(); ++i) { | |
| 427 ButtonInfo button_info = buttons[i]; | |
| 428 if (new_buttons) { | |
| 429 views::LabelButton* button = new views::LabelButton( | |
| 430 this, button_info.title, views::style::CONTEXT_BUTTON_MD); | |
| 431 button->SetFocusForPlatform(); | |
| 432 action_buttons_.push_back(button); | |
| 433 actions_row_->AddChildView(button); | |
| 434 } else { | |
| 435 action_buttons_[i]->SetText(button_info.title); | |
| 436 action_buttons_[i]->SchedulePaint(); | |
| 437 action_buttons_[i]->Layout(); | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 if (new_buttons) { | |
| 442 Layout(); | |
|
yoshiki
2017/06/09 08:48:25
Is this Layout necessary?
fukino
2017/06/09 09:26:33
I blindly copied it from notification_view.
https:
| |
| 443 views::Widget* widget = GetWidget(); | |
| 444 if (widget != NULL) { | |
| 445 widget->SetSize(widget->GetContentsView()->GetPreferredSize()); | |
| 446 GetWidget()->SynthesizeMouseMoveEvent(); | |
| 447 } | |
| 448 } | |
| 401 } | 449 } |
| 402 | 450 |
| 403 void NotificationViewMD::CreateOrUpdateCloseButtonView( | 451 void NotificationViewMD::CreateOrUpdateCloseButtonView( |
| 404 const Notification& notification) { | 452 const Notification& notification) { |
| 405 if (!notification.pinned() && !close_button_) { | 453 if (!notification.pinned()) { |
| 406 close_button_ = base::MakeUnique<PaddedButton>(this); | 454 header_row_->SetCloseButtonEnabled(true); |
| 407 close_button_->SetImage(views::Button::STATE_NORMAL, GetCloseIcon()); | 455 } else { |
| 408 close_button_->SetAccessibleName(l10n_util::GetStringUTF16( | 456 header_row_->SetCloseButtonEnabled(false); |
| 409 IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME)); | |
| 410 close_button_->SetTooltipText(l10n_util::GetStringUTF16( | |
| 411 IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_TOOLTIP)); | |
| 412 close_button_->set_owned_by_client(); | |
| 413 AddChildView(close_button_.get()); | |
| 414 UpdateControlButtonsVisibility(); | |
| 415 } else if (notification.pinned() && close_button_) { | |
| 416 close_button_.reset(); | |
| 417 } | 457 } |
| 418 } | 458 } |
| 419 | 459 |
| 420 void NotificationViewMD::CreateOrUpdateSettingsButtonView( | 460 void NotificationViewMD::CreateOrUpdateSettingsButtonView( |
| 421 const Notification& notification) { | 461 const Notification& notification) { |
| 422 if (!settings_button_ && notification.delegate() && | 462 if (notification.delegate() && |
| 423 notification.delegate()->ShouldDisplaySettingsButton()) { | 463 notification.delegate()->ShouldDisplaySettingsButton()) { |
|
yoshiki
2017/06/09 08:48:25
nit: braces are not necessary
fukino
2017/06/09 09:26:33
Done.
| |
| 424 settings_button_ = base::MakeUnique<PaddedButton>(this); | 464 header_row_->SetSettingsButtonEnabled(true); |
| 425 settings_button_->SetImage(views::Button::STATE_NORMAL, GetSettingsIcon()); | |
| 426 settings_button_->SetAccessibleName(l10n_util::GetStringUTF16( | |
| 427 IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME)); | |
| 428 settings_button_->SetTooltipText(l10n_util::GetStringUTF16( | |
| 429 IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME)); | |
| 430 settings_button_->set_owned_by_client(); | |
| 431 AddChildView(settings_button_.get()); | |
| 432 } else { | 465 } else { |
| 433 settings_button_.reset(); | 466 header_row_->SetSettingsButtonEnabled(false); |
| 434 } | 467 } |
| 435 UpdateControlButtonsVisibility(); | 468 } |
| 469 | |
| 470 bool NotificationViewMD::IsExpandable() { | |
| 471 // Expandable if the message exceeds one line. | |
| 472 if (message_view_ && message_view_->visible() && | |
| 473 message_view_->GetLinesForWidthAndLimit(message_view_->width(), -1) > 1) { | |
| 474 return true; | |
| 475 } | |
| 476 // Expandable if there is at least one inline action. | |
| 477 if (actions_row_->has_children()) | |
| 478 return true; | |
| 479 | |
| 480 // Expandable if the notification has image. | |
| 481 if (image_view_) | |
| 482 return true; | |
| 483 | |
| 484 // TODO(fukino): Expandable if both progress bar and message exist. | |
| 485 | |
| 486 return false; | |
| 487 } | |
| 488 | |
| 489 void NotificationViewMD::ToggleExpanded() { | |
| 490 expanded_ = !expanded_; | |
| 491 UpdateViewForExpandedState(expanded_); | |
| 492 content_row_->InvalidateLayout(); | |
| 493 if (controller()) | |
| 494 controller()->UpdateNotificationSize(notification_id()); | |
| 495 } | |
| 496 | |
| 497 void NotificationViewMD::UpdateViewForExpandedState(bool expanded) { | |
| 498 header_row_->SetExpanded(expanded); | |
| 499 if (message_view_) { | |
| 500 message_view_->SetLineLimit(expanded ? kMaxLinesForExpandedMessageView | |
| 501 : kMaxLinesForMessageView); | |
| 502 } | |
| 503 right_content_->SetVisible(!expanded); | |
| 504 if (image_container_) | |
| 505 image_container_->SetVisible(expanded); | |
| 506 actions_row_->SetVisible(expanded && actions_row_->has_children()); | |
| 436 } | 507 } |
| 437 | 508 |
| 438 void NotificationViewMD::UpdateControlButtonsVisibility() { | 509 void NotificationViewMD::UpdateControlButtonsVisibility() { |
| 439 const bool target_visibility = | 510 const bool target_visibility = IsMouseHovered() || HasFocusedView(); |
| 440 IsMouseHovered() || HasFocus() || | 511 header_row_->SetControlButtonsVisible(target_visibility); |
| 441 (close_button_ && close_button_->HasFocus()) || | 512 } |
| 442 (settings_button_ && settings_button_->HasFocus()); | |
| 443 | 513 |
| 444 if (close_button_) { | 514 bool NotificationViewMD::HasFocusedView() { |
| 445 if (target_visibility != close_button_->visible()) | 515 const views::FocusManager* focus_manager = GetFocusManager(); |
| 446 close_button_->SetVisible(target_visibility); | 516 return focus_manager && Contains(focus_manager->GetFocusedView()); |
| 447 } | |
| 448 | |
| 449 if (settings_button_) { | |
| 450 if (target_visibility != settings_button_->visible()) | |
| 451 settings_button_->SetVisible(target_visibility); | |
| 452 } | |
| 453 } | 517 } |
| 454 | 518 |
| 455 } // namespace message_center | 519 } // namespace message_center |
| OLD | NEW |