1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/views/global_media_controls/media_notification_list_view.h"
6
7 #include "chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.h"
8 #include "chrome/browser/ui/views/global_media_controls/overlay_media_notification_view.h"
9 #include "ui/native_theme/native_theme.h"
10 #include "ui/views/border.h"
11 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
12 #include "ui/views/layout/box_layout.h"
13
14 namespace {
15
16 constexpr int kMediaListMaxHeight = 478;
17
18 // Thickness of separator border.
19 constexpr int kMediaListSeparatorThickness = 2;
20
CreateMediaListSeparatorBorder(SkColor color,int thickness)21 std::unique_ptr<views::Border> CreateMediaListSeparatorBorder(SkColor color,
22 int thickness) {
23 return views::CreateSolidSidedBorder(/*top=*/thickness,
24 /*left=*/0,
25 /*bottom=*/0,
26 /*right=*/0, color);
27 }
28
29 } // anonymous namespace
30
SeparatorStyle(SkColor separator_color,int separator_thickness)31 MediaNotificationListView::SeparatorStyle::SeparatorStyle(
32 SkColor separator_color,
33 int separator_thickness)
34 : separator_color(separator_color),
35 separator_thickness(separator_thickness) {}
36
MediaNotificationListView()37 MediaNotificationListView::MediaNotificationListView()
38 : MediaNotificationListView(base::nullopt) {}
39
MediaNotificationListView(const base::Optional<SeparatorStyle> & separator_style)40 MediaNotificationListView::MediaNotificationListView(
41 const base::Optional<SeparatorStyle>& separator_style)
42 : separator_style_(separator_style) {
43 SetBackgroundColor(base::nullopt);
44 SetContents(std::make_unique<views::View>());
45 contents()->SetLayoutManager(std::make_unique<views::BoxLayout>(
46 views::BoxLayout::Orientation::kVertical));
47 ClipHeightTo(0, kMediaListMaxHeight);
48
49 SetVerticalScrollBar(
50 std::make_unique<views::OverlayScrollBar>(/*horizontal=*/false));
51 SetHorizontalScrollBar(
52 std::make_unique<views::OverlayScrollBar>(/*horizontal=*/true));
53 }
54
55 MediaNotificationListView::~MediaNotificationListView() = default;
56
ShowNotification(const std::string & id,std::unique_ptr<MediaNotificationContainerImplView> notification)57 void MediaNotificationListView::ShowNotification(
58 const std::string& id,
59 std::unique_ptr<MediaNotificationContainerImplView> notification) {
60 DCHECK(!base::Contains(notifications_, id));
61 DCHECK_NE(nullptr, notification.get());
62
63 // If this isn't the first notification, then create a top-sided separator
64 // border.
65 if (!notifications_.empty()) {
66 if (separator_style_.has_value()) {
67 notification->SetBorder(CreateMediaListSeparatorBorder(
68 separator_style_->separator_color,
69 separator_style_->separator_thickness));
70 } else {
71 notification->SetBorder(CreateMediaListSeparatorBorder(
72 GetNativeTheme()->GetSystemColor(
73 ui::NativeTheme::kColorId_MenuSeparatorColor),
74 kMediaListSeparatorThickness));
75 }
76 }
77
78 notifications_[id] = contents()->AddChildView(std::move(notification));
79
80 contents()->InvalidateLayout();
81 PreferredSizeChanged();
82 }
83
HideNotification(const std::string & id)84 void MediaNotificationListView::HideNotification(const std::string& id) {
85 RemoveNotification(id);
86 }
87
PopOut(const std::string & id,gfx::Rect bounds)88 std::unique_ptr<OverlayMediaNotification> MediaNotificationListView::PopOut(
89 const std::string& id,
90 gfx::Rect bounds) {
91 std::unique_ptr<MediaNotificationContainerImplView> notification =
92 RemoveNotification(id);
93 if (!notification)
94 return nullptr;
95
96 return std::make_unique<OverlayMediaNotificationView>(
97 id, std::move(notification), bounds, nullptr);
98 }
99
100 std::unique_ptr<MediaNotificationContainerImplView>
RemoveNotification(const std::string & id)101 MediaNotificationListView::RemoveNotification(const std::string& id) {
102 if (!base::Contains(notifications_, id))
103 return nullptr;
104
105 // If we're removing the topmost notification and there are others, then we
106 // need to remove the top-sided separator border from the new topmost
107 // notification.
108 if (contents()->children().size() > 1 &&
109 contents()->children().at(0) == notifications_[id]) {
110 contents()->children().at(1)->SetBorder(nullptr);
111 }
112
113 // Remove the notification. Note that since |RemoveChildView()| does not
114 // delete the notification, we now have ownership.
115 contents()->RemoveChildView(notifications_[id]);
116 std::unique_ptr<MediaNotificationContainerImplView> notification(
117 notifications_[id]);
118 notifications_.erase(id);
119
120 contents()->InvalidateLayout();
121 PreferredSizeChanged();
122
123 return notification;
124 }
125