Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(447)

Unified Diff: ui/message_center/views/notification_view_md.cc

Issue 2892893002: Initial implementation of new-style notification (Closed)
Patch Set: addressed comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/message_center/views/notification_view_md.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/message_center/views/notification_view_md.cc
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5bc79bc9a6ec7150cd32af78df7421cb7ea801c4
--- /dev/null
+++ b/ui/message_center/views/notification_view_md.cc
@@ -0,0 +1,455 @@
+// Copyright 2017 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 "ui/message_center/views/notification_view_md.h"
+
+#include <stddef.h>
+
+#include "base/strings/string_util.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/text_elider.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/message_center_style.h"
+#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_types.h"
+#include "ui/message_center/vector_icons.h"
+#include "ui/message_center/views/bounded_label.h"
+#include "ui/message_center/views/constants.h"
+#include "ui/message_center/views/message_center_controller.h"
+#include "ui/message_center/views/notification_button.h"
+#include "ui/message_center/views/padded_button.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/native_cursor.h"
+#include "ui/views/view_targeter.h"
+
+namespace message_center {
+
+namespace {
+
+// Dimensions.
+constexpr int kNotificationRightPadding = 13;
+constexpr int kNotificationLeftPadding = 13;
+constexpr int kNotificationTopPadding = 6;
+constexpr int kNotificationBottomPadding = 10;
+constexpr gfx::Insets kNotificationPadding(kNotificationTopPadding,
+ kNotificationLeftPadding,
+ kNotificationBottomPadding,
+ kNotificationRightPadding);
+
+constexpr int kMaxContextTitleLines = 1;
+
+// Foreground of small icon image.
+constexpr SkColor kSmallImageBackgroundColor = SK_ColorWHITE;
+// Background of small icon image.
+const SkColor kSmallImageColor = SkColorSetRGB(0x43, 0x43, 0x43);
+
+const gfx::ImageSkia CreateSolidColorImage(int width,
+ int height,
+ SkColor color) {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(width, height);
+ bitmap.eraseColor(color);
+ return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+}
+
+// Take the alpha channel of icon, mask it with the foreground,
+// then add the masked foreground on top of the background
+const gfx::ImageSkia GetMaskedIcon(const gfx::ImageSkia& icon) {
+ int width = icon.width();
+ int height = icon.height();
+
+ // Background color grey
+ const gfx::ImageSkia background = CreateSolidColorImage(
+ width, height, message_center::kSmallImageBackgroundColor);
+ // Foreground color white
+ const gfx::ImageSkia foreground =
+ CreateSolidColorImage(width, height, message_center::kSmallImageColor);
+ const gfx::ImageSkia masked_small_image =
+ gfx::ImageSkiaOperations::CreateMaskedImage(foreground, icon);
+ return gfx::ImageSkiaOperations::CreateSuperimposedImage(background,
+ masked_small_image);
+}
+
+const gfx::ImageSkia GetProductIcon() {
+ return gfx::CreateVectorIcon(kProductIcon, kSmallImageColor);
+}
+
+} // anonymous namespace
+
+// ////////////////////////////////////////////////////////////
+// NotificationViewMD
+// ////////////////////////////////////////////////////////////
+
+views::View* NotificationViewMD::TargetForRect(views::View* root,
+ const gfx::Rect& rect) {
+ CHECK_EQ(root, this);
+
+ // TODO(tdanderson): Modify this function to support rect-based event
+ // targeting. Using the center point of |rect| preserves this function's
+ // expected behavior for the time being.
+ gfx::Point point = rect.CenterPoint();
+
+ // Want to return this for underlying views, otherwise GetCursor is not
+ // called. But buttons are exceptions, they'll have their own event handlings.
+ std::vector<views::View*> buttons(action_buttons_.begin(),
+ action_buttons_.end());
+ if (settings_button_)
+ buttons.push_back(settings_button_.get());
+ if (close_button_)
+ buttons.push_back(close_button_.get());
+
+ for (size_t i = 0; i < buttons.size(); ++i) {
+ gfx::Point point_in_child = point;
+ ConvertPointToTarget(this, buttons[i], &point_in_child);
+ if (buttons[i]->HitTestPoint(point_in_child))
+ return buttons[i]->GetEventHandlerForPoint(point_in_child);
+ }
+
+ return root;
+}
+
+void NotificationViewMD::CreateOrUpdateViews(const Notification& notification) {
+ CreateOrUpdateContextTitleView(notification);
+ CreateOrUpdateTitleView(notification);
+ CreateOrUpdateMessageView(notification);
+ CreateOrUpdateProgressBarView(notification);
+ CreateOrUpdateListItemViews(notification);
+ CreateOrUpdateIconView(notification);
+ CreateOrUpdateSmallIconView(notification);
+ CreateOrUpdateImageView(notification);
+ CreateOrUpdateActionButtonViews(notification);
+ CreateOrUpdateCloseButtonView(notification);
+ CreateOrUpdateSettingsButtonView(notification);
+}
+
+NotificationViewMD::NotificationViewMD(MessageCenterController* controller,
+ const Notification& notification)
+ : MessageView(controller, notification),
+ clickable_(notification.clickable()) {
+ layout_ = new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 2);
+ layout_->set_inside_border_insets(kNotificationPadding);
+ SetLayoutManager(layout_);
+
+ // Create the top_view_, which collects into a vertical box all content
+ // at the top of the notification (to the right of the icon) except for the
+ // close button.
+ top_view_ = new views::View();
+ views::BoxLayout* top_box_layout =
+ new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 1, 5);
+ top_box_layout->set_cross_axis_alignment(
+ views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
+ top_view_->SetLayoutManager(top_box_layout);
+ AddChildView(top_view_);
+
+ main_view_ = new views::View();
+ main_view_->SetLayoutManager(
+ new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
+ AddChildView(main_view_);
+
+ // Create the bottom_view_, which collects notification icon.
+ bottom_view_ = new views::View();
+ bottom_view_->SetLayoutManager(
+ new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
+ AddChildView(bottom_view_);
+
+ views::ImageView* small_image_view = new views::ImageView();
+ small_image_view->SetImageSize(gfx::Size(kSmallImageSize, kSmallImageSize));
+ small_image_view->set_owned_by_client();
+ small_image_view_.reset(small_image_view);
+ top_view_->AddChildView(small_image_view_.get());
+
+ CreateOrUpdateViews(notification);
+
+ SetEventTargeter(
+ std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
+}
+
+NotificationViewMD::~NotificationViewMD() {}
+
+void NotificationViewMD::Layout() {
+ MessageView::Layout();
+
+ // Before any resizing, set or adjust the number of message lines.
+ int title_lines = 0;
+ if (title_view_) {
+ title_lines = title_view_->GetLinesForWidthAndLimit(title_view_->width(),
+ kMaxTitleLines);
+ }
+ if (message_view_) {
+ message_view_->SetLineLimit(
+ std::max(0, message_center::kMessageExpandedLineLimit - title_lines));
+ }
+
+ // Settings & Bottom views.
+ if (settings_button_) {
+ gfx::Rect content_bounds = GetContentsBounds();
+ const gfx::Size settings_size(settings_button_->GetPreferredSize());
+ int marginFromRight = settings_size.width() + kControlButtonPadding;
+ if (close_button_)
+ marginFromRight += close_button_->GetPreferredSize().width();
+ gfx::Rect settings_rect(content_bounds.right() - marginFromRight,
+ GetContentsBounds().y() + kControlButtonPadding,
+ settings_size.width(), settings_size.height());
+ settings_button_->SetBoundsRect(settings_rect);
+ }
+
+ // Close button.
+ if (close_button_) {
+ gfx::Rect content_bounds = GetContentsBounds();
+ gfx::Size close_size(close_button_->GetPreferredSize());
+ gfx::Rect close_rect(
+ content_bounds.right() - close_size.width() - kControlButtonPadding,
+ content_bounds.y() + kControlButtonPadding, close_size.width(),
+ close_size.height());
+ close_button_->SetBoundsRect(close_rect);
+ }
+}
+
+void NotificationViewMD::OnFocus() {
+ MessageView::OnFocus();
+ ScrollRectToVisible(GetLocalBounds());
+}
+
+void NotificationViewMD::ScrollRectToVisible(const gfx::Rect& rect) {
+ // Notification want to show the whole notification when a part of it (like
+ // a button) gets focused.
+ views::View::ScrollRectToVisible(GetLocalBounds());
+}
+
+gfx::NativeCursor NotificationViewMD::GetCursor(const ui::MouseEvent& event) {
+ if (!clickable_ || !controller()->HasClickedListener(notification_id()))
+ return views::View::GetCursor(event);
+
+ return views::GetNativeHandCursor();
+}
+
+void NotificationViewMD::OnMouseEntered(const ui::MouseEvent& event) {
+ MessageView::OnMouseEntered(event);
+ UpdateControlButtonsVisibility();
+}
+
+void NotificationViewMD::OnMouseExited(const ui::MouseEvent& event) {
+ MessageView::OnMouseExited(event);
+ UpdateControlButtonsVisibility();
+}
+
+void NotificationViewMD::UpdateWithNotification(
+ const Notification& notification) {
+ MessageView::UpdateWithNotification(notification);
+
+ CreateOrUpdateViews(notification);
+ Layout();
+ SchedulePaint();
+}
+
+void NotificationViewMD::ButtonPressed(views::Button* sender,
+ const ui::Event& event) {
+ // Certain operations can cause |this| to be destructed, so copy the members
+ // we send to other parts of the code.
+ // TODO(dewittj): Remove this hack.
+ std::string id(notification_id());
+
+ if (close_button_ && sender == close_button_.get()) {
+ // Warning: This causes the NotificationViewMD itself to be deleted, so
+ // don't do anything afterwards.
+ OnCloseButtonPressed();
+ return;
+ }
+
+ if (sender == settings_button_.get()) {
+ controller()->ClickOnSettingsButton(id);
+ return;
+ }
+
+ // See if the button pressed was an action button.
+ for (size_t i = 0; i < action_buttons_.size(); ++i) {
+ if (sender == action_buttons_[i]) {
+ controller()->ClickOnNotificationButton(id, i);
+ return;
+ }
+ }
+}
+
+bool NotificationViewMD::IsCloseButtonFocused() const {
+ if (!close_button_)
+ return false;
+
+ const views::FocusManager* focus_manager = GetFocusManager();
+ return focus_manager &&
+ focus_manager->GetFocusedView() == close_button_.get();
+}
+
+void NotificationViewMD::RequestFocusOnCloseButton() {
+ if (close_button_)
+ close_button_->RequestFocus();
+}
+
+void NotificationViewMD::CreateOrUpdateContextTitleView(
+ const Notification& notification) {
+ DCHECK(top_view_);
+
+ const gfx::FontList& font_list = views::Label().font_list().Derive(
+ -2, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
+
+ base::string16 sub_title = notification.display_source();
+ if (!context_title_view_) {
+ context_title_view_ = new BoundedLabel(sub_title, font_list);
+ context_title_view_->SetLineHeight(kTitleLineHeight);
+ context_title_view_->SetLineLimit(kMaxContextTitleLines);
+ top_view_->AddChildView(context_title_view_);
+ } else {
+ context_title_view_->SetText(sub_title);
+ }
+}
+
+void NotificationViewMD::CreateOrUpdateTitleView(
+ const Notification& notification) {
+ DCHECK(top_view_ != NULL);
+
+ const gfx::FontList& font_list = views::Label().font_list().Derive(
+ 1, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
+
+ int title_character_limit =
+ kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacter;
+
+ base::string16 title = gfx::TruncateString(
+ notification.title(), title_character_limit, gfx::WORD_BREAK);
+ if (!title_view_) {
+ title_view_ = new BoundedLabel(title, font_list);
+ title_view_->SetLineHeight(kMessageLineHeight);
+ title_view_->SetColors(message_center::kRegularTextColor,
+ kDimTextBackgroundColor);
+ main_view_->AddChildView(title_view_);
+ } else {
+ title_view_->SetText(title);
+ }
+}
+
+void NotificationViewMD::CreateOrUpdateMessageView(
+ const Notification& notification) {
+ if (notification.message().empty()) {
+ // Deletion will also remove |context_message_view_| from its parent.
+ delete message_view_;
+ message_view_ = nullptr;
+ return;
+ }
+
+ DCHECK(top_view_ != NULL);
+
+ base::string16 text = gfx::TruncateString(
+ notification.message(), kMessageCharacterLimit, gfx::WORD_BREAK);
+
+ const gfx::FontList& font_list = views::Label().font_list().Derive(
+ 1, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL);
+
+ if (!message_view_) {
+ message_view_ = new BoundedLabel(text, font_list);
+ message_view_->SetLineLimit(message_center::kMessageExpandedLineLimit);
+ message_view_->SetColors(message_center::kDimTextColor,
+ kContextTextBackgroundColor);
+ main_view_->AddChildView(message_view_);
+ } else {
+ message_view_->SetText(text);
+ }
+}
+
+void NotificationViewMD::CreateOrUpdateProgressBarView(
+ const Notification& notification) {
+ // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateListItemViews(
+ const Notification& notification) {
+ // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateIconView(
+ const Notification& notification) {
+ // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateSmallIconView(
+ const Notification& notification) {
+ gfx::ImageSkia icon =
+ notification.small_image().IsEmpty()
+ ? GetProductIcon()
+ : GetMaskedIcon(notification.small_image().AsImageSkia());
+
+ small_image_view_->SetImage(icon);
+}
+
+void NotificationViewMD::CreateOrUpdateImageView(
+ const Notification& notification) {
+ // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateActionButtonViews(
+ const Notification& notification) {
+ // TODO(yoshiki): Implement this.
+}
+
+void NotificationViewMD::CreateOrUpdateCloseButtonView(
+ const Notification& notification) {
+ if (!notification.pinned() && !close_button_) {
+ close_button_ = base::MakeUnique<PaddedButton>(this);
+ close_button_->SetImage(views::Button::STATE_NORMAL, GetCloseIcon());
+ close_button_->SetAccessibleName(l10n_util::GetStringUTF16(
+ IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME));
+ close_button_->SetTooltipText(l10n_util::GetStringUTF16(
+ IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_TOOLTIP));
+ close_button_->set_owned_by_client();
+ AddChildView(close_button_.get());
+ UpdateControlButtonsVisibility();
+ } else if (notification.pinned() && close_button_) {
+ close_button_.reset();
+ }
+}
+
+void NotificationViewMD::CreateOrUpdateSettingsButtonView(
+ const Notification& notification) {
+ if (!settings_button_ && notification.delegate() &&
+ notification.delegate()->ShouldDisplaySettingsButton()) {
+ settings_button_ = base::MakeUnique<PaddedButton>(this);
+ settings_button_->SetImage(views::Button::STATE_NORMAL, GetSettingsIcon());
+ settings_button_->SetAccessibleName(l10n_util::GetStringUTF16(
+ IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
+ settings_button_->SetTooltipText(l10n_util::GetStringUTF16(
+ IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
+ settings_button_->set_owned_by_client();
+ AddChildView(settings_button_.get());
+ } else {
+ settings_button_.reset();
+ }
+ UpdateControlButtonsVisibility();
+}
+
+void NotificationViewMD::UpdateControlButtonsVisibility() {
+ const bool target_visibility =
+ IsMouseHovered() || HasFocus() ||
+ (close_button_ && close_button_->HasFocus()) ||
+ (settings_button_ && settings_button_->HasFocus());
+
+ if (close_button_) {
+ if (target_visibility != close_button_->visible())
+ close_button_->SetVisible(target_visibility);
+ }
+
+ if (settings_button_) {
+ if (target_visibility != settings_button_->visible())
+ settings_button_->SetVisible(target_visibility);
+ }
+}
+
+} // namespace message_center
« no previous file with comments | « ui/message_center/views/notification_view_md.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698