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

Side by Side Diff: ui/message_center/views/notification_view_md.cc

Issue 2969603003: Implement new-style image notification resizing. (Closed)
Patch Set: Fix unit test. Created 3 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 unified diff | Download patch
OLDNEW
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/i18n/case_conversion.h" 9 #include "base/i18n/case_conversion.h"
10 #include "base/strings/string_util.h" 10 #include "base/strings/string_util.h"
11 #include "ui/base/cursor/cursor.h" 11 #include "ui/base/cursor/cursor.h"
12 #include "ui/base/l10n/l10n_util.h" 12 #include "ui/base/l10n/l10n_util.h"
13 #include "ui/gfx/canvas.h" 13 #include "ui/gfx/canvas.h"
14 #include "ui/gfx/geometry/size.h" 14 #include "ui/gfx/geometry/size.h"
15 #include "ui/gfx/image/image_skia_operations.h"
15 #include "ui/gfx/paint_vector_icon.h" 16 #include "ui/gfx/paint_vector_icon.h"
16 #include "ui/gfx/skia_util.h" 17 #include "ui/gfx/skia_util.h"
17 #include "ui/gfx/text_elider.h" 18 #include "ui/gfx/text_elider.h"
18 #include "ui/message_center/message_center.h" 19 #include "ui/message_center/message_center.h"
19 #include "ui/message_center/message_center_style.h" 20 #include "ui/message_center/message_center_style.h"
20 #include "ui/message_center/notification.h" 21 #include "ui/message_center/notification.h"
21 #include "ui/message_center/notification_types.h" 22 #include "ui/message_center/notification_types.h"
22 #include "ui/message_center/vector_icons.h" 23 #include "ui/message_center/vector_icons.h"
23 #include "ui/message_center/views/bounded_label.h" 24 #include "ui/message_center/views/bounded_label.h"
24 #include "ui/message_center/views/constants.h" 25 #include "ui/message_center/views/constants.h"
(...skipping 17 matching lines...) Expand all
42 #include "ui/views/widget/widget.h" 43 #include "ui/views/widget/widget.h"
43 44
44 namespace message_center { 45 namespace message_center {
45 46
46 namespace { 47 namespace {
47 48
48 // Dimensions. 49 // Dimensions.
49 constexpr gfx::Insets kContentRowPadding(4, 12, 12, 12); 50 constexpr gfx::Insets kContentRowPadding(4, 12, 12, 12);
50 constexpr gfx::Insets kActionsRowPadding(8, 8, 8, 8); 51 constexpr gfx::Insets kActionsRowPadding(8, 8, 8, 8);
51 constexpr int kActionsRowHorizontalSpacing = 8; 52 constexpr int kActionsRowHorizontalSpacing = 8;
52 constexpr gfx::Insets kImageContainerPadding(0, 12, 12, 12);
53 constexpr gfx::Insets kActionButtonPadding(0, 12, 0, 12); 53 constexpr gfx::Insets kActionButtonPadding(0, 12, 0, 12);
54 constexpr gfx::Insets kStatusTextPadding(4, 0, 0, 0); 54 constexpr gfx::Insets kStatusTextPadding(4, 0, 0, 0);
55 constexpr gfx::Size kActionButtonMinSize(88, 32); 55 constexpr gfx::Size kActionButtonMinSize(88, 32);
56 constexpr gfx::Size kIconViewSize(30, 30); 56 constexpr gfx::Size kIconViewSize(30, 30);
57 constexpr gfx::Insets kLargeImageContainerPadding(0, 12, 12, 12);
58 constexpr gfx::Size kLargeImageMinSize(328, 0);
59 constexpr gfx::Size kLargeImageMaxSize(328, 218);
57 60
58 // Background of inline actions area. 61 // Background of inline actions area.
59 const SkColor kActionsRowBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee); 62 const SkColor kActionsRowBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee);
60 // Base ink drop color of action buttons. 63 // Base ink drop color of action buttons.
61 const SkColor kActionButtonInkDropBaseColor = SkColorSetRGB(0x0, 0x0, 0x0); 64 const SkColor kActionButtonInkDropBaseColor = SkColorSetRGB(0x0, 0x0, 0x0);
62 // Ripple ink drop opacity of action buttons. 65 // Ripple ink drop opacity of action buttons.
63 const float kActionButtonInkDropRippleVisibleOpacity = 0.08f; 66 const float kActionButtonInkDropRippleVisibleOpacity = 0.08f;
64 // Highlight (hover) ink drop opacity of action buttons. 67 // Highlight (hover) ink drop opacity of action buttons.
65 const float kActionButtonInkDropHighlightVisibleOpacity = 0.08f; 68 const float kActionButtonInkDropHighlightVisibleOpacity = 0.08f;
66 // Text color of action button. 69 // Text color of action button.
67 const SkColor kActionButtonTextColor = SkColorSetRGB(0x33, 0x67, 0xD6); 70 const SkColor kActionButtonTextColor = SkColorSetRGB(0x33, 0x67, 0xD6);
71 // Background color of the large image.
72 const SkColor kLargeImageBackgroundColor = SkColorSetRGB(0xf5, 0xf5, 0xf5);
68 73
69 // Max number of lines for message_view_. 74 // Max number of lines for message_view_.
70 constexpr int kMaxLinesForMessageView = 1; 75 constexpr int kMaxLinesForMessageView = 1;
71 constexpr int kMaxLinesForExpandedMessageView = 4; 76 constexpr int kMaxLinesForExpandedMessageView = 4;
72 77
73 constexpr int kCompactTitleMessageViewSpacing = 12; 78 constexpr int kCompactTitleMessageViewSpacing = 12;
74 79
75 constexpr int kProgressBarHeight = 4; 80 constexpr int kProgressBarHeight = 4;
76 81
77 constexpr int kMessageViewWidth = 82 constexpr int kMessageViewWidth =
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 } 253 }
249 254
250 std::unique_ptr<views::InkDropHighlight> 255 std::unique_ptr<views::InkDropHighlight>
251 NotificationButtonMD::CreateInkDropHighlight() const { 256 NotificationButtonMD::CreateInkDropHighlight() const {
252 std::unique_ptr<views::InkDropHighlight> highlight = 257 std::unique_ptr<views::InkDropHighlight> highlight =
253 views::LabelButton::CreateInkDropHighlight(); 258 views::LabelButton::CreateInkDropHighlight();
254 highlight->set_visible_opacity(kActionButtonInkDropHighlightVisibleOpacity); 259 highlight->set_visible_opacity(kActionButtonInkDropHighlightVisibleOpacity);
255 return highlight; 260 return highlight;
256 } 261 }
257 262
263 // LargeImageView //////////////////////////////////////////////////////////////
264
265 class LargeImageView : public views::View {
266 public:
267 LargeImageView();
268 ~LargeImageView() override;
269
270 void SetImage(const gfx::ImageSkia& image);
271
272 void OnPaint(gfx::Canvas* canvas) override;
273 const char* GetClassName() const override;
274
275 private:
276 gfx::Size GetResizedImageSize();
277
278 gfx::ImageSkia image_;
279
280 DISALLOW_COPY_AND_ASSIGN(LargeImageView);
281 };
282
283 LargeImageView::LargeImageView() {
284 SetBackground(views::CreateSolidBackground(kLargeImageBackgroundColor));
285 }
286
287 LargeImageView::~LargeImageView() = default;
288
289 void LargeImageView::SetImage(const gfx::ImageSkia& image) {
290 image_ = image;
291 gfx::Size preferred_size = GetResizedImageSize();
292 preferred_size.SetToMax(kLargeImageMinSize);
293 preferred_size.SetToMin(kLargeImageMaxSize);
294 SetPreferredSize(preferred_size);
295 SchedulePaint();
296 Layout();
297 }
298
299 void LargeImageView::OnPaint(gfx::Canvas* canvas) {
300 views::View::OnPaint(canvas);
301
302 gfx::Size resized_size = GetResizedImageSize();
303 gfx::Size drawn_size = resized_size;
304 drawn_size.SetToMin(kLargeImageMaxSize);
305 gfx::Rect drawn_bounds = GetContentsBounds();
306 drawn_bounds.ClampToCenteredSize(drawn_size);
307
308 gfx::ImageSkia resized_image = gfx::ImageSkiaOperations::CreateResizedImage(
309 image_, skia::ImageOperations::RESIZE_BEST, resized_size);
310
311 // Cut off the overflown part.
312 gfx::ImageSkia drawn_image = gfx::ImageSkiaOperations::ExtractSubset(
313 resized_image, gfx::Rect(drawn_size));
314
315 canvas->DrawImageInt(drawn_image, drawn_bounds.x(), drawn_bounds.y());
316 }
317
318 const char* LargeImageView::GetClassName() const {
319 return "LargeImageView";
320 }
321
322 // Returns expected size of the image right after resizing.
323 // The GetResizedImageSize().width() <= kLargeImageMaxSize.width() holds, but
324 // GetResizedImageSize().height() may be larger than kLargeImageMaxSize.height()
325 // In this case, the overflown part will be just cutted off from the view.
326 gfx::Size LargeImageView::GetResizedImageSize() {
327 gfx::Size original_size = image_.size();
328 if (original_size.width() <= kLargeImageMaxSize.width())
329 return image_.size();
330
331 const double proportion =
332 original_size.height() / static_cast<double>(original_size.width());
333 gfx::Size resized_size;
334 resized_size.SetSize(kLargeImageMaxSize.width(),
335 kLargeImageMaxSize.width() * proportion);
336 return resized_size;
337 }
338
339 // LargeImageContainerView /////////////////////////////////////////////////////
340
341 // We have a container view outside LargeImageView, because we want to fill
342 // area that is not coverted by the image by background color.
343 class LargeImageContainerView : public views::View {
344 public:
345 explicit LargeImageContainerView();
yoshiki 2017/08/04 08:46:23 nit: explicit is unnecessary.
tetsui 2017/08/04 09:32:58 Done.
346 ~LargeImageContainerView() override;
347
348 void SetImage(const gfx::ImageSkia& image);
349 const char* GetClassName() const override;
350
351 private:
352 LargeImageView* image_view_;
yoshiki 2017/08/04 08:46:23 nit: const
tetsui 2017/08/04 09:32:59 Done.
353
354 DISALLOW_COPY_AND_ASSIGN(LargeImageContainerView);
355 };
356
357 LargeImageContainerView::LargeImageContainerView()
358 : image_view_(new LargeImageView()) {
359 SetLayoutManager(new views::FillLayout());
360 SetBorder(views::CreateEmptyBorder(kLargeImageContainerPadding));
361 SetBackground(
362 views::CreateSolidBackground(message_center::kImageBackgroundColor));
363 AddChildView(image_view_);
364 }
365
366 LargeImageContainerView::~LargeImageContainerView() = default;
367
368 void LargeImageContainerView::SetImage(const gfx::ImageSkia& image) {
369 image_view_->SetImage(image);
370 }
371
372 const char* LargeImageContainerView::GetClassName() const {
373 return "LargeImageContainerView";
374 }
375
258 } // anonymous namespace 376 } // anonymous namespace
259 377
260 // //////////////////////////////////////////////////////////// 378 // ////////////////////////////////////////////////////////////
261 // NotificationViewMD 379 // NotificationViewMD
262 // //////////////////////////////////////////////////////////// 380 // ////////////////////////////////////////////////////////////
263 381
264 views::View* NotificationViewMD::TargetForRect(views::View* root, 382 views::View* NotificationViewMD::TargetForRect(views::View* root,
265 const gfx::Rect& rect) { 383 const gfx::Rect& rect) {
266 CHECK_EQ(root, this); 384 CHECK_EQ(root, this);
267 385
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 list_items_count_ = items.size(); 748 list_items_count_ = items.size();
631 749
632 // Needed when CreateOrUpdateViews is called for update. 750 // Needed when CreateOrUpdateViews is called for update.
633 if (!item_views_.empty()) 751 if (!item_views_.empty())
634 left_content_->InvalidateLayout(); 752 left_content_->InvalidateLayout();
635 } 753 }
636 754
637 void NotificationViewMD::CreateOrUpdateIconView( 755 void NotificationViewMD::CreateOrUpdateIconView(
638 const Notification& notification) { 756 const Notification& notification) {
639 if (notification.type() == NOTIFICATION_TYPE_PROGRESS || 757 if (notification.type() == NOTIFICATION_TYPE_PROGRESS ||
640 notification.type() == NOTIFICATION_TYPE_MULTIPLE) { 758 notification.type() == NOTIFICATION_TYPE_MULTIPLE ||
759 notification.type() == NOTIFICATION_TYPE_IMAGE) {
641 DCHECK(!icon_view_ || right_content_->Contains(icon_view_)); 760 DCHECK(!icon_view_ || right_content_->Contains(icon_view_));
642 delete icon_view_; 761 delete icon_view_;
643 icon_view_ = nullptr; 762 icon_view_ = nullptr;
644 return; 763 return;
645 } 764 }
646 765
647 if (!icon_view_) { 766 if (!icon_view_) {
648 icon_view_ = new ProportionalImageView(kIconViewSize); 767 icon_view_ = new ProportionalImageView(kIconViewSize);
649 right_content_->AddChildView(icon_view_); 768 right_content_->AddChildView(icon_view_);
650 } 769 }
651 770
652 gfx::ImageSkia icon = notification.icon().AsImageSkia(); 771 gfx::ImageSkia icon = notification.icon().AsImageSkia();
653 icon_view_->SetImage(icon, icon.size()); 772 icon_view_->SetImage(icon, icon.size());
654 } 773 }
655 774
656 void NotificationViewMD::CreateOrUpdateSmallIconView( 775 void NotificationViewMD::CreateOrUpdateSmallIconView(
657 const Notification& notification) { 776 const Notification& notification) {
658 if (notification.small_image().IsEmpty()) 777 if (notification.small_image().IsEmpty())
659 header_row_->ClearAppIcon(); 778 header_row_->ClearAppIcon();
660 else 779 else
661 header_row_->SetAppIcon(notification.small_image().AsImageSkia()); 780 header_row_->SetAppIcon(notification.small_image().AsImageSkia());
662 } 781 }
663 782
664 void NotificationViewMD::CreateOrUpdateImageView( 783 void NotificationViewMD::CreateOrUpdateImageView(
665 const Notification& notification) { 784 const Notification& notification) {
666 // |image_view_| is the view representing the area covered by the
667 // notification's image, including background and border. Its size can be
668 // specified in advance and images will be scaled to fit including a border if
669 // necessary.
670 if (notification.image().IsEmpty()) { 785 if (notification.image().IsEmpty()) {
671 if (image_container_) { 786 if (image_container_view_) {
672 DCHECK(image_view_); 787 DCHECK(Contains(image_container_view_));
673 DCHECK(Contains(image_container_)); 788 delete image_container_view_;
674 delete image_container_; 789 image_container_view_ = nullptr;
675 image_container_ = NULL;
676 image_view_ = NULL;
677 } else {
678 DCHECK(!image_view_);
679 } 790 }
680 return; 791 return;
681 } 792 }
682 793
683 gfx::Size ideal_size(kNotificationPreferredImageWidth, 794 if (!image_container_view_) {
684 kNotificationPreferredImageHeight); 795 image_container_view_ = new LargeImageContainerView();
685
686 if (!image_container_) {
687 image_container_ = new views::View();
688 image_container_->SetLayoutManager(new views::FillLayout());
689 image_container_->SetBorder(
690 views::CreateEmptyBorder(kImageContainerPadding));
691 image_container_->SetBackground(
692 views::CreateSolidBackground(message_center::kImageBackgroundColor));
693
694 DCHECK(!image_view_);
695 image_view_ = new message_center::ProportionalImageView(ideal_size);
696 image_container_->AddChildView(image_view_);
697 // Insert the created image container just after the |content_row_|. 796 // Insert the created image container just after the |content_row_|.
698 AddChildViewAt(image_container_, GetIndexOf(content_row_) + 1); 797 AddChildViewAt(image_container_view_, GetIndexOf(content_row_) + 1);
699 } 798 }
700 799
701 DCHECK(image_view_); 800 image_container_view_->SetImage(notification.image().AsImageSkia());
702 image_view_->SetImage(notification.image().AsImageSkia(), ideal_size);
703 } 801 }
704 802
705 void NotificationViewMD::CreateOrUpdateActionButtonViews( 803 void NotificationViewMD::CreateOrUpdateActionButtonViews(
706 const Notification& notification) { 804 const Notification& notification) {
707 std::vector<ButtonInfo> buttons = notification.buttons(); 805 std::vector<ButtonInfo> buttons = notification.buttons();
708 bool new_buttons = action_buttons_.size() != buttons.size(); 806 bool new_buttons = action_buttons_.size() != buttons.size();
709 807
710 if (new_buttons || buttons.size() == 0) { 808 if (new_buttons || buttons.size() == 0) {
711 for (auto* item : action_buttons_) 809 for (auto* item : action_buttons_)
712 delete item; 810 delete item;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
771 // Expandable if the message exceeds one line. 869 // Expandable if the message exceeds one line.
772 if (message_view_ && message_view_->visible() && 870 if (message_view_ && message_view_->visible() &&
773 message_view_->GetLinesForWidthAndLimit(message_view_->width(), -1) > 1) { 871 message_view_->GetLinesForWidthAndLimit(message_view_->width(), -1) > 1) {
774 return true; 872 return true;
775 } 873 }
776 // Expandable if there is at least one inline action. 874 // Expandable if there is at least one inline action.
777 if (actions_row_->has_children()) 875 if (actions_row_->has_children())
778 return true; 876 return true;
779 877
780 // Expandable if the notification has image. 878 // Expandable if the notification has image.
781 if (image_view_) 879 if (image_container_view_)
782 return true; 880 return true;
783 881
784 // Expandable if there are multiple list items. 882 // Expandable if there are multiple list items.
785 if (item_views_.size() > 1) 883 if (item_views_.size() > 1)
786 return true; 884 return true;
787 885
788 // TODO(fukino): Expandable if both progress bar and message exist. 886 // TODO(fukino): Expandable if both progress bar and message exist.
789 887
790 return false; 888 return false;
791 } 889 }
792 890
793 void NotificationViewMD::ToggleExpanded() { 891 void NotificationViewMD::ToggleExpanded() {
794 expanded_ = !expanded_; 892 expanded_ = !expanded_;
795 UpdateViewForExpandedState(expanded_); 893 UpdateViewForExpandedState(expanded_);
796 content_row_->InvalidateLayout(); 894 content_row_->InvalidateLayout();
797 if (controller()) 895 if (controller())
798 controller()->UpdateNotificationSize(notification_id()); 896 controller()->UpdateNotificationSize(notification_id());
799 } 897 }
800 898
801 void NotificationViewMD::UpdateViewForExpandedState(bool expanded) { 899 void NotificationViewMD::UpdateViewForExpandedState(bool expanded) {
802 header_row_->SetExpanded(expanded); 900 header_row_->SetExpanded(expanded);
803 if (message_view_) { 901 if (message_view_) {
804 message_view_->SetLineLimit(expanded ? kMaxLinesForExpandedMessageView 902 message_view_->SetLineLimit(expanded ? kMaxLinesForExpandedMessageView
805 : kMaxLinesForMessageView); 903 : kMaxLinesForMessageView);
806 } 904 }
807 if (image_container_) 905 if (image_container_view_)
808 image_container_->SetVisible(expanded); 906 image_container_view_->SetVisible(expanded);
809 actions_row_->SetVisible(expanded && actions_row_->has_children()); 907 actions_row_->SetVisible(expanded && actions_row_->has_children());
810 for (size_t i = kMaxLinesForMessageView; i < item_views_.size(); ++i) { 908 for (size_t i = kMaxLinesForMessageView; i < item_views_.size(); ++i) {
811 item_views_[i]->SetVisible(expanded); 909 item_views_[i]->SetVisible(expanded);
812 } 910 }
813 if (status_view_) 911 if (status_view_)
814 status_view_->SetVisible(expanded); 912 status_view_->SetVisible(expanded);
815 header_row_->SetOverflowIndicator( 913 header_row_->SetOverflowIndicator(
816 list_items_count_ - 914 list_items_count_ -
817 (expanded ? item_views_.size() : kMaxLinesForMessageView)); 915 (expanded ? item_views_.size() : kMaxLinesForMessageView));
818 } 916 }
(...skipping 10 matching lines...) Expand all
829 header_row_->SetControlButtonsVisible(target_visibility); 927 header_row_->SetControlButtonsVisible(target_visibility);
830 } 928 }
831 929
832 NotificationControlButtonsView* NotificationViewMD::GetControlButtonsView() 930 NotificationControlButtonsView* NotificationViewMD::GetControlButtonsView()
833 const { 931 const {
834 // TODO(yoshiki): have this view use NotificationControlButtonsView. 932 // TODO(yoshiki): have this view use NotificationControlButtonsView.
835 return nullptr; 933 return nullptr;
836 } 934 }
837 935
838 } // namespace message_center 936 } // namespace message_center
OLDNEW
« no previous file with comments | « ui/message_center/views/notification_view_md.h ('k') | ui/message_center/views/notification_view_md_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698