| // Copyright 2020 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 "chrome/browser/ui/views/global_media_controls/media_notification_device_entry_ui.h" |
| |
| #include "base/bind.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "components/vector_icons/vector_icons.h" |
| #include "ui/base/metadata/metadata_impl_macros.h" |
| #include "ui/gfx/paint_vector_icon.h" |
| #include "ui/views/animation/ink_drop.h" |
| #include "ui/views/background.h" |
| #include "ui/views/controls/styled_label.h" |
| |
| namespace { |
| |
| constexpr int kDeviceIconSize = 20; |
| constexpr auto kDeviceIconBorder = gfx::Insets(6); |
| constexpr gfx::Size kDeviceEntryViewSize{400, 30}; |
| constexpr int kEntryHighlightOpacity = 45; |
| |
| void ChangeEntryColor(views::ImageView* image_view, |
| views::StyledLabel* title_view, |
| views::Label* subtitle_view, |
| const gfx::VectorIcon* icon, |
| SkColor foreground_color, |
| SkColor background_color) { |
| if (image_view) { |
| image_view->SetImage( |
| gfx::CreateVectorIcon(*icon, kDeviceIconSize, foreground_color)); |
| } |
| |
| title_view->SetDisplayedOnBackgroundColor(background_color); |
| if (!title_view->GetText().empty()) { |
| views::StyledLabel::RangeStyleInfo style_info; |
| style_info.text_style = views::style::STYLE_PRIMARY; |
| style_info.override_color = foreground_color; |
| title_view->ClearStyleRanges(); |
| title_view->AddStyleRange(gfx::Range(0, title_view->GetText().length()), |
| style_info); |
| title_view->SizeToFit(0); |
| } |
| |
| if (subtitle_view) { |
| subtitle_view->SetEnabledColor(foreground_color); |
| subtitle_view->SetBackgroundColor(background_color); |
| } |
| } |
| |
| std::unique_ptr<views::ImageView> GetAudioDeviceIcon() { |
| auto icon_view = std::make_unique<views::ImageView>(); |
| icon_view->SetImage(gfx::CreateVectorIcon( |
| vector_icons::kHeadsetIcon, kDeviceIconSize, gfx::kPlaceholderColor)); |
| icon_view->SetBorder(views::CreateEmptyBorder(kDeviceIconBorder)); |
| return icon_view; |
| } |
| |
| } // namespace |
| |
| DeviceEntryUI::DeviceEntryUI(const std::string& raw_device_id, |
| const std::string& device_name, |
| const gfx::VectorIcon* icon, |
| const std::string& subtext) |
| : raw_device_id_(raw_device_id), device_name_(device_name), icon_(icon) {} |
| |
| AudioDeviceEntryView::AudioDeviceEntryView(PressedCallback callback, |
| SkColor foreground_color, |
| SkColor background_color, |
| const std::string& raw_device_id, |
| const std::string& device_name) |
| : DeviceEntryUI(raw_device_id, device_name, &vector_icons::kHeadsetIcon), |
| HoverButton(std::move(callback), |
| GetAudioDeviceIcon(), |
| base::UTF8ToUTF16(device_name)) { |
| ChangeEntryColor(static_cast<views::ImageView*>(icon_view()), title(), |
| subtitle(), icon_, foreground_color, background_color); |
| |
| SetFocusBehavior(views::View::FocusBehavior::ALWAYS); |
| ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); |
| ink_drop()->SetBaseColor(foreground_color); |
| // Bypass color-callback setup in HoverButton. |
| ink_drop()->SetBaseColorCallback({}); |
| SetHasInkDropActionOnClick(true); |
| SetPreferredSize(kDeviceEntryViewSize); |
| } |
| |
| void AudioDeviceEntryView::SetHighlighted(bool highlighted) { |
| if (is_highlighted_ == highlighted) { |
| return; |
| } |
| is_highlighted_ = highlighted; |
| if (highlighted) { |
| ink_drop()->SetMode(views::InkDropHost::InkDropMode::OFF); |
| SetHasInkDropActionOnClick(false); |
| SetBackground(views::CreateSolidBackground( |
| SkColorSetA(ink_drop()->GetBaseColor(), kEntryHighlightOpacity))); |
| } else { |
| ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); |
| SetHasInkDropActionOnClick(true); |
| SetBackground(nullptr); |
| } |
| OnPropertyChanged(&is_highlighted_, views::kPropertyEffectsPaint); |
| } |
| |
| bool AudioDeviceEntryView::GetHighlighted() const { |
| return is_highlighted_; |
| } |
| |
| void AudioDeviceEntryView::OnColorsChanged(SkColor foreground_color, |
| SkColor background_color) { |
| ink_drop()->SetBaseColor(foreground_color); |
| |
| ChangeEntryColor(static_cast<views::ImageView*>(icon_view()), title(), |
| subtitle(), icon_, foreground_color, background_color); |
| |
| // Reapply highlight formatting as some effects rely on these colors. |
| SetHighlighted(is_highlighted_); |
| } |
| |
| DeviceEntryUIType AudioDeviceEntryView::GetType() const { |
| return DeviceEntryUIType::kAudio; |
| } |
| |
| CastDeviceEntryView::CastDeviceEntryView( |
| base::RepeatingCallback<void(CastDeviceEntryView*)> callback, |
| SkColor foreground_color, |
| SkColor background_color, |
| const media_router::UIMediaSink& sink) |
| : DeviceEntryUI(sink.id, |
| base::UTF16ToUTF8(sink.friendly_name), |
| CastDialogSinkButton::GetVectorIcon(sink)), |
| CastDialogSinkButton( |
| base::BindRepeating(std::move(callback), base::Unretained(this)), |
| sink) { |
| ChangeCastEntryColor(sink, foreground_color, background_color); |
| |
| SetFocusBehavior(views::View::FocusBehavior::ALWAYS); |
| ink_drop()->SetMode(views::InkDropHost::InkDropMode::ON); |
| ink_drop()->SetBaseColor(foreground_color); |
| SetHasInkDropActionOnClick(true); |
| // Bypass color-callback setup in HoverButton. |
| ink_drop()->SetBaseColorCallback({}); |
| SetPreferredSize(kDeviceEntryViewSize); |
| } |
| |
| void CastDeviceEntryView::OnColorsChanged(SkColor foreground_color, |
| SkColor background_color) { |
| ink_drop()->SetBaseColor(foreground_color); |
| ChangeCastEntryColor(sink(), foreground_color, background_color); |
| } |
| |
| DeviceEntryUIType CastDeviceEntryView::GetType() const { |
| return DeviceEntryUIType::kCast; |
| } |
| |
| void CastDeviceEntryView::OnFocus() { |
| // CastDialogSinkButton::OnFocus() changes the button's status text to "Stop |
| // Casting" if the sink is connected. This status text may cause confusion to |
| // users when the button is shown in the Zenith dialog, where clicking on the |
| // sink button will automatically stop the sink's connected route and start a |
| // new one. |
| HoverButton::OnFocus(); |
| } |
| |
| void CastDeviceEntryView::ChangeCastEntryColor( |
| const media_router::UIMediaSink& sink, |
| SkColor foreground_color, |
| SkColor background_color) { |
| switch (sink.state) { |
| // If the sink state is CONNECTING or DISCONNECTING, a throbber icon will |
| // show up. The icon's color remains unchanged. |
| case media_router::UIMediaSinkState::CONNECTING: |
| case media_router::UIMediaSinkState::DISCONNECTING: |
| ChangeEntryColor(nullptr, title(), subtitle(), nullptr, foreground_color, |
| background_color); |
| break; |
| case media_router::UIMediaSinkState::CONNECTED: |
| case media_router::UIMediaSinkState::AVAILABLE: |
| case media_router::UIMediaSinkState::UNAVAILABLE: |
| ChangeEntryColor(static_cast<views::ImageView*>(icon_view()), title(), |
| subtitle(), icon_, foreground_color, background_color); |
| break; |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| BEGIN_METADATA(AudioDeviceEntryView, HoverButton) |
| ADD_PROPERTY_METADATA(bool, Highlighted) |
| END_METADATA |
| |
| BEGIN_METADATA(CastDeviceEntryView, media_router::CastDialogSinkButton) |
| END_METADATA |