Commit 1a5e0788 authored by Thomas Tangl's avatar Thomas Tangl Committed by Commit Bot

[profile-menu] Add account feature buttons

Account feature buttons are added at the bottom
of the bordered box.

Screenshot:
https://drive.google.com/file/d/17tsNrV3HmOZD9yVNp6VwfbJ46GOAuvQu/view?usp=sharing

Flag: profile-menu-revamp

Bug: 995720
Change-Id: Icbd286cdf388742d710688e6c93cd44d1ad16e9a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1803438
Commit-Queue: Thomas Tangl <tangltom@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Cr-Commit-Position: refs/heads/master@{#696737}
parent 1512a4cd
......@@ -170,6 +170,7 @@ void ProfileMenuView::BuildMenu() {
}
BuildIdentity();
BuildAutofillButtons();
BuildAccountFeatureButtons();
BuildSelectableProfiles();
}
......@@ -199,8 +200,14 @@ void ProfileMenuView::OnManageGoogleAccountButtonClicked() {
// TODO(crbug.com/995757): Remove user action.
base::RecordAction(
base::UserMetricsAction("ProfileChooser_ManageGoogleAccountClicked"));
DCHECK(!dice_accounts_.empty());
NavigateToGoogleAccountPage(browser()->profile(), dice_accounts_[0].email);
Profile* profile = browser()->profile();
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(profile);
DCHECK(identity_manager->HasUnconsentedPrimaryAccount());
NavigateToGoogleAccountPage(
profile, identity_manager->GetUnconsentedPrimaryAccountInfo().email);
}
void ProfileMenuView::OnPasswordsButtonClicked() {
......@@ -414,6 +421,34 @@ void ProfileMenuView::BuildAutofillButtons() {
base::Unretained(this)));
}
void ProfileMenuView::BuildAccountFeatureButtons() {
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(browser()->profile());
if (!identity_manager->HasUnconsentedPrimaryAccount())
return;
AddAccountFeatureButton(
#if defined(GOOGLE_CHROME_BUILD)
// The Google G icon needs to be shrunk, so it won't look too big
// compared to the other icons.
ImageForMenu(kGoogleGLogoIcon, /*icon_to_image_ratio=*/0.75),
#else
gfx::ImageSkia(),
#endif
l10n_util::GetStringUTF16(IDS_SETTINGS_MANAGE_GOOGLE_ACCOUNT),
base::BindRepeating(&ProfileMenuView::OnManageGoogleAccountButtonClicked,
base::Unretained(this)));
if (!identity_manager->HasPrimaryAccount()) {
// The sign-out button is only shown when sync is off.
AddAccountFeatureButton(
ImageForMenu(kSignOutIcon),
l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_SIGN_OUT),
base::BindRepeating(&ProfileMenuView::OnSignoutButtonClicked,
base::Unretained(this)));
}
}
void ProfileMenuView::BuildSelectableProfiles() {
auto profile_entries = g_browser_process->profile_manager()
->GetProfileAttributesStorage()
......
......@@ -100,6 +100,7 @@ class ProfileMenuView : public ProfileMenuViewBase, public AvatarMenuObserver {
// Helper methods for building the menu.
void BuildIdentity();
void BuildAutofillButtons();
void BuildAccountFeatureButtons();
void BuildSelectableProfiles();
// Adds the profile chooser view.
......
......@@ -25,6 +25,8 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/image/canvas_image_source.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/button/md_text_button.h"
......@@ -47,6 +49,7 @@ ProfileMenuViewBase* g_profile_bubble_ = nullptr;
constexpr int kMenuWidth = 288;
constexpr int kIconSize = 16;
constexpr int kIdentityImageSize = 64;
constexpr int kMaxImageSize = kIdentityImageSize;
// If the bubble is too large to fit on the screen, it still needs to be at
// least this tall to show one row.
......@@ -56,6 +59,15 @@ constexpr int kMinimumScrollableContentHeight = 40;
// the menu items.
constexpr int kMenuEdgeMargin = 16;
gfx::ImageSkia SizeImage(const gfx::ImageSkia& image, int size) {
return gfx::ImageSkiaOperations::CreateResizedImage(
image, skia::ImageOperations::RESIZE_BEST, gfx::Size(size, size));
}
gfx::ImageSkia ColorImage(const gfx::ImageSkia& image, SkColor color) {
return gfx::ImageSkiaOperations::CreateColorMask(image, color);
}
std::unique_ptr<views::BoxLayout> CreateBoxLayout(
views::BoxLayout::Orientation orientation,
views::BoxLayout::CrossAxisAlignment cross_axis_alignment) {
......@@ -219,7 +231,7 @@ void ProfileMenuViewBase::AddShortcutFeatureButton(
const gfx::VectorIcon& icon,
const base::string16& text,
base::RepeatingClosure action) {
constexpr int kTopMargin = 8;
constexpr int kVerticalMargin = 8;
constexpr int kButtonSpacing = 6;
constexpr int kIconSize = 16;
constexpr int kIconPadding = 6;
......@@ -235,7 +247,7 @@ void ProfileMenuViewBase::AddShortcutFeatureButton(
views::BoxLayout* layout = shortcut_features_container_->SetLayoutManager(
std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal,
gfx::Insets(kTopMargin, 0, 0, 0), kButtonSpacing));
gfx::Insets(kVerticalMargin, 0), kButtonSpacing));
layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
}
......@@ -255,6 +267,32 @@ void ProfileMenuViewBase::AddShortcutFeatureButton(
RegisterClickAction(button, std::move(action));
}
void ProfileMenuViewBase::AddAccountFeatureButton(
const gfx::ImageSkia& icon,
const base::string16& text,
base::RepeatingClosure action) {
constexpr int kIconSize = 16;
const SkColor kIconColor =
ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
ui::NativeTheme::kColorId_DefaultIconColor);
// Initialize layout if this is the first time a button is added.
if (!account_features_container_->GetLayoutManager()) {
account_features_container_->SetLayoutManager(
std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
}
account_features_container_->AddChildView(
std::make_unique<views::Separator>());
views::Button* button =
account_features_container_->AddChildView(std::make_unique<HoverButton>(
this, SizeImage(ColorImage(icon, kIconColor), kIconSize), text));
RegisterClickAction(button, std::move(action));
}
void ProfileMenuViewBase::AddSelectableProfile(const gfx::Image& image,
const base::string16& name,
base::RepeatingClosure action) {
......@@ -277,6 +315,19 @@ void ProfileMenuViewBase::AddSelectableProfile(const gfx::Image& image,
RegisterClickAction(button, std::move(action));
}
gfx::ImageSkia ProfileMenuViewBase::ImageForMenu(const gfx::VectorIcon& icon,
float icon_to_image_ratio) {
const SkColor kIconColor =
ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
ui::NativeTheme::kColorId_DefaultIconColor);
const int padding =
static_cast<int>(kMaxImageSize * (1.0 - icon_to_image_ratio) / 2.0);
auto sized_icon =
gfx::CreateVectorIcon(icon, kMaxImageSize - 2 * padding, kIconColor);
return gfx::CanvasImageSource::CreatePadded(sized_icon, gfx::Insets(padding));
}
ax::mojom::Role ProfileMenuViewBase::GetAccessibleWindowRole() {
// Return |ax::mojom::Role::kDialog| which will make screen readers announce
// the following in the listed order:
......@@ -368,6 +419,8 @@ void ProfileMenuViewBase::Reset() {
bordered_box_container->AddChildView(std::make_unique<views::View>());
shortcut_features_container_ =
bordered_box_container->AddChildView(std::make_unique<views::View>());
account_features_container_ =
bordered_box_container->AddChildView(std::make_unique<views::View>());
components->AddChildView(
CreateBorderedBoxView(std::move(bordered_box_container)));
......
......@@ -100,9 +100,17 @@ class ProfileMenuViewBase : public content::WebContentsDelegate,
void AddShortcutFeatureButton(const gfx::VectorIcon& icon,
const base::string16& text,
base::RepeatingClosure action);
void AddAccountFeatureButton(const gfx::ImageSkia& icon,
const base::string16& text,
base::RepeatingClosure action);
void AddSelectableProfile(const gfx::Image& image,
const base::string16& name,
base::RepeatingClosure action);
// 0 < |icon_to_image_ratio| <= 1 is the size ratio of |icon| in the returned
// image. E.g. a value of 0.8 means that |icon| only takes up 80% of the
// returned image, with the rest being padding around it.
gfx::ImageSkia ImageForMenu(const gfx::VectorIcon& icon,
float icon_to_image_ratio = 1.0f);
// Initializes a new group of menu items. A separator is added before them if
// |add_separator| is true.
......@@ -203,6 +211,7 @@ class ProfileMenuViewBase : public content::WebContentsDelegate,
// Component containers.
views::View* identity_info_container_ = nullptr;
views::View* shortcut_features_container_ = nullptr;
views::View* account_features_container_ = nullptr;
views::View* selectable_profiles_container_ = nullptr;
CloseBubbleOnTabActivationHelper close_bubble_helper_;
......
......@@ -26,6 +26,7 @@
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/scoped_account_consistency.h"
#include "chrome/browser/sync/test/integration/secondary_account_helper.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/browser_finder.h"
......@@ -48,6 +49,7 @@
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/extension_registry.h"
#include "services/network/test/test_url_loader_factory.h"
#include "ui/events/event_utils.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/webview/webview.h"
......@@ -709,10 +711,11 @@ class ProfileMenuClickTest_WithPrimaryAccount : public ProfileMenuClickTest {
public:
// List of actionable items in the correct order as they appear in the menu.
// If a new button is added to the menu, it should also be added to this list.
static constexpr ProfileMenuView::ActionableItem kOrderedActionableItems[4] =
static constexpr ProfileMenuView::ActionableItem kOrderedActionableItems[5] =
{ProfileMenuView::ActionableItem::kPasswordsButton,
ProfileMenuView::ActionableItem::kCreditCardsButton,
ProfileMenuView::ActionableItem::kAddressesButton,
ProfileMenuView::ActionableItem::kManageGoogleAccountButton,
// The first button is added again to finish the cycle and test that
// there are no other buttons at the end.
ProfileMenuView::ActionableItem::kPasswordsButton};
......@@ -748,3 +751,74 @@ INSTANTIATE_TEST_SUITE_P(
size_t(0),
base::size(
ProfileMenuClickTest_WithPrimaryAccount::kOrderedActionableItems)));
class ProfileMenuClickTest_WithUnconsentedPrimaryAccount
: public ProfileMenuClickTest {
public:
// List of actionable items in the correct order as they appear in the menu.
// If a new button is added to the menu, it should also be added to this list.
static constexpr ProfileMenuView::ActionableItem kOrderedActionableItems[6] =
{ProfileMenuView::ActionableItem::kPasswordsButton,
ProfileMenuView::ActionableItem::kCreditCardsButton,
ProfileMenuView::ActionableItem::kAddressesButton,
ProfileMenuView::ActionableItem::kManageGoogleAccountButton,
ProfileMenuView::ActionableItem::kSignoutButton,
// The first button is added again to finish the cycle and test that
// there are no other buttons at the end.
ProfileMenuView::ActionableItem::kPasswordsButton};
ProfileMenuClickTest_WithUnconsentedPrimaryAccount() = default;
void SetUpInProcessBrowserTestFixture() override {
// This is required to support (fake) secondary-account-signin (based on
// cookies) in tests. Without this, the real GaiaCookieManagerService would
// try talking to Google servers which of course wouldn't work in tests.
test_signin_client_factory_ =
secondary_account_helper::SetUpSigninClient(&test_url_loader_factory_);
ProfileMenuClickTest::SetUpInProcessBrowserTestFixture();
}
ProfileMenuView::ActionableItem GetExpectedActionableItemAtIndex(
size_t index) override {
return kOrderedActionableItems[index];
}
void SetUnconsentedPrimaryAccount() {
signin::MakeAccountAvailableWithCookies(
IdentityManagerFactory::GetForProfile(browser()->profile()),
&test_url_loader_factory_, "account@example.com", "dummyId");
}
private:
secondary_account_helper::ScopedSigninClientFactory
test_signin_client_factory_;
network::TestURLLoaderFactory test_url_loader_factory_;
DISALLOW_COPY_AND_ASSIGN(ProfileMenuClickTest_WithUnconsentedPrimaryAccount);
};
// static
constexpr ProfileMenuView::ActionableItem
ProfileMenuClickTest_WithUnconsentedPrimaryAccount::kOrderedActionableItems
[];
IN_PROC_BROWSER_TEST_P(ProfileMenuClickTest_WithUnconsentedPrimaryAccount,
SetupAndRunTest) {
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(browser()->profile());
ASSERT_FALSE(identity_manager->HasUnconsentedPrimaryAccount());
SetUnconsentedPrimaryAccount();
ASSERT_FALSE(identity_manager->HasPrimaryAccount());
ASSERT_TRUE(identity_manager->HasUnconsentedPrimaryAccount());
RunTest();
}
INSTANTIATE_TEST_SUITE_P(
,
ProfileMenuClickTest_WithUnconsentedPrimaryAccount,
::testing::Range(
size_t(0),
base::size(ProfileMenuClickTest_WithUnconsentedPrimaryAccount::
kOrderedActionableItems)));
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