Commit 57556783 authored by Jan Krcal's avatar Jan Krcal Committed by Commit Bot

[User menu] Update the user menu to show profile color

This CL adds a new implementation of SetProfileIdentityInfo() within
ProfileMenuViewBase guarded by a feature flag. The new implementation:
 - adds a colored background that matches the active frame color,
 - forces the profile name to always appear (for standard profiles), and
 - replaces the previous edit action (when you click on the profile
   name) with a dedicated edit icon.

https://screenshot.googleplex.com/1OV5VXrCVKK

Bug: 1099286
Change-Id: I20fff5b4a117aeb47174c3337900347057eb4b34
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2266958
Commit-Queue: Jan Krcal <jkrcal@chromium.org>
Reviewed-by: default avatarPeter Boström <pbos@chromium.org>
Reviewed-by: default avatarRamin Halavati <rhalavati@chromium.org>
Cr-Commit-Position: refs/heads/master@{#786216}
parent affcc770
...@@ -425,14 +425,16 @@ void ProfileMenuView::BuildIdentity() { ...@@ -425,14 +425,16 @@ void ProfileMenuView::BuildIdentity() {
GetProfileAttributesEntry(profile); GetProfileAttributesEntry(profile);
base::string16 profile_name; base::string16 profile_name;
base::Optional<EditButtonParams> edit_button; base::Optional<EditButtonParams> edit_button_params;
// Profile names are not supported on ChromeOS. // Profile names are not supported on ChromeOS.
#if !defined(OS_CHROMEOS) #if !defined(OS_CHROMEOS)
size_t num_of_profiles = size_t num_of_profiles =
g_browser_process->profile_manager()->GetNumberOfProfiles(); g_browser_process->profile_manager()->GetNumberOfProfiles();
if (num_of_profiles > 1 || !profile_attributes->IsUsingDefaultName()) { if (num_of_profiles > 1 || !profile_attributes->IsUsingDefaultName() ||
base::FeatureList::IsEnabled(features::kNewProfilePicker)) {
profile_name = profile_attributes->GetLocalProfileName(); profile_name = profile_attributes->GetLocalProfileName();
edit_button = EditButtonParams( edit_button_params = EditButtonParams(
&vector_icons::kEditIcon,
l10n_util::GetStringUTF16(IDS_SETTINGS_EDIT_PERSON), l10n_util::GetStringUTF16(IDS_SETTINGS_EDIT_PERSON),
base::BindRepeating(&ProfileMenuView::OnEditProfileButtonClicked, base::BindRepeating(&ProfileMenuView::OnEditProfileButtonClicked,
base::Unretained(this))); base::Unretained(this)));
...@@ -441,7 +443,7 @@ void ProfileMenuView::BuildIdentity() { ...@@ -441,7 +443,7 @@ void ProfileMenuView::BuildIdentity() {
if (account_info.has_value()) { if (account_info.has_value()) {
SetProfileIdentityInfo( SetProfileIdentityInfo(
profile_name, edit_button, profile_name, edit_button_params,
account_info.value().account_image.AsImageSkia(), account_info.value().account_image.AsImageSkia(),
base::UTF8ToUTF16(account_info.value().full_name), base::UTF8ToUTF16(account_info.value().full_name),
IsSyncPaused(profile) IsSyncPaused(profile)
...@@ -449,7 +451,7 @@ void ProfileMenuView::BuildIdentity() { ...@@ -449,7 +451,7 @@ void ProfileMenuView::BuildIdentity() {
: base::UTF8ToUTF16(account_info.value().email)); : base::UTF8ToUTF16(account_info.value().email));
} else { } else {
SetProfileIdentityInfo( SetProfileIdentityInfo(
profile_name, edit_button, profile_name, edit_button_params,
profile_attributes->GetAvatarIcon().AsImageSkia(), profile_attributes->GetAvatarIcon().AsImageSkia(),
/*title=*/base::string16(), /*title=*/base::string16(),
l10n_util::GetStringUTF16(IDS_PROFILES_LOCAL_PROFILE_STATE)); l10n_util::GetStringUTF16(IDS_PROFILES_LOCAL_PROFILE_STATE));
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h"
#include "chrome/browser/signin/signin_ui_util.h" #include "chrome/browser/signin/signin_ui_util.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/chrome_layout_provider.h"
...@@ -39,6 +40,8 @@ ...@@ -39,6 +40,8 @@
#include "ui/views/controls/separator.h" #include "ui/views/controls/separator.h"
#include "ui/views/controls/styled_label.h" #include "ui/views/controls/styled_label.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/flex_layout_types.h"
#include "ui/views/view_class_properties.h" #include "ui/views/view_class_properties.h"
#if !defined(OS_CHROMEOS) #if !defined(OS_CHROMEOS)
...@@ -54,8 +57,10 @@ ProfileMenuViewBase* g_profile_bubble_ = nullptr; ...@@ -54,8 +57,10 @@ ProfileMenuViewBase* g_profile_bubble_ = nullptr;
constexpr int kMenuWidth = 288; constexpr int kMenuWidth = 288;
constexpr int kIdentityImageSize = 64; constexpr int kIdentityImageSize = 64;
constexpr int kMaxImageSize = kIdentityImageSize; constexpr int kMaxImageSize = kIdentityImageSize;
constexpr int kDefaultVerticalMargin = 8; constexpr int kDefaultMargin = 8;
constexpr int kBadgeSize = 16; constexpr int kBadgeSize = 16;
constexpr int kCircularImageButtonSize = 28;
constexpr int kAvatarImageViewBottomMargin = kDefaultMargin;
// If the bubble is too large to fit on the screen, it still needs to be at // If the bubble is too large to fit on the screen, it still needs to be at
// least this tall to show one row. // least this tall to show one row.
...@@ -154,16 +159,17 @@ class CircularImageButton : public views::ImageButton { ...@@ -154,16 +159,17 @@ class CircularImageButton : public views::ImageButton {
// views::ImageButton: // views::ImageButton:
void OnThemeChanged() override { void OnThemeChanged() override {
views::ImageButton::OnThemeChanged(); views::ImageButton::OnThemeChanged();
constexpr int kImageSize = 28;
constexpr float kShortcutIconToImageRatio = 9.0f / 16.0f; constexpr float kShortcutIconToImageRatio = 9.0f / 16.0f;
const int kBorderThickness = show_border_ ? 1 : 0; const int kBorderThickness = show_border_ ? 1 : 0;
const SkScalar kButtonRadius = (kImageSize + 2 * kBorderThickness) / 2.0f; const SkScalar kButtonRadius =
(kCircularImageButtonSize + 2 * kBorderThickness) / 2.0f;
const SkColor icon_color = GetNativeTheme()->GetSystemColor( const SkColor icon_color = GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_DefaultIconColor); ui::NativeTheme::kColorId_DefaultIconColor);
gfx::ImageSkia image = gfx::ImageSkia image =
ImageForMenu(icon_, kShortcutIconToImageRatio, icon_color); ImageForMenu(icon_, kShortcutIconToImageRatio, icon_color);
SetImage(views::Button::STATE_NORMAL, SizeImage(image, kImageSize)); SetImage(views::Button::STATE_NORMAL,
SizeImage(image, kCircularImageButtonSize));
set_ink_drop_base_color(icon_color); set_ink_drop_base_color(icon_color);
if (show_border_) { if (show_border_) {
...@@ -234,7 +240,7 @@ class AvatarImageView : public views::ImageView { ...@@ -234,7 +240,7 @@ class AvatarImageView : public views::ImageView {
root_view_(root_view), root_view_(root_view),
icon_(icon), icon_(icon),
icon_color_id_(icon_color_id) { icon_color_id_(icon_color_id) {
SetBorder(views::CreateEmptyBorder(0, 0, kDefaultVerticalMargin, 0)); SetBorder(views::CreateEmptyBorder(0, 0, kAvatarImageViewBottomMargin, 0));
} }
// views::ImageVIew: // views::ImageVIew:
...@@ -303,6 +309,93 @@ class SyncImageView : public views::ImageView { ...@@ -303,6 +309,93 @@ class SyncImageView : public views::ImageView {
const ProfileMenuViewBase* root_view_; const ProfileMenuViewBase* root_view_;
}; };
void BuildProfileTitleAndSubtitle(views::View* parent,
const base::string16& title,
const base::string16& subtitle) {
if (!title.empty()) {
parent->AddChildView(std::make_unique<views::Label>(
title, views::style::CONTEXT_DIALOG_TITLE));
}
if (!subtitle.empty()) {
parent->AddChildView(std::make_unique<views::Label>(
subtitle, views::style::CONTEXT_LABEL, views::style::STYLE_SECONDARY));
}
}
// This function deals with the somewhat complicted layout to build the part of
// the profile identity info that has a colored background.
void BuildProfileBackgroundContainer(
views::View* parent,
std::unique_ptr<views::View> heading_label,
base::Optional<SkColor> background_color,
std::unique_ptr<views::View> avatar_image_view,
std::unique_ptr<views::View> edit_button) {
constexpr int kExtraMarginInsideProfileBackground = 2;
views::View* profile_background_container =
parent->AddChildView(std::make_unique<views::View>());
gfx::Insets background_container_insets(
kExtraMarginInsideProfileBackground, kExtraMarginInsideProfileBackground,
/*bottom=*/0, kExtraMarginInsideProfileBackground);
if (edit_button) {
// Compensate for the edit button on the right with an extra margin on the
// left so that the rest is centered.
background_container_insets.set_left(background_container_insets.left() +
kCircularImageButtonSize);
}
profile_background_container
->SetLayoutManager(std::make_unique<views::FlexLayout>())
->SetOrientation(views::LayoutOrientation::kHorizontal)
.SetCrossAxisAlignment(views::LayoutAlignment::kStart)
.SetInteriorMargin(background_container_insets);
if (background_color.has_value()) {
// The bottom background edge should match the center of the identity image.
gfx::Insets background_insets(
0, 0,
/*bottom=*/kIdentityImageSize / 2 + kAvatarImageViewBottomMargin, 0);
profile_background_container->SetBackground(
views::CreateBackgroundFromPainter(
views::Painter::CreateSolidRoundRectPainter(
background_color.value(),
/*radius=*/kDefaultMargin, background_insets)));
}
// The |heading_and_image_container| is on the left and it stretches almost
// the full width. It contains the profile heading and the avatar image.
views::View* heading_and_image_container =
profile_background_container->AddChildView(
std::make_unique<views::View>());
heading_and_image_container->SetProperty(
views::kFlexBehaviorKey,
views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred,
views::MaximumFlexSizeRule::kUnbounded)
.WithOrder(1));
heading_and_image_container
->SetLayoutManager(std::make_unique<views::FlexLayout>())
->SetOrientation(views::LayoutOrientation::kVertical)
.SetMainAxisAlignment(views::LayoutAlignment::kCenter)
.SetCrossAxisAlignment(views::LayoutAlignment::kCenter)
.SetInteriorMargin(gfx::Insets(/*top=*/kDefaultMargin, 0, 0, 0));
if (heading_label) {
heading_label->SetBorder(
views::CreateEmptyBorder(gfx::Insets(/*vertical=*/kDefaultMargin, 0)));
heading_and_image_container->AddChildView(std::move(heading_label));
}
heading_and_image_container->AddChildView(std::move(avatar_image_view));
// The |edit_button| is on the right and has fixed width.
if (edit_button) {
edit_button->SetProperty(
views::kFlexBehaviorKey,
views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred,
views::MaximumFlexSizeRule::kPreferred)
.WithOrder(2));
profile_background_container->AddChildView(std::move(edit_button));
}
}
} // namespace } // namespace
// ProfileMenuViewBase --------------------------------------------------------- // ProfileMenuViewBase ---------------------------------------------------------
...@@ -350,9 +443,12 @@ ProfileMenuViewBase* ProfileMenuViewBase::GetBubbleForTesting() { ...@@ -350,9 +443,12 @@ ProfileMenuViewBase* ProfileMenuViewBase::GetBubbleForTesting() {
} }
ProfileMenuViewBase::EditButtonParams::EditButtonParams( ProfileMenuViewBase::EditButtonParams::EditButtonParams(
const gfx::VectorIcon* edit_icon,
const base::string16& edit_tooltip_text, const base::string16& edit_tooltip_text,
base::RepeatingClosure edit_action) base::RepeatingClosure edit_action)
: edit_tooltip_text(edit_tooltip_text), edit_action(edit_action) {} : edit_icon(edit_icon),
edit_tooltip_text(edit_tooltip_text),
edit_action(edit_action) {}
ProfileMenuViewBase::EditButtonParams::~EditButtonParams() = default; ProfileMenuViewBase::EditButtonParams::~EditButtonParams() = default;
...@@ -397,51 +493,92 @@ void ProfileMenuViewBase::SetProfileIdentityInfo( ...@@ -397,51 +493,92 @@ void ProfileMenuViewBase::SetProfileIdentityInfo(
const base::string16& subtitle, const base::string16& subtitle,
const gfx::VectorIcon& icon, const gfx::VectorIcon& icon,
ui::NativeTheme::ColorId icon_color_id) { ui::NativeTheme::ColorId icon_color_id) {
constexpr int kTopMargin = kMenuEdgeMargin; constexpr int kBottomMargin = kDefaultMargin;
constexpr int kBottomMargin = kDefaultVerticalMargin; const bool new_design =
constexpr int kHorizontalMargin = kMenuEdgeMargin; base::FeatureList::IsEnabled(features::kNewProfilePicker);
if (!profile_name.empty()) {
DCHECK(edit_button_params.has_value());
constexpr int kHeadingInsidePadding = kDefaultVerticalMargin;
const SkColor kBackgroundColor = GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_HighlightedMenuItemBackgroundColor);
heading_container_->RemoveAllChildViews(/*delete_children=*/true);
heading_container_->SetLayoutManager(std::make_unique<views::FillLayout>());
heading_container_->SetBackground(
views::CreateSolidBackground(kBackgroundColor));
views::LabelButton* button = heading_container_->AddChildView(
std::make_unique<HoverButton>(this, profile_name));
button->SetEnabledTextColors(views::style::GetColor(
*this, views::style::CONTEXT_LABEL, views::style::STYLE_SECONDARY));
button->SetTooltipText(edit_button_params->edit_tooltip_text);
button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
button->SetBorder(
views::CreateEmptyBorder(gfx::Insets(kHeadingInsidePadding)));
RegisterClickAction(button, std::move(edit_button_params->edit_action));
}
identity_info_container_->RemoveAllChildViews(/*delete_children=*/true); identity_info_container_->RemoveAllChildViews(/*delete_children=*/true);
// In the new design, the colored background must only have|kDefaultMargin|
// margins so this container cannot have larger margins. In this case, further
// margins will be added by children views.
const int container_margin = new_design ? kDefaultMargin : kMenuEdgeMargin;
identity_info_container_->SetLayoutManager( identity_info_container_->SetLayoutManager(
CreateBoxLayout(views::BoxLayout::Orientation::kVertical, CreateBoxLayout(views::BoxLayout::Orientation::kVertical,
views::BoxLayout::CrossAxisAlignment::kCenter, views::BoxLayout::CrossAxisAlignment::kStretch,
gfx::Insets(kTopMargin, kHorizontalMargin, kBottomMargin, gfx::Insets(container_margin, container_margin,
kHorizontalMargin))); kBottomMargin, container_margin)));
auto avatar_image_view =
std::make_unique<AvatarImageView>(image, this, icon, icon_color_id);
if (!new_design) {
if (!profile_name.empty()) {
DCHECK(edit_button_params.has_value());
const SkColor kBackgroundColor = GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_HighlightedMenuItemBackgroundColor);
heading_container_->RemoveAllChildViews(/*delete_children=*/true);
heading_container_->SetLayoutManager(
std::make_unique<views::FillLayout>());
heading_container_->SetBackground(
views::CreateSolidBackground(kBackgroundColor));
views::LabelButton* heading_button = heading_container_->AddChildView(
std::make_unique<HoverButton>(this, profile_name));
heading_button->SetEnabledTextColors(views::style::GetColor(
*this, views::style::CONTEXT_LABEL, views::style::STYLE_SECONDARY));
heading_button->SetTooltipText(edit_button_params->edit_tooltip_text);
heading_button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
heading_button->SetBorder(
views::CreateEmptyBorder(gfx::Insets(kDefaultMargin)));
RegisterClickAction(heading_button, edit_button_params->edit_action);
}
identity_info_container_->AddChildView( identity_info_container_->AddChildView(std::move(avatar_image_view));
std::make_unique<AvatarImageView>(image, this, icon, icon_color_id)); BuildProfileTitleAndSubtitle(/*parent=*/identity_info_container_, title,
subtitle);
return;
}
if (!title.empty()) { base::Optional<SkColor> background_color;
identity_info_container_->AddChildView(std::make_unique<views::Label>( // Only show a colored background when there is an edit button (this
title, views::style::CONTEXT_DIALOG_TITLE)); // coincides with the profile being a real profile that can be edited).
if (edit_button_params.has_value()) {
// We get the theme provider from the anchor view since our widget hasn't
// been created yet.
const ui::ThemeProvider* theme_provider =
anchor_button_->GetThemeProvider();
DCHECK(theme_provider);
// TODO(crbug.com/1099286): Make the |heading_label| and |edit_button| have
// good contrast against |background_color|.
background_color =
theme_provider->GetColor(ThemeProperties::COLOR_FRAME_ACTIVE);
} }
if (!subtitle.empty()) { std::unique_ptr<views::Label> heading_label;
identity_info_container_->AddChildView(std::make_unique<views::Label>( if (!profile_name.empty()) {
subtitle, views::style::CONTEXT_LABEL, views::style::STYLE_SECONDARY)); views::Label::CustomFont font = {
views::Label::GetDefaultFontList()
.DeriveWithSizeDelta(2)
.DeriveWithWeight(gfx::Font::Weight::BOLD)};
heading_label = std::make_unique<views::Label>(profile_name, font);
heading_label->SetElideBehavior(gfx::ELIDE_TAIL);
heading_label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
} }
std::unique_ptr<views::View> edit_button;
if (edit_button_params.has_value()) {
edit_button = std::make_unique<CircularImageButton>(
this, *edit_button_params->edit_icon,
edit_button_params->edit_tooltip_text);
RegisterClickAction(edit_button.get(), edit_button_params->edit_action);
}
BuildProfileBackgroundContainer(
/*parent=*/identity_info_container_, std::move(heading_label),
background_color, std::move(avatar_image_view), std::move(edit_button));
BuildProfileTitleAndSubtitle(/*parent=*/identity_info_container_, title,
subtitle);
} }
void ProfileMenuViewBase::SetSyncInfo( void ProfileMenuViewBase::SetSyncInfo(
...@@ -480,7 +617,7 @@ void ProfileMenuViewBase::SetSyncInfo( ...@@ -480,7 +617,7 @@ void ProfileMenuViewBase::SetSyncInfo(
border_color), border_color),
gfx::Insets(kInsidePadding))); gfx::Insets(kInsidePadding)));
sync_info_container_->SetProperty( sync_info_container_->SetProperty(
views::kMarginsKey, gfx::Insets(kDefaultVerticalMargin, kMenuEdgeMargin)); views::kMarginsKey, gfx::Insets(kDefaultMargin, kMenuEdgeMargin));
// Add icon + description at the top. // Add icon + description at the top.
views::View* description_container = views::View* description_container =
...@@ -523,7 +660,7 @@ void ProfileMenuViewBase::AddShortcutFeatureButton( ...@@ -523,7 +660,7 @@ void ProfileMenuViewBase::AddShortcutFeatureButton(
views::BoxLayout* layout = shortcut_features_container_->SetLayoutManager( views::BoxLayout* layout = shortcut_features_container_->SetLayoutManager(
std::make_unique<views::BoxLayout>( std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, views::BoxLayout::Orientation::kHorizontal,
gfx::Insets(/*top=*/kDefaultVerticalMargin / 2, 0, gfx::Insets(/*top=*/kDefaultMargin / 2, 0,
/*bottom=*/kMenuEdgeMargin, 0), /*bottom=*/kMenuEdgeMargin, 0),
kButtonSpacing)); kButtonSpacing));
layout->set_main_axis_alignment( layout->set_main_axis_alignment(
...@@ -569,8 +706,8 @@ void ProfileMenuViewBase::SetProfileManagementHeading( ...@@ -569,8 +706,8 @@ void ProfileMenuViewBase::SetProfileManagementHeading(
/*delete_children=*/true); /*delete_children=*/true);
profile_mgmt_separator_container_->SetLayoutManager( profile_mgmt_separator_container_->SetLayoutManager(
std::make_unique<views::FillLayout>()); std::make_unique<views::FillLayout>());
profile_mgmt_separator_container_->SetBorder(views::CreateEmptyBorder( profile_mgmt_separator_container_->SetBorder(
gfx::Insets(kDefaultVerticalMargin, /*horizontal=*/0))); views::CreateEmptyBorder(gfx::Insets(kDefaultMargin, /*horizontal=*/0)));
profile_mgmt_separator_container_->AddChildView( profile_mgmt_separator_container_->AddChildView(
std::make_unique<views::Separator>()); std::make_unique<views::Separator>());
...@@ -579,8 +716,8 @@ void ProfileMenuViewBase::SetProfileManagementHeading( ...@@ -579,8 +716,8 @@ void ProfileMenuViewBase::SetProfileManagementHeading(
/*delete_children=*/true); /*delete_children=*/true);
profile_mgmt_heading_container_->SetLayoutManager( profile_mgmt_heading_container_->SetLayoutManager(
std::make_unique<views::FillLayout>()); std::make_unique<views::FillLayout>());
profile_mgmt_heading_container_->SetBorder(views::CreateEmptyBorder( profile_mgmt_heading_container_->SetBorder(
gfx::Insets(kDefaultVerticalMargin, kMenuEdgeMargin))); views::CreateEmptyBorder(gfx::Insets(kDefaultMargin, kMenuEdgeMargin)));
// Add heading. // Add heading.
views::Label* label = profile_mgmt_heading_container_->AddChildView( views::Label* label = profile_mgmt_heading_container_->AddChildView(
......
...@@ -69,13 +69,14 @@ class ProfileMenuViewBase : public content::WebContentsDelegate, ...@@ -69,13 +69,14 @@ class ProfileMenuViewBase : public content::WebContentsDelegate,
kNoPrimaryAccount, kNoPrimaryAccount,
}; };
// TODO(crbug.com/1099286): Add the edit icon into this struct.
struct EditButtonParams { struct EditButtonParams {
EditButtonParams(const base::string16& edit_tooltip_text, EditButtonParams(const gfx::VectorIcon* edit_icon,
const base::string16& edit_tooltip_text,
base::RepeatingClosure edit_action); base::RepeatingClosure edit_action);
EditButtonParams(const EditButtonParams&); EditButtonParams(const EditButtonParams&);
~EditButtonParams(); ~EditButtonParams();
const gfx::VectorIcon* edit_icon;
base::string16 edit_tooltip_text; base::string16 edit_tooltip_text;
base::RepeatingClosure edit_action; base::RepeatingClosure edit_action;
}; };
......
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