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

Unified Diff: ash/common/system/web_notification/web_notification_tray.cc

Issue 2209443006: Show small notification icons in notification tray (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 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
Index: ash/common/system/web_notification/web_notification_tray.cc
diff --git a/ash/common/system/web_notification/web_notification_tray.cc b/ash/common/system/web_notification/web_notification_tray.cc
index feba9fffdf06e91fba9d42e6d2c0e151a1782607..bde98a579f43e017efea54f82b5c32d70f3bb229 100644
--- a/ash/common/system/web_notification/web_notification_tray.cc
+++ b/ash/common/system/web_notification/web_notification_tray.cc
@@ -63,8 +63,24 @@ namespace ash {
namespace {
// Menu commands
-const int kToggleQuietMode = 0;
-const int kEnableQuietModeDay = 2;
+constexpr int kToggleQuietMode = 0;
+constexpr int kEnableQuietModeDay = 2;
+
+constexpr int kMaximumSmallIconCount = 3;
+
+constexpr gfx::Size kTrayItemInnerIconSize = gfx::Size(16, 16);
+constexpr gfx::Size kTrayItemInnerBellIconSize = gfx::Size(18, 18);
oshima 2016/08/04 18:15:21 I think you can do kTrayItemInnerIconSize(16, 16)
yoshiki 2016/08/05 13:30:47 Done.
+
+constexpr int kTrayItemWidth = 26;
+constexpr int kTrayItemHeight = 26;
oshima 2016/08/04 18:15:21 can this also be gfx::Size ?
yoshiki 2016/08/05 13:30:47 Done.
+constexpr int kTrayItemHorizontalInset = 6;
+constexpr int kTrayItemVerticalInset = 6;
+
+constexpr int kTrayItemAnimationDurationMS = 200;
+
+static int round(double d) {
+ return std::floor(d + 0.5);
+}
oshima 2016/08/04 18:15:20 gfx::ToRoundedInt
yoshiki 2016/08/05 13:30:48 Done.
}
namespace {
@@ -115,53 +131,66 @@ class WebNotificationBubbleWrapper {
DISALLOW_COPY_AND_ASSIGN(WebNotificationBubbleWrapper);
};
-class WebNotificationButton : public views::CustomButton {
+class WebNotificationItem : public views::View, public gfx::AnimationDelegate {
public:
- WebNotificationButton(views::ButtonListener* listener)
- : views::CustomButton(listener),
- is_bubble_visible_(false),
- unread_count_(0) {
- SetLayoutManager(new views::FillLayout);
+ WebNotificationItem(gfx::AnimationContainer* container,
+ WebNotificationTray* tray)
+ : tray_(tray) {
+ SetPaintToLayer(true);
+ layer()->SetFillsBoundsOpaquely(false);
+ views::View::SetVisible(false);
+ set_owned_by_client();
- gfx::ImageSkia image;
- if (MaterialDesignController::IsShelfMaterial()) {
- image = CreateVectorIcon(gfx::VectorIconId::SHELF_NOTIFICATIONS,
- kShelfIconColor);
- } else {
- image =
- CreateVectorIcon(gfx::VectorIconId::NOTIFICATIONS, kNoUnreadIconSize,
- kWebNotificationColorNoUnread);
- }
-
- no_unread_icon_.SetImage(image);
- no_unread_icon_.set_owned_by_client();
-
- unread_label_.set_owned_by_client();
- SetupLabelForTray(&unread_label_);
+ SetLayoutManager(new views::FillLayout);
- AddChildView(&no_unread_icon_);
+ animation_.reset(new gfx::SlideAnimation(this));
+ animation_->SetContainer(container);
+ animation_->SetSlideDuration(kTrayItemAnimationDurationMS);
+ animation_->SetTweenType(gfx::Tween::LINEAR);
}
- void SetBubbleVisible(bool visible) {
- if (visible == is_bubble_visible_)
+ void SetVisible(bool set_visible) override {
+ if (!GetWidget()) {
+ views::View::SetVisible(set_visible);
return;
+ }
- is_bubble_visible_ = visible;
- UpdateIconVisibility();
+ if (!set_visible) {
+ animation_->Hide();
+ AnimationProgressed(animation_.get());
+ } else {
+ animation_->Show();
+ AnimationProgressed(animation_.get());
+ views::View::SetVisible(true);
+ }
}
- void SetUnreadCount(int unread_count) {
- // base::FormatNumber doesn't convert to arabic numeric characters.
- // TODO(mukai): use ICU to support conversion for such locales.
- unread_count_ = unread_count;
- UpdateIconVisibility();
+ void HideAndDelete() {
+ SetVisible(false);
+
+ if (!visible() && !animation_->is_animating()) {
+ if (parent())
+ parent()->RemoveChildView(this);
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+ } else {
+ delete_after_animation_ = true;
+ }
}
protected:
// Overridden from views::ImageButton:
gfx::Size GetPreferredSize() const override {
- const int size = GetTrayConstant(TRAY_ITEM_HEIGHT_LEGACY);
- return gfx::Size(size, size);
+ gfx::Size size = gfx::Size(kTrayItemWidth, kTrayItemHeight);
+ if (!animation_.get() || !animation_->is_animating())
+ return size;
+ if (IsHorizontalAlignment(tray_->shelf_alignment())) {
oshima 2016/08/04 18:15:21 since it's used in many places now, it's probably
yoshiki 2016/08/05 13:30:48 Done.
+ size.set_width(
+ std::max(1, round(size.width() * animation_->GetCurrentValue())));
+ } else {
+ size.set_height(
+ std::max(1, round(size.height() * animation_->GetCurrentValue())));
+ }
+ return size;
}
oshima 2016/08/04 18:15:21 I guess we can't just clip it because there are mu
yoshiki 2016/08/05 13:30:48 Done.
int GetHeightForWidth(int width) const override {
@@ -169,38 +198,86 @@ class WebNotificationButton : public views::CustomButton {
}
private:
- void UpdateIconVisibility() {
- if (unread_count_ == 0) {
- if (!Contains(&no_unread_icon_)) {
- RemoveAllChildViews(false /* delete_children */);
- AddChildView(&no_unread_icon_);
- }
+ // Overridden from gfx::AnimationDelegate.
oshima 2016/08/04 18:15:21 // gfx::AnimationDelegate:
yoshiki 2016/08/05 13:30:47 Done.
+ void AnimationProgressed(const gfx::Animation* animation) override {
+ gfx::Transform transform;
+ if (IsHorizontalAlignment(tray_->shelf_alignment())) {
+ transform.Translate(0, animation->CurrentValueBetween(
+ static_cast<double>(height()) / 2, 0.));
} else {
- if (!Contains(&unread_label_)) {
- RemoveAllChildViews(false /* delete_children */);
- AddChildView(&unread_label_);
- }
-
- // TODO(mukai): move NINE_PLUS message to ui_strings, it doesn't need to
- // be in ash_strings.
- unread_label_.SetText(
- (unread_count_ > 9) ? l10n_util::GetStringUTF16(
- IDS_ASH_NOTIFICATION_UNREAD_COUNT_NINE_PLUS)
- : base::FormatNumber(unread_count_));
- unread_label_.SetEnabledColor((unread_count_ > 0)
- ? kWebNotificationColorWithUnread
- : kWebNotificationColorNoUnread);
+ transform.Translate(
+ animation->CurrentValueBetween(static_cast<double>(width() / 2), 0.),
+ 0);
}
- SchedulePaint();
+ transform.Scale(animation->GetCurrentValue(), animation->GetCurrentValue());
+ layer()->SetTransform(transform);
+ PreferredSizeChanged();
+ }
+ void AnimationEnded(const gfx::Animation* animation) override {
+ if (animation->GetCurrentValue() < 0.1)
+ views::View::SetVisible(false);
+
+ if (delete_after_animation_) {
+ if (parent())
+ parent()->RemoveChildView(this);
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+ }
+ }
+ void AnimationCanceled(const gfx::Animation* animation) override {
+ AnimationEnded(animation);
+ }
+
+ std::unique_ptr<gfx::SlideAnimation> animation_;
+ bool delete_after_animation_ = false;
+ WebNotificationTray* tray_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebNotificationItem);
+};
+
+class WebNotificationImage : public WebNotificationItem {
+ public:
+ WebNotificationImage(const gfx::ImageSkia& image,
+ gfx::Size size,
+ gfx::AnimationContainer* container,
+ WebNotificationTray* tray)
+ : WebNotificationItem(container, tray) {
+ view_ = new views::ImageView();
+ view_->SetImage(image);
+ view_->SetImageSize(size);
+ AddChildView(view_);
}
- bool is_bubble_visible_;
- int unread_count_;
+ private:
+ views::ImageView* view_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebNotificationImage);
+};
- views::ImageView no_unread_icon_;
- views::Label unread_label_;
+class WebNotificationLabel : public WebNotificationItem {
+ public:
+ WebNotificationLabel(gfx::AnimationContainer* container,
+ WebNotificationTray* tray)
+ : WebNotificationItem(container, tray) {
+ view_ = new views::Label();
+ SetupLabelForTray(view_);
+ }
- DISALLOW_COPY_AND_ASSIGN(WebNotificationButton);
+ void SetUnreadCount(int unread_count) {
+ // TODO(mukai): move NINE_PLUS message to ui_strings, it doesn't need to
+ // be in ash_strings.
+ view_->SetText((unread_count > 9)
+ ? l10n_util::GetStringUTF16(
+ IDS_ASH_NOTIFICATION_UNREAD_COUNT_NINE_PLUS)
+ : base::FormatNumber(unread_count));
+ view_->SetEnabledColor(kWebNotificationColorWithUnread);
+ AddChildView(view_);
+ SchedulePaint();
+ }
+
+ private:
+ views::Label* view_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebNotificationLabel);
};
WebNotificationTray::WebNotificationTray(WmShelf* shelf,
@@ -209,18 +286,30 @@ WebNotificationTray::WebNotificationTray(WmShelf* shelf,
: TrayBackgroundView(shelf),
status_area_window_(status_area_window),
system_tray_(system_tray),
- button_(nullptr),
show_message_center_on_unlock_(false),
should_update_tray_content_(false),
should_block_shelf_auto_hide_(false) {
DCHECK(shelf);
DCHECK(status_area_window_);
DCHECK(system_tray_);
- button_ = new WebNotificationButton(this);
- button_->set_triggerable_event_flags(ui::EF_LEFT_MOUSE_BUTTON |
- ui::EF_RIGHT_MOUSE_BUTTON);
- tray_container()->AddChildView(button_);
- button_->SetFocusBehavior(FocusBehavior::NEVER);
+
+ gfx::ImageSkia bell_image;
+ if (MaterialDesignController::IsShelfMaterial()) {
+ bell_image = CreateVectorIcon(gfx::VectorIconId::SHELF_NOTIFICATIONS,
+ kShelfIconColor);
+ } else {
+ bell_image =
+ CreateVectorIcon(gfx::VectorIconId::NOTIFICATIONS, kNoUnreadIconSize,
+ kWebNotificationColorNoUnread);
+ }
+ bell_icon_.reset(new WebNotificationImage(bell_image,
+ kTrayItemInnerBellIconSize,
+ animation_container_.get(), this));
+ tray_container()->AddChildView(bell_icon_.get());
+
+ counter_.reset(new WebNotificationLabel(animation_container_.get(), this));
+ tray_container()->AddChildView(counter_.get());
+
SetContentsBackground();
tray_container()->SetBorder(views::Border::NullBorder());
message_center_tray_.reset(new message_center::MessageCenterTray(
@@ -234,6 +323,9 @@ WebNotificationTray::WebNotificationTray(WmShelf* shelf,
popup_alignment_delegate_->StartObserving(display::Screen::GetScreen(),
display);
OnMessageCenterTrayChanged();
+
+ tray_container()->set_insets(
+ gfx::Insets(kTrayItemHorizontalInset, kTrayItemVerticalInset));
}
WebNotificationTray::~WebNotificationTray() {
@@ -273,7 +365,6 @@ bool WebNotificationTray::ShowMessageCenterInternal(bool show_settings) {
system_tray_->SetHideNotifications(true);
shelf()->UpdateAutoHideState();
- button_->SetBubbleVisible(true);
SetDrawBackgroundAsActive(true);
return true;
}
@@ -291,7 +382,6 @@ void WebNotificationTray::HideMessageCenter() {
show_message_center_on_unlock_ = false;
system_tray_->SetHideNotifications(false);
shelf()->UpdateAutoHideState();
- button_->SetBubbleVisible(false);
}
void WebNotificationTray::SetTrayBubbleHeight(int height) {
@@ -460,12 +550,6 @@ void WebNotificationTray::ExecuteCommand(int command_id, int event_flags) {
message_center()->EnterQuietModeWithExpire(expires_in);
}
-void WebNotificationTray::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- DCHECK_EQ(button_, sender);
- PerformAction(event);
-}
-
void WebNotificationTray::OnMessageCenterTrayChanged() {
// Do not update the tray contents directly. Multiple change events can happen
// consecutively, and calling Update in the middle of those events will show
@@ -481,15 +565,60 @@ void WebNotificationTray::UpdateTrayContent() {
return;
should_update_tray_content_ = false;
+ std::set<std::string> notification_ids;
oshima 2016/08/04 18:15:21 unorderd_set or you can just use vector (which is
yoshiki 2016/08/05 13:30:48 Let me use unordered_map, since I want to show tha
+ for (auto i : visible_small_icons_) {
+ notification_ids.insert(i.first);
+ }
+
+ // Add small icons (up to kMaximumSmallIconCount = 3).
message_center::MessageCenter* message_center =
message_center_tray_->message_center();
- button_->SetUnreadCount(message_center->UnreadNotificationCount());
- if (IsMessageCenterBubbleVisible())
- button_->SetState(views::CustomButton::STATE_PRESSED);
- else
- button_->SetState(views::CustomButton::STATE_NORMAL);
+ size_t visible_small_icon_count = 0;
+ for (const auto* notification : message_center->GetVisibleNotifications()) {
+ gfx::Image image = notification->small_image();
+ if (image.IsEmpty())
+ continue;
+
+ if (visible_small_icon_count >= kMaximumSmallIconCount)
+ break;
+ visible_small_icon_count++;
+
+ notification_ids.erase(notification->id());
+ if (visible_small_icons_.count(notification->id()) != 0)
+ continue;
+
+ auto* item =
+ new WebNotificationImage(image.AsImageSkia(), kTrayItemInnerIconSize,
+ animation_container_.get(), this);
+ visible_small_icons_.insert(std::make_pair(notification->id(), item));
+
+ tray_container()->AddChildViewAt(item, 0);
+ item->SetVisible(true);
+ }
+
+ // Remove unnecessary icons.
+ for (const std::string& id : notification_ids) {
+ WebNotificationImage* item = visible_small_icons_[id];
+ visible_small_icons_.erase(id);
+ item->HideAndDelete();
+ }
+
+ // Show or hide the bell icon.
+ size_t visible_notification_count = message_center->NotificationCount();
+ bell_icon_->SetVisible(visible_notification_count == 0);
+
+ // Show or hide the counter.
+ size_t hidden_icon_count =
+ visible_notification_count - visible_small_icon_count;
+ if (hidden_icon_count != 0) {
+ counter_->SetVisible(true);
+ counter_->SetUnreadCount(hidden_icon_count);
+ } else {
+ counter_->SetVisible(false);
+ }
SetVisible(IsLoggedIn());
+ PreferredSizeChanged();
Layout();
SchedulePaint();
if (IsLoggedIn())

Powered by Google App Engine
This is Rietveld 408576698