Commit 8f1d3e6d authored by Muyao Xu's avatar Muyao Xu Committed by Commit Bot

[Cast+Zenith] Modify the Cast/AudioDeviceEntryView UI

AudioDeviceEntryView is changed to be a sub-class of HoverButton.
Changed button colors and added ink drop effects in
Cast/AudioDeviceEntryView.

Bug: b/161610050, 1107162
Change-Id: If91d5041cbf81954bd2a3c9a8b5fd79fe3fdf22e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2387204
Commit-Queue: Muyao Xu <muyaoxu@google.com>
Reviewed-by: default avatarTakumi Fujimoto <takumif@chromium.org>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808420}
parent 7d41cc89
......@@ -6,91 +6,74 @@
#include "base/strings/utf_string_conversions.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/animation/ink_drop.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/controls/styled_label.h"
namespace {
constexpr gfx::Insets kIconContainerInsets{10, 15};
constexpr int kDeviceIconSize = 18;
constexpr gfx::Insets kLabelsContainerInsets{18, 0};
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) {
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(SkColor foreground_color,
SkColor background_color,
const std::string& raw_device_id,
DeviceEntryUI::DeviceEntryUI(const std::string& raw_device_id,
const std::string& device_name,
const gfx::VectorIcon* icon,
const std::string& subtext)
: foreground_color_(foreground_color),
background_color_(background_color),
raw_device_id_(raw_device_id),
device_name_(device_name),
icon_(icon) {}
std::string DeviceEntryUI::GetEntryLabelForTesting() {
return base::UTF16ToUTF8(device_name_label_->GetText());
}
AudioDeviceEntryView::AudioDeviceEntryView(SkColor foreground_color,
SkColor background_color,
const std::string& raw_device_id,
const std::string& device_name,
const std::string& subtext)
: DeviceEntryUI(foreground_color,
background_color,
raw_device_id,
device_name,
&vector_icons::kHeadsetIcon) {
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal));
icon_container_ = AddChildView(std::make_unique<views::View>());
auto* icon_container_layout =
icon_container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, kIconContainerInsets));
icon_container_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
icon_container_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
device_icon_ =
icon_container_->AddChildView(std::make_unique<views::ImageView>());
device_icon_->SetImage(
gfx::CreateVectorIcon(*icon_, kDeviceIconSize, foreground_color));
labels_container_ = AddChildView(std::make_unique<views::View>());
auto* labels_container_layout =
labels_container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, kLabelsContainerInsets));
labels_container_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
labels_container_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kStart);
views::Label::CustomFont device_name_label_font{
views::Label::GetDefaultFontList().DeriveWithSizeDelta(1)};
device_name_label_ =
labels_container_->AddChildView(std::make_unique<views::Label>(
base::UTF8ToUTF16(device_name_), device_name_label_font));
device_name_label_->SetEnabledColor(foreground_color);
device_name_label_->SetBackgroundColor(background_color);
if (!subtext.empty()) {
device_subtext_label_ = labels_container_->AddChildView(
std::make_unique<views::Label>(base::UTF8ToUTF16(subtext)));
device_subtext_label_->SetTextStyle(
views::style::TextStyle::STYLE_SECONDARY);
device_subtext_label_->SetEnabledColor(foreground_color);
device_subtext_label_->SetBackgroundColor(background_color);
}
// Ensures that hovering over these items also hovers this view.
icon_container_->set_can_process_events_within_subtree(false);
labels_container_->set_can_process_events_within_subtree(false);
: raw_device_id_(raw_device_id), device_name_(device_name), icon_(icon) {}
AudioDeviceEntryView::AudioDeviceEntryView(
views::ButtonListener* button_listener,
SkColor foreground_color,
SkColor background_color,
const std::string& raw_device_id,
const std::string& device_name,
const std::string& subtext)
: DeviceEntryUI(raw_device_id, device_name, &vector_icons::kHeadsetIcon),
HoverButton(button_listener,
GetAudioDeviceIcon(),
base::UTF8ToUTF16(device_name),
base::UTF8ToUTF16(subtext)) {
ChangeEntryColor(static_cast<views::ImageView*>(icon_view()), title(),
subtitle(), icon_, foreground_color, background_color);
SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
SetInkDropMode(Button::InkDropMode::ON);
......@@ -115,46 +98,55 @@ void AudioDeviceEntryView::SetHighlighted(bool highlighted) {
void AudioDeviceEntryView::OnColorsChanged(SkColor foreground_color,
SkColor background_color) {
foreground_color_ = foreground_color;
background_color_ = background_color;
set_ink_drop_base_color(foreground_color_);
device_icon_->SetImage(
gfx::CreateVectorIcon(*icon_, kDeviceIconSize, foreground_color_));
device_name_label_->SetEnabledColor(foreground_color_);
device_name_label_->SetBackgroundColor(background_color_);
set_ink_drop_base_color(foreground_color);
if (device_subtext_label_) {
device_subtext_label_->SetEnabledColor(foreground_color_);
device_subtext_label_->SetBackgroundColor(background_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_);
}
SkColor AudioDeviceEntryView::GetInkDropBaseColor() const {
return views::Button::GetInkDropBaseColor();
}
DeviceEntryUIType AudioDeviceEntryView::GetType() const {
return DeviceEntryUIType::kAudio;
}
CastDeviceEntryView::CastDeviceEntryView(SkColor foreground_color,
CastDeviceEntryView::CastDeviceEntryView(views::ButtonListener* button_listener,
SkColor foreground_color,
SkColor background_color,
const media_router::UIMediaSink& sink)
: DeviceEntryUI(foreground_color,
background_color,
sink.id,
: DeviceEntryUI(sink.id,
base::UTF16ToUTF8(sink.friendly_name),
// TODO(muyaoxu): change device icon
&vector_icons::kHeadsetIcon),
CastDialogSinkButton(nullptr,
CastDialogSinkButton::GetVectorIcon(sink.icon_type)),
CastDialogSinkButton(button_listener,
sink,
/* TODO(muyaoxu): change this to button_tag */ 0) {}
/* TODO(muyaoxu): button tag */ -1) {
// TODO(muyaoxu): change the sink's style based on its UIMediaSinkState
ChangeEntryColor(static_cast<views::ImageView*>(icon_view()), title(),
subtitle(), icon_, foreground_color, background_color);
SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
SetInkDropMode(Button::InkDropMode::ON);
set_ink_drop_base_color(foreground_color);
set_has_ink_drop_action_on_click(true);
SetPreferredSize(kDeviceEntryViewSize);
}
// TODO(muyaoxu): Implement this function
void CastDeviceEntryView::OnColorsChanged(SkColor foreground_color,
SkColor background_color) {}
SkColor background_color) {
set_ink_drop_base_color(foreground_color);
ChangeEntryColor(static_cast<views::ImageView*>(icon_view()), title(),
subtitle(), icon_, foreground_color, background_color);
}
DeviceEntryUIType CastDeviceEntryView::GetType() const {
return DeviceEntryUIType::kCast;
}
SkColor CastDeviceEntryView::GetInkDropBaseColor() const {
return views::Button::GetInkDropBaseColor();
}
......@@ -6,14 +6,6 @@
#define CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_NOTIFICATION_DEVICE_ENTRY_UI_H_
#include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icon_types.h"
#include "ui/views/controls/button/button.h"
namespace views {
class ImageView;
class Label;
} // namespace views
enum class DeviceEntryUIType {
kAudio = 0,
......@@ -23,9 +15,7 @@ enum class DeviceEntryUIType {
class DeviceEntryUI {
public:
DeviceEntryUI(SkColor foreground_color,
SkColor background_color,
const std::string& raw_device_id,
DeviceEntryUI(const std::string& raw_device_id,
const std::string& device_name,
const gfx::VectorIcon* icon_,
const std::string& subtext = "");
......@@ -41,45 +31,41 @@ class DeviceEntryUI {
SkColor background_color) = 0;
virtual DeviceEntryUIType GetType() const = 0;
std::string GetEntryLabelForTesting();
bool GetEntryIsHighlightedForTesting() const { return is_highlighted_; }
protected:
SkColor foreground_color_, background_color_;
const std::string raw_device_id_;
const std::string device_name_;
bool is_highlighted_ = false;
const gfx::VectorIcon* const icon_;
views::Label* device_name_label_ = nullptr;
};
class AudioDeviceEntryView : public views::Button, public DeviceEntryUI {
class AudioDeviceEntryView : public DeviceEntryUI, public HoverButton {
public:
AudioDeviceEntryView(SkColor foreground_color,
AudioDeviceEntryView(views::ButtonListener* button_listener,
SkColor foreground_color,
SkColor background_color,
const std::string& raw_device_id,
const std::string& name,
const std::string& subtext = "");
~AudioDeviceEntryView() override = default;
void SetHighlighted(bool highlighted);
// DeviceEntryUI
void OnColorsChanged(SkColor foreground_color,
SkColor background_color) override;
DeviceEntryUIType GetType() const override;
private:
views::View* icon_container_ = nullptr;
views::ImageView* device_icon_ = nullptr;
views::View* labels_container_ = nullptr;
views::Label* device_subtext_label_ = nullptr;
// HoverButton
SkColor GetInkDropBaseColor() const override;
void SetHighlighted(bool highlighted);
};
class CastDeviceEntryView : public DeviceEntryUI,
public media_router::CastDialogSinkButton {
public:
CastDeviceEntryView(SkColor foreground_color,
CastDeviceEntryView(views::ButtonListener* button_listener,
SkColor foreground_color,
SkColor background_color,
const media_router::UIMediaSink& sink);
~CastDeviceEntryView() override = default;
......@@ -88,6 +74,9 @@ class CastDeviceEntryView : public DeviceEntryUI,
void OnColorsChanged(SkColor foreground_color,
SkColor background_color) override;
DeviceEntryUIType GetType() const override;
// HoverButton
SkColor GetInkDropBaseColor() const override;
};
#endif // CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_NOTIFICATION_DEVICE_ENTRY_UI_H_
......@@ -184,9 +184,8 @@ void MediaNotificationDeviceSelectorView::UpdateAvailableAudioDevices(
bool current_device_still_exists = false;
for (auto description : device_descriptions) {
auto device_entry_view = std::make_unique<AudioDeviceEntryView>(
foreground_color_, background_color_, description.unique_id,
this, foreground_color_, background_color_, description.unique_id,
description.device_name, "");
device_entry_view->set_listener(this);
device_entry_view->set_tag(next_tag_++);
device_entry_ui_map_[device_entry_view->tag()] = device_entry_view.get();
device_entry_views_container_->AddChildView(std::move(device_entry_view));
......@@ -354,13 +353,14 @@ void MediaNotificationDeviceSelectorView::OnModelUpdated(
RemoveDevicesOfType(DeviceEntryUIType::kCast);
for (auto sink : model.media_sinks()) {
auto device_entry_view = std::make_unique<CastDeviceEntryView>(
foreground_color_, background_color_, sink);
this, foreground_color_, background_color_, sink);
device_entry_view->set_tag(next_tag_++);
device_entry_ui_map_[device_entry_view->tag()] = device_entry_view.get();
device_entry_views_container_->AddChildView(std::move(device_entry_view));
}
SetVisible(true);
delegate_->OnDeviceSelectorViewSizeChanged();
Layout();
}
void MediaNotificationDeviceSelectorView::OnControllerInvalidated() {
......
......@@ -11,9 +11,6 @@
#include "chrome/browser/ui/views/global_media_controls/media_notification_device_entry_ui.h"
#include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h"
#include "media/audio/audio_device_description.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/layout/box_layout.h"
namespace {
class ExpandDeviceSelectorButton;
......@@ -73,13 +70,13 @@ class MediaNotificationDeviceSelectorView
FRIEND_TEST_ALL_PREFIXES(MediaNotificationDeviceSelectorViewTest,
ExpandButtonOpensEntryContainer);
FRIEND_TEST_ALL_PREFIXES(MediaNotificationDeviceSelectorViewTest,
DeviceButtonClickNotifiesContainer);
AudioDeviceButtonClickNotifiesContainer);
FRIEND_TEST_ALL_PREFIXES(MediaNotificationDeviceSelectorViewTest,
CurrentDeviceHighlighted);
CurrentAudioDeviceHighlighted);
FRIEND_TEST_ALL_PREFIXES(MediaNotificationDeviceSelectorViewTest,
DeviceHighlightedOnChange);
AudioDeviceHighlightedOnChange);
FRIEND_TEST_ALL_PREFIXES(MediaNotificationDeviceSelectorViewTest,
DeviceButtonsChange);
AudioDeviceButtonsChange);
FRIEND_TEST_ALL_PREFIXES(MediaNotificationDeviceSelectorViewTest,
AudioDevicesCountHistogramRecorded);
FRIEND_TEST_ALL_PREFIXES(MediaNotificationDeviceSelectorViewTest,
......
......@@ -36,38 +36,9 @@ namespace media_router {
namespace {
gfx::ImageSkia CreateSinkIcon(SinkIconType icon_type, bool enabled = true) {
const gfx::VectorIcon* vector_icon;
switch (icon_type) {
case SinkIconType::CAST_AUDIO_GROUP:
vector_icon = &kSpeakerGroupIcon;
break;
case SinkIconType::CAST_AUDIO:
vector_icon = &kSpeakerIcon;
break;
case SinkIconType::EDUCATION:
vector_icon = &kCastForEducationIcon;
break;
case SinkIconType::WIRED_DISPLAY:
vector_icon = &kInputIcon;
break;
// Use proprietary icons only in Chrome builds. The default TV icon is used
// instead for these sink types in Chromium builds.
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
case SinkIconType::MEETING:
vector_icon = &vector_icons::kMeetIcon;
break;
case SinkIconType::HANGOUT:
vector_icon = &vector_icons::kHangoutIcon;
break;
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
case SinkIconType::CAST:
case SinkIconType::GENERIC:
default:
vector_icon = &kTvIcon;
break;
}
SkColor icon_color = enabled ? gfx::kChromeIconGrey : gfx::kGoogleGrey500;
return gfx::CreateVectorIcon(*vector_icon, kPrimaryIconSize, icon_color);
return gfx::CreateVectorIcon(*CastDialogSinkButton::GetVectorIcon(icon_type),
kPrimaryIconSize, icon_color);
}
gfx::ImageSkia CreateDisabledSinkIcon(SinkIconType icon_type) {
......@@ -82,11 +53,7 @@ std::unique_ptr<views::ImageView> CreatePrimaryIconView(
return icon_view;
}
std::unique_ptr<views::View> CreatePrimaryIconForSink(
CastDialogSinkButton* sink_button,
views::ButtonListener* button_listener,
const UIMediaSink& sink,
int button_tag) {
std::unique_ptr<views::View> CreatePrimaryIconForSink(const UIMediaSink& sink) {
// The stop button has the highest priority, and the issue icon comes second.
if (sink.state == UIMediaSinkState::CONNECTED) {
return CreatePrimaryIconView(gfx::CreateVectorIcon(
......@@ -128,12 +95,11 @@ CastDialogSinkButton::CastDialogSinkButton(
views::ButtonListener* button_listener,
const UIMediaSink& sink,
int button_tag)
: HoverButton(
button_listener,
CreatePrimaryIconForSink(this, button_listener, sink, button_tag),
sink.friendly_name,
GetStatusTextForSink(sink),
/** secondary_icon_view */ nullptr),
: HoverButton(button_listener,
CreatePrimaryIconForSink(sink),
sink.friendly_name,
GetStatusTextForSink(sink),
/** secondary_icon_view */ nullptr),
sink_(sink) {
set_tag(button_tag);
SetEnabled(sink.state == UIMediaSinkState::AVAILABLE ||
......@@ -232,4 +198,40 @@ void CastDialogSinkButton::OnBlur() {
RestoreStatusText();
}
// static
const gfx::VectorIcon* CastDialogSinkButton::GetVectorIcon(
SinkIconType icon_type) {
const gfx::VectorIcon* vector_icon;
switch (icon_type) {
case SinkIconType::CAST_AUDIO_GROUP:
vector_icon = &kSpeakerGroupIcon;
break;
case SinkIconType::CAST_AUDIO:
vector_icon = &kSpeakerIcon;
break;
case SinkIconType::EDUCATION:
vector_icon = &kCastForEducationIcon;
break;
case SinkIconType::WIRED_DISPLAY:
vector_icon = &kInputIcon;
break;
// Use proprietary icons only in Chrome builds. The default TV icon is used
// instead for these sink types in Chromium builds.
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
case SinkIconType::MEETING:
vector_icon = &vector_icons::kMeetIcon;
break;
case SinkIconType::HANGOUT:
vector_icon = &vector_icons::kHangoutIcon;
break;
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
case SinkIconType::CAST:
case SinkIconType::GENERIC:
default:
vector_icon = &kTvIcon;
break;
}
return vector_icon;
}
} // namespace media_router
......@@ -36,6 +36,8 @@ class CastDialogSinkButton : public HoverButton {
const UIMediaSink& sink() const { return sink_; }
static const gfx::VectorIcon* GetVectorIcon(SinkIconType icon_type);
private:
friend class MediaRouterUiForTest;
FRIEND_TEST_ALL_PREFIXES(CastDialogSinkButtonTest, OverrideStatusText);
......
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