Commit b8bfc2a4 authored by Thomas Tangl's avatar Thomas Tangl Committed by Commit Bot

[Dice] Add accounts submenu to user menu

When the "Sync to another account" button is clicked in the DICE
user menu, a submenu showing a list of web accounts (other than the
first one) should be displayed. This CL adds this feature.

Mocks can be found in the bug report.

Bug: 786369
Change-Id: I32b4f3f19472a67e7aa203426692739030acc4c9
Reviewed-on: https://chromium-review.googlesource.com/893570
Commit-Queue: Thomas Tangl <tangltom@chromium.org>
Reviewed-by: default avatarMihai Sardarescu <msarda@chromium.org>
Reviewed-by: default avatarTrent Apted <tapted@chromium.org>
Cr-Commit-Position: refs/heads/master@{#534036}
parent da0d0c50
...@@ -7570,6 +7570,9 @@ I don't think this site should be blocked! ...@@ -7570,6 +7570,9 @@ I don't think this site should be blocked!
<message name="IDS_PROFILES_DICE_SIGNIN_WITH_ANOTHER_ACCOUNT_BUTTON" desc="Button to sign in and turn on Sync with another web account."> <message name="IDS_PROFILES_DICE_SIGNIN_WITH_ANOTHER_ACCOUNT_BUTTON" desc="Button to sign in and turn on Sync with another web account.">
Sync to another account Sync to another account
</message> </message>
<message name="IDS_PROFILES_DICE_USE_ANOTHER_ACCOUNT_BUTTON" desc="Button to use another account to sign in and turn on Sync.">
Use another account
</message>
<message name="IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON" desc="Text of the ok button on the account removal view in the avatar menu bubble."> <message name="IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON" desc="Text of the ok button on the account removal view in the avatar menu bubble.">
Remove account Remove account
</message> </message>
......
...@@ -2205,6 +2205,8 @@ split_static_library("ui") { ...@@ -2205,6 +2205,8 @@ split_static_library("ui") {
"views/profiles/avatar_button_style.h", "views/profiles/avatar_button_style.h",
"views/profiles/badged_profile_photo.cc", "views/profiles/badged_profile_photo.cc",
"views/profiles/badged_profile_photo.h", "views/profiles/badged_profile_photo.h",
"views/profiles/dice_accounts_menu.cc",
"views/profiles/dice_accounts_menu.h",
"views/profiles/profile_chooser_view.cc", "views/profiles/profile_chooser_view.cc",
"views/profiles/profile_chooser_view.h", "views/profiles/profile_chooser_view.h",
"webui/app_launcher_page_ui.cc", "webui/app_launcher_page_ui.cc",
......
// Copyright 2018 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/profiles/dice_accounts_menu.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile_avatar_icon_util.h"
#include "chrome/grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/view.h"
namespace {
constexpr int kAvatarIconSize = 16;
gfx::Image SizeAndCircleIcon(const gfx::Image& icon) {
return profiles::GetSizedAvatarIcon(icon, true, kAvatarIconSize,
kAvatarIconSize, profiles::SHAPE_CIRCLE);
}
} // namespace
DiceAccountsMenu::DiceAccountsMenu(const std::vector<AccountInfo>& accounts,
const std::vector<gfx::Image>& icons)
: menu_(this), accounts_(accounts) {
DCHECK_EQ(accounts.size(), icons.size());
gfx::Image default_icon =
ui::ResourceBundle::GetSharedInstance().GetImageNamed(
profiles::GetPlaceholderAvatarIconResourceID());
// Add a menu item for each account.
menu_.AddSeparator(ui::SPACING_SEPARATOR);
for (size_t idx = 0; idx < accounts.size(); idx++) {
menu_.AddItem(idx, base::UTF8ToUTF16(accounts[idx].email));
menu_.SetIcon(
menu_.GetIndexOfCommandId(idx),
SizeAndCircleIcon(icons[idx].IsEmpty() ? default_icon : icons[idx]));
menu_.AddSeparator(ui::SPACING_SEPARATOR);
}
// Add the "Use another account" button at the bottom.
menu_.AddItem(
accounts.size(),
l10n_util::GetStringUTF16(IDS_PROFILES_DICE_USE_ANOTHER_ACCOUNT_BUTTON));
menu_.SetIcon(menu_.GetIndexOfCommandId(accounts.size()),
SizeAndCircleIcon(default_icon));
menu_.AddSeparator(ui::SPACING_SEPARATOR);
}
void DiceAccountsMenu::Show(views::View* anchor_view) {
DCHECK(!runner_);
runner_ =
std::make_unique<views::MenuRunner>(&menu_, views::MenuRunner::COMBOBOX);
runner_->RunMenuAt(anchor_view->GetWidget(), nullptr,
anchor_view->GetBoundsInScreen(),
views::MENU_ANCHOR_BUBBLE_BELOW, ui::MENU_SOURCE_MOUSE);
}
DiceAccountsMenu::~DiceAccountsMenu() {}
bool DiceAccountsMenu::IsCommandIdChecked(int command_id) const {
return false;
}
bool DiceAccountsMenu::IsCommandIdEnabled(int command_id) const {
return true;
}
void DiceAccountsMenu::ExecuteCommand(int id, int event_flags) {
NOTIMPLEMENTED() << "Selected id: " << id;
}
// Copyright 2018 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.
#ifndef CHROME_BROWSER_UI_VIEWS_PROFILES_DICE_ACCOUNTS_MENU_H_
#define CHROME_BROWSER_UI_VIEWS_PROFILES_DICE_ACCOUNTS_MENU_H_
#include <vector>
#include "components/signin/core/browser/account_info.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/gfx/image/image.h"
#include "ui/views/controls/menu/menu_runner.h"
namespace views {
class View;
} // namespace views
// Accounts menu class used to select an account for turning on Sync when DICE
// is enabled.
// TODO(tangltom): Add action handling.
class DiceAccountsMenu : public ui::SimpleMenuModel::Delegate {
public:
// Builds the accounts menu. Each account from |accounts| is placed in a menu
// item showing the email and the corresponding icon from |icons|. The last
// item in the accounts menu is the "Use another accounts" button. Separators
// are added at the top, bottom and between each item to increase the spacing.
DiceAccountsMenu(const std::vector<AccountInfo>& accounts,
const std::vector<gfx::Image>& icons);
~DiceAccountsMenu() override;
// Shows the accounts menu below |anchor_view|. This method can only be called
// once.
void Show(views::View* anchor_view);
private:
// Overridden from ui::SimpleMenuModel::Delegate:
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
void ExecuteCommand(int command_id, int event_flags) override;
ui::SimpleMenuModel menu_;
std::unique_ptr<views::MenuRunner> runner_;
std::vector<AccountInfo> accounts_;
DISALLOW_COPY_AND_ASSIGN(DiceAccountsMenu);
};
#endif // CHROME_BROWSER_UI_VIEWS_PROFILES_DICE_ACCOUNTS_MENU_H_
...@@ -184,6 +184,18 @@ BadgedProfilePhoto::BadgeType GetProfileBadgeType(Profile* profile) { ...@@ -184,6 +184,18 @@ BadgedProfilePhoto::BadgeType GetProfileBadgeType(Profile* profile) {
: BadgedProfilePhoto::BADGE_TYPE_SUPERVISOR; : BadgedProfilePhoto::BADGE_TYPE_SUPERVISOR;
} }
std::vector<gfx::Image> GetImagesForAccounts(
const std::vector<AccountInfo>& accounts,
Profile* profile) {
AccountTrackerService* tracker_service =
AccountTrackerServiceFactory::GetForProfile(profile);
std::vector<gfx::Image> images;
for (auto account : accounts) {
images.push_back(tracker_service->GetAccountImage(account.account_id));
}
return images;
}
} // namespace } // namespace
// A title card with one back button left aligned and one label center aligned. // A title card with one back button left aligned and one label center aligned.
...@@ -374,6 +386,7 @@ void ProfileChooserView::ResetView() { ...@@ -374,6 +386,7 @@ void ProfileChooserView::ResetView() {
gaia_signin_cancel_button_ = nullptr; gaia_signin_cancel_button_ = nullptr;
remove_account_button_ = nullptr; remove_account_button_ = nullptr;
account_removal_cancel_button_ = nullptr; account_removal_cancel_button_ = nullptr;
sync_to_another_account_button_ = nullptr;
} }
void ProfileChooserView::Init() { void ProfileChooserView::Init() {
...@@ -652,8 +665,16 @@ void ProfileChooserView::ButtonPressed(views::Button* sender, ...@@ -652,8 +665,16 @@ void ProfileChooserView::ButtonPressed(views::Button* sender,
} else if (sender == signin_current_profile_button_) { } else if (sender == signin_current_profile_button_) {
ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN); ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN);
} else if (sender == signin_with_gaia_account_button_) { } else if (sender == signin_with_gaia_account_button_) {
signin_ui_util::EnableSync(browser_, dice_sync_promo_account_, DCHECK(!dice_sync_promo_accounts_.empty());
signin_ui_util::EnableSync(browser_, dice_sync_promo_accounts_[0],
access_point_); access_point_);
} else if (sender == sync_to_another_account_button_) {
// Display a submenu listing the GAIA web accounts (without the first one).
std::vector<AccountInfo> accounts(dice_sync_promo_accounts_.begin() + 1,
dice_sync_promo_accounts_.end());
dice_accounts_menu_ = std::make_unique<DiceAccountsMenu>(
accounts, GetImagesForAccounts(accounts, browser_->profile()));
dice_accounts_menu_->Show(sender);
} else { } else {
// Either one of the "other profiles", or one of the profile accounts // Either one of the "other profiles", or one of the profile accounts
// buttons was pressed. // buttons was pressed.
...@@ -997,7 +1018,7 @@ views::View* ProfileChooserView::CreateCurrentProfileView( ...@@ -997,7 +1018,7 @@ views::View* ProfileChooserView::CreateCurrentProfileView(
views::View* ProfileChooserView::CreateDiceSigninView() { views::View* ProfileChooserView::CreateDiceSigninView() {
// Fetch signed in GAIA web accounts. // Fetch signed in GAIA web accounts.
std::vector<AccountInfo> accounts = dice_sync_promo_accounts_ =
signin_ui_util::GetAccountsForDicePromos(browser_->profile()); signin_ui_util::GetAccountsForDicePromos(browser_->profile());
// Create a view that holds an illustration and a promo, which includes a // Create a view that holds an illustration and a promo, which includes a
...@@ -1006,7 +1027,8 @@ views::View* ProfileChooserView::CreateDiceSigninView() { ...@@ -1006,7 +1027,8 @@ views::View* ProfileChooserView::CreateDiceSigninView() {
// |kIllustrationPromoOverlap|. The illustration will be changed in the // |kIllustrationPromoOverlap|. The illustration will be changed in the
// future, once the final asset is ready. // future, once the final asset is ready.
constexpr int kIllustrationPromoOverlap = 48; constexpr int kIllustrationPromoOverlap = 48;
const int additional_bottom_spacing = accounts.empty() ? 0 : 8; const int additional_bottom_spacing =
dice_sync_promo_accounts_.empty() ? 0 : 8;
views::View* view = new views::View(); views::View* view = new views::View();
view->SetLayoutManager(std::make_unique<views::BoxLayout>( view->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical, views::BoxLayout::kVertical,
...@@ -1044,7 +1066,7 @@ views::View* ProfileChooserView::CreateDiceSigninView() { ...@@ -1044,7 +1066,7 @@ views::View* ProfileChooserView::CreateDiceSigninView() {
signin_button_view->SetBorder( signin_button_view->SetBorder(
views::CreateSolidBorder(kMenuEdgeMargin, SK_ColorTRANSPARENT)); views::CreateSolidBorder(kMenuEdgeMargin, SK_ColorTRANSPARENT));
if (accounts.empty()) { if (dice_sync_promo_accounts_.empty()) {
// When there is no signed in web account, just display a sign-in button. // When there is no signed in web account, just display a sign-in button.
signin_current_profile_button_ = signin_current_profile_button_ =
views::MdTextButton::CreateSecondaryUiBlueButton( views::MdTextButton::CreateSecondaryUiBlueButton(
...@@ -1056,10 +1078,12 @@ views::View* ProfileChooserView::CreateDiceSigninView() { ...@@ -1056,10 +1078,12 @@ views::View* ProfileChooserView::CreateDiceSigninView() {
return view; return view;
} }
// Create a hover button to sign in the first account of |accounts|. // Create a hover button to sign in the first account of
// |dice_sync_promo_accounts_|.
AccountInfo dice_promo_default_account = dice_sync_promo_accounts_[0];
gfx::Image account_icon = gfx::Image account_icon =
AccountTrackerServiceFactory::GetForProfile(browser_->profile()) AccountTrackerServiceFactory::GetForProfile(browser_->profile())
->GetAccountImage(accounts[0].account_id); ->GetAccountImage(dice_promo_default_account.account_id);
if (account_icon.IsEmpty()) { if (account_icon.IsEmpty()) {
account_icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed( account_icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
profiles::GetPlaceholderAvatarIconResourceID()); profiles::GetPlaceholderAvatarIconResourceID());
...@@ -1067,32 +1091,30 @@ views::View* ProfileChooserView::CreateDiceSigninView() { ...@@ -1067,32 +1091,30 @@ views::View* ProfileChooserView::CreateDiceSigninView() {
auto account_photo = std::make_unique<BadgedProfilePhoto>( auto account_photo = std::make_unique<BadgedProfilePhoto>(
BadgedProfilePhoto::BADGE_TYPE_NONE, account_icon); BadgedProfilePhoto::BADGE_TYPE_NONE, account_icon);
base::string16 first_account_button_title = base::string16 first_account_button_title =
accounts[0].full_name.empty() dice_promo_default_account.full_name.empty()
? l10n_util::GetStringUTF16( ? l10n_util::GetStringUTF16(
IDS_PROFILES_DICE_SIGNIN_FIRST_ACCOUNT_BUTTON_NO_NAME) IDS_PROFILES_DICE_SIGNIN_FIRST_ACCOUNT_BUTTON_NO_NAME)
: l10n_util::GetStringFUTF16( : l10n_util::GetStringFUTF16(
IDS_PROFILES_DICE_SIGNIN_FIRST_ACCOUNT_BUTTON, IDS_PROFILES_DICE_SIGNIN_FIRST_ACCOUNT_BUTTON,
base::UTF8ToUTF16(accounts[0].full_name)); base::UTF8ToUTF16(dice_promo_default_account.full_name));
HoverButton* first_account_button = new HoverButton( HoverButton* first_account_button = new HoverButton(
this, std::move(account_photo), first_account_button_title, this, std::move(account_photo), first_account_button_title,
base::UTF8ToUTF16(accounts[0].email)); base::UTF8ToUTF16(dice_promo_default_account.email));
first_account_button->SetStyle(HoverButton::STYLE_PROMINENT); first_account_button->SetStyle(HoverButton::STYLE_PROMINENT);
signin_button_view->AddChildView(first_account_button); signin_button_view->AddChildView(first_account_button);
promo_button_container->AddChildView(signin_button_view); promo_button_container->AddChildView(signin_button_view);
signin_with_gaia_account_button_ = first_account_button; signin_with_gaia_account_button_ = first_account_button;
dice_sync_promo_account_ = accounts[0];
constexpr int kSmallMenuIconSize = 16; constexpr int kSmallMenuIconSize = 16;
HoverButton* sync_to_another_account_button = new HoverButton( sync_to_another_account_button_ = new HoverButton(
this, this,
gfx::CreateVectorIcon(kSyncSwitchAccountIcon, kSmallMenuIconSize, gfx::CreateVectorIcon(kSyncSwitchAccountIcon, kSmallMenuIconSize,
gfx::kChromeIconGrey), gfx::kChromeIconGrey),
l10n_util::GetStringUTF16( l10n_util::GetStringUTF16(
IDS_PROFILES_DICE_SIGNIN_WITH_ANOTHER_ACCOUNT_BUTTON)); IDS_PROFILES_DICE_SIGNIN_WITH_ANOTHER_ACCOUNT_BUTTON));
signin_current_profile_button_ = sync_to_another_account_button; promo_button_container->AddChildView(sync_to_another_account_button_);
promo_button_container->AddChildView(sync_to_another_account_button);
view->AddChildView(promo_button_container); view->AddChildView(promo_button_container);
return view; return view;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/profile_chooser_constants.h" #include "chrome/browser/ui/profile_chooser_constants.h"
#include "chrome/browser/ui/views/close_bubble_on_tab_activation_helper.h" #include "chrome/browser/ui/views/close_bubble_on_tab_activation_helper.h"
#include "chrome/browser/ui/views/profiles/dice_accounts_menu.h"
#include "components/signin/core/browser/signin_header_helper.h" #include "components/signin/core/browser/signin_header_helper.h"
#include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_delegate.h"
#include "google_apis/gaia/oauth2_token_service.h" #include "google_apis/gaia/oauth2_token_service.h"
...@@ -194,6 +195,7 @@ class ProfileChooserView : public content::WebContentsDelegate, ...@@ -194,6 +195,7 @@ class ProfileChooserView : public content::WebContentsDelegate,
views::LabelButton* manage_accounts_button_; views::LabelButton* manage_accounts_button_;
views::LabelButton* signin_current_profile_button_; views::LabelButton* signin_current_profile_button_;
views::LabelButton* signin_with_gaia_account_button_; views::LabelButton* signin_with_gaia_account_button_;
views::LabelButton* sync_to_another_account_button_;
// For material design user menu, the active profile card owns the profile // For material design user menu, the active profile card owns the profile
// name and photo. // name and photo.
...@@ -229,8 +231,12 @@ class ProfileChooserView : public content::WebContentsDelegate, ...@@ -229,8 +231,12 @@ class ProfileChooserView : public content::WebContentsDelegate,
CloseBubbleOnTabActivationHelper close_bubble_helper_; CloseBubbleOnTabActivationHelper close_bubble_helper_;
// Account that is presented in the enable sync promo. // Accounts that are presented in the enable sync promo.
AccountInfo dice_sync_promo_account_; std::vector<AccountInfo> dice_sync_promo_accounts_;
// Accounts submenu that is shown when |sync_to_another_account_button_| is
// pressed.
std::unique_ptr<DiceAccountsMenu> dice_accounts_menu_;
const bool dice_enabled_; const bool dice_enabled_;
......
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