Commit 22fde54f authored by Tetsui Ohkubo's avatar Tetsui Ohkubo Committed by Commit Bot

Unified: Implement stacking notification counter

This CL implements a counter view at the top of UnifiedSystemTray that
shows number of notifications hidden by scrolling.

Screenshot: http://screen/LK1ETwVGn2d

BUG=863635

Change-Id: I4cc16ec8f7e5f1f0b64836b1217655a52ca9882e
Reviewed-on: https://chromium-review.googlesource.com/1168945Reviewed-by: default avatarYoshiki Iguchi <yoshiki@chromium.org>
Commit-Queue: Tetsui Ohkubo <tetsui@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582485}
parent 9d0263ed
...@@ -328,6 +328,27 @@ void MessageListView::SetBorderPadding() { ...@@ -328,6 +328,27 @@ void MessageListView::SetBorderPadding() {
gfx::Insets(message_center::kMarginBetweenItemsInList))); gfx::Insets(message_center::kMarginBetweenItemsInList)));
} }
int MessageListView::GetCountAboveVisibleRect() const {
DCHECK(scroller_);
int height = 0;
int padding = 0;
for (int i = 0; i < child_count(); ++i) {
const views::View* child = child_at(i);
if (!child->visible())
continue;
if (!IsValidChild(child))
continue;
height += child->bounds().height() + padding;
padding = GetMarginBetweenItems();
if (height >= scroller_->GetVisibleRect().y())
return i;
}
return child_count();
}
int MessageListView::GetHeightBelowVisibleRect() const { int MessageListView::GetHeightBelowVisibleRect() const {
DCHECK(scroller_); DCHECK(scroller_);
......
...@@ -70,6 +70,9 @@ class ASH_EXPORT MessageListView : public views::View, ...@@ -70,6 +70,9 @@ class ASH_EXPORT MessageListView : public views::View,
void SetBorderPadding(); void SetBorderPadding();
// Get the number of notifications above ScrollView's visible rect.
int GetCountAboveVisibleRect() const;
// Get the distance from the bottom of ScrollView's visible rect to the bottom // Get the distance from the bottom of ScrollView's visible rect to the bottom
// of the notification list. // of the notification list.
int GetHeightBelowVisibleRect() const; int GetHeightBelowVisibleRect() const;
......
...@@ -169,6 +169,14 @@ constexpr int kUnifiedNotificationHiddenLineHeight = 20; ...@@ -169,6 +169,14 @@ constexpr int kUnifiedNotificationHiddenLineHeight = 20;
constexpr gfx::Insets kUnifiedTopShortcutPadding(0, 16); constexpr gfx::Insets kUnifiedTopShortcutPadding(0, 16);
constexpr gfx::Insets kUnifiedNotificationHiddenPadding(6, 16); constexpr gfx::Insets kUnifiedNotificationHiddenPadding(6, 16);
constexpr int kStackingNotificationCounterMax = 8;
constexpr int kStackingNotificationCounterRadius = 2;
constexpr int kStackingNotificationCounterStartX = 18;
constexpr int kStackingNotificationCounterDistanceX = 10;
constexpr int kStackingNotificationCounterHeight = 20;
constexpr SkColor kStackingNotificationCounterColor =
SkColorSetRGB(0xeb, 0xea, 0xed);
// Size of an icon drawn inside top shortcut buttons. // Size of an icon drawn inside top shortcut buttons.
// A dark disc with |kTrayItemSize| diameter is drawn in the background. // A dark disc with |kTrayItemSize| diameter is drawn in the background.
constexpr int kTrayTopShortcutButtonIconSize = 20; constexpr int kTrayTopShortcutButtonIconSize = 20;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "ash/system/unified/unified_system_tray_controller.h" #include "ash/system/unified/unified_system_tray_controller.h"
#include "ash/system/unified/unified_system_tray_view.h" #include "ash/system/unified/unified_system_tray_view.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/message_center/message_center.h" #include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_types.h" #include "ui/message_center/message_center_types.h"
#include "ui/message_center/views/message_view.h" #include "ui/message_center/views/message_view.h"
...@@ -32,6 +33,32 @@ const int kMaxVisibleNotifications = 100; ...@@ -32,6 +33,32 @@ const int kMaxVisibleNotifications = 100;
} // namespace } // namespace
StackingNotificationCounterView::StackingNotificationCounterView() = default;
StackingNotificationCounterView::~StackingNotificationCounterView() = default;
void StackingNotificationCounterView::SetCount(int stacking_count) {
stacking_count_ = std::min(stacking_count, kStackingNotificationCounterMax);
SetVisible(stacking_count > 0);
SchedulePaint();
}
void StackingNotificationCounterView::OnPaint(gfx::Canvas* canvas) {
int x = kStackingNotificationCounterStartX;
const int y = kStackingNotificationCounterHeight / 2;
cc::PaintFlags flags;
flags.setColor(kStackingNotificationCounterColor);
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setAntiAlias(true);
for (int i = 0; i < stacking_count_; ++i) {
canvas->DrawCircle(gfx::Point(x, y), kStackingNotificationCounterRadius,
flags);
x += kStackingNotificationCounterDistanceX;
}
}
// UnifiedMessageCenterView // UnifiedMessageCenterView
// /////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////
...@@ -42,6 +69,8 @@ UnifiedMessageCenterView::UnifiedMessageCenterView( ...@@ -42,6 +69,8 @@ UnifiedMessageCenterView::UnifiedMessageCenterView(
: tray_controller_(tray_controller), : tray_controller_(tray_controller),
parent_(parent), parent_(parent),
message_center_(message_center), message_center_(message_center),
stacking_counter_(new StackingNotificationCounterView()),
scroll_bar_(new MessageCenterScrollBar(this)),
scroller_(new views::ScrollView()), scroller_(new views::ScrollView()),
message_list_view_(new MessageListView()) { message_list_view_(new MessageListView()) {
DCHECK(message_center_); DCHECK(message_center_);
...@@ -52,10 +81,12 @@ UnifiedMessageCenterView::UnifiedMessageCenterView( ...@@ -52,10 +81,12 @@ UnifiedMessageCenterView::UnifiedMessageCenterView(
set_notify_enter_exit_on_child(true); set_notify_enter_exit_on_child(true);
SetFocusBehavior(views::View::FocusBehavior::NEVER); SetFocusBehavior(views::View::FocusBehavior::NEVER);
AddChildView(stacking_counter_);
// Need to set the transparent background explicitly, since ScrollView has // Need to set the transparent background explicitly, since ScrollView has
// set the default opaque background color. // set the default opaque background color.
scroller_->SetBackgroundColor(SK_ColorTRANSPARENT); scroller_->SetBackgroundColor(SK_ColorTRANSPARENT);
scroller_->SetVerticalScrollBar(new MessageCenterScrollBar(this)); scroller_->SetVerticalScrollBar(scroll_bar_);
scroller_->set_draw_overflow_indicator(false); scroller_->set_draw_overflow_indicator(false);
AddChildView(scroller_); AddChildView(scroller_);
...@@ -101,6 +132,8 @@ void UnifiedMessageCenterView::Init() { ...@@ -101,6 +132,8 @@ void UnifiedMessageCenterView::Init() {
focus_manager_ = GetFocusManager(); focus_manager_ = GetFocusManager();
if (focus_manager_) if (focus_manager_)
focus_manager_->AddFocusChangeListener(this); focus_manager_->AddFocusChangeListener(this);
LayoutInternal(false /* force */);
ScrollToPositionFromBottom(); ScrollToPositionFromBottom();
NotifyHeightBelowScroll(); NotifyHeightBelowScroll();
} }
...@@ -133,11 +166,44 @@ void UnifiedMessageCenterView::SetNotifications( ...@@ -133,11 +166,44 @@ void UnifiedMessageCenterView::SetNotifications(
} }
void UnifiedMessageCenterView::Layout() { void UnifiedMessageCenterView::Layout() {
scroller_->SetBounds(0, 0, width(), height()); LayoutInternal(true /* force */);
ScrollToPositionFromBottom(); ScrollToPositionFromBottom();
NotifyHeightBelowScroll(); NotifyHeightBelowScroll();
} }
void UnifiedMessageCenterView::LayoutInternal(bool force) {
// GetCountAboveVisibleRect() only works after SetBoundsRect() is called at
// least once.
if (scroller_->bounds().IsEmpty())
scroller_->SetBoundsRect(GetContentsBounds());
bool was_visible = stacking_counter_->visible();
stacking_counter_->SetCount(message_list_view_->GetCountAboveVisibleRect());
// Only do the actual layout if counter visibility is changed or forced.
if (was_visible != stacking_counter_->visible() || force) {
if (stacking_counter_->visible()) {
gfx::Rect counter_bounds(GetContentsBounds());
counter_bounds.set_height(kStackingNotificationCounterHeight);
stacking_counter_->SetBoundsRect(counter_bounds);
gfx::Insets scroller_insets(kStackingNotificationCounterHeight, 0, 0, 0);
gfx::Rect scroller_bounds(GetContentsBounds());
scroller_bounds.Inset(scroller_insets);
scroller_->SetBoundsRect(scroller_bounds);
} else {
scroller_->SetBoundsRect(GetContentsBounds());
}
}
// Adjust scroll position when counter visibility is changed so that on-screen
// position of notification list does not change.
if (was_visible != stacking_counter_->visible()) {
scroll_bar_->ScrollByContentsOffset(kStackingNotificationCounterHeight *
(was_visible ? 1 : -1));
}
}
gfx::Size UnifiedMessageCenterView::CalculatePreferredSize() const { gfx::Size UnifiedMessageCenterView::CalculatePreferredSize() const {
gfx::Size preferred_size = scroller_->GetPreferredSize(); gfx::Size preferred_size = scroller_->GetPreferredSize();
// Hide Clear All button at the buttom from initial viewport. // Hide Clear All button at the buttom from initial viewport.
...@@ -219,10 +285,10 @@ void UnifiedMessageCenterView::OnAllNotificationsCleared() { ...@@ -219,10 +285,10 @@ void UnifiedMessageCenterView::OnAllNotificationsCleared() {
void UnifiedMessageCenterView::OnMessageCenterScrolled() { void UnifiedMessageCenterView::OnMessageCenterScrolled() {
// Notification list is scrolled manually e.g. by mouse or gesture. // Notification list is scrolled manually e.g. by mouse or gesture.
auto* scroll_bar = scroller_->vertical_scroll_bar();
// Save the distance from the bottom when manually scrolled. // Save the distance from the bottom when manually scrolled.
position_from_bottom_ = position_from_bottom_ =
scroll_bar->GetMaxPosition() - scroller_->GetVisibleRect().y(); scroll_bar_->GetMaxPosition() - scroller_->GetVisibleRect().y();
LayoutInternal(false /* force */);
NotifyHeightBelowScroll(); NotifyHeightBelowScroll();
} }
...@@ -253,6 +319,8 @@ void UnifiedMessageCenterView::Update() { ...@@ -253,6 +319,8 @@ void UnifiedMessageCenterView::Update() {
scroller_->Layout(); scroller_->Layout();
PreferredSizeChanged(); PreferredSizeChanged();
LayoutInternal(false /* force */);
ScrollToPositionFromBottom();
NotifyHeightBelowScroll(); NotifyHeightBelowScroll();
} }
...@@ -287,9 +355,8 @@ void UnifiedMessageCenterView::UpdateNotification(const std::string& id) { ...@@ -287,9 +355,8 @@ void UnifiedMessageCenterView::UpdateNotification(const std::string& id) {
void UnifiedMessageCenterView::ScrollToPositionFromBottom() { void UnifiedMessageCenterView::ScrollToPositionFromBottom() {
scroller_->ScrollToPosition( scroller_->ScrollToPosition(
const_cast<views::ScrollBar*>(scroller_->vertical_scroll_bar()), scroll_bar_,
std::max(0, scroller_->vertical_scroll_bar()->GetMaxPosition() - std::max(0, scroll_bar_->GetMaxPosition() - position_from_bottom_));
position_from_bottom_));
} }
} // namespace ash } // namespace ash
...@@ -35,6 +35,22 @@ namespace ash { ...@@ -35,6 +35,22 @@ namespace ash {
class UnifiedSystemTrayController; class UnifiedSystemTrayController;
class UnifiedSystemTrayView; class UnifiedSystemTrayView;
class StackingNotificationCounterView : public views::View {
public:
StackingNotificationCounterView();
~StackingNotificationCounterView() override;
void SetCount(int stacking_count);
// views::View:
void OnPaint(gfx::Canvas* canvas) override;
private:
int stacking_count_ = 0;
DISALLOW_COPY_AND_ASSIGN(StackingNotificationCounterView);
};
// Container for message list view. Acts as a controller/delegate of message // Container for message list view. Acts as a controller/delegate of message
// list view, passing data back and forth to message center. // list view, passing data back and forth to message center.
class ASH_EXPORT UnifiedMessageCenterView class ASH_EXPORT UnifiedMessageCenterView
...@@ -104,10 +120,16 @@ class ASH_EXPORT UnifiedMessageCenterView ...@@ -104,10 +120,16 @@ class ASH_EXPORT UnifiedMessageCenterView
// Scroll the notification list to |position_from_bottom_|. // Scroll the notification list to |position_from_bottom_|.
void ScrollToPositionFromBottom(); void ScrollToPositionFromBottom();
// If |force| is false, it might not do the actual layout i.e. it assumes
// the reason of layout change is limited to |stacking_counter_| visibility.
void LayoutInternal(bool force);
UnifiedSystemTrayController* const tray_controller_; UnifiedSystemTrayController* const tray_controller_;
UnifiedSystemTrayView* const parent_; UnifiedSystemTrayView* const parent_;
message_center::MessageCenter* const message_center_; message_center::MessageCenter* const message_center_;
StackingNotificationCounterView* const stacking_counter_;
MessageCenterScrollBar* const scroll_bar_;
views::ScrollView* const scroller_; views::ScrollView* const scroller_;
MessageListView* const message_list_view_; MessageListView* const message_list_view_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment