Commit ef785cb4 authored by David Roger's avatar David Roger Committed by Commit Bot

[signin] Add avatar and plumbing to profile customization bubble

The UI now shows the avatar. It also listens to changes in the avatar
and profile colors.
The input is now fully wired and propagates the profile name to the
profile info cache.

Screenshot: https://screenshot.googleplex.com/4MKQd5N6pNjLH45.png

Bug: 1130945
Change-Id: Ie4526520df36a96fb4ca3d4baaf0a2df158a4bd0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2461321
Commit-Queue: David Roger <droger@chromium.org>
Reviewed-by: default avatarMonica Basta <msalama@chromium.org>
Cr-Commit-Position: refs/heads/master@{#817051}
parent c612513c
......@@ -633,8 +633,11 @@ void ProfileAttributesEntry::SetProfileThemeColors(
changed |= ClearValue(kDefaultAvatarStrokeColorKey);
}
if (changed && ShouldShowGenericColoredAvatar(GetAvatarIconIndex()))
profile_info_cache_->NotifyOnProfileAvatarChanged(GetPath());
if (changed) {
profile_info_cache_->NotifyProfileThemeColorsChanged(GetPath());
if (ShouldShowGenericColoredAvatar(GetAvatarIconIndex()))
profile_info_cache_->NotifyOnProfileAvatarChanged(GetPath());
}
}
void ProfileAttributesEntry::SetHostedDomain(std::string hosted_domain) {
......
......@@ -97,6 +97,8 @@ class ProfileAttributesTestObserver
void(const base::FilePath& profile_path));
MOCK_METHOD1(OnProfileIsOmittedChanged,
void(const base::FilePath& profile_path));
MOCK_METHOD1(OnProfileThemeColorsChanged,
void(const base::FilePath& profile_path));
};
} // namespace
......@@ -947,6 +949,7 @@ TEST_F(ProfileAttributesStorageTest, ProfileThemeColors) {
ProfileThemeColors colors = {SK_ColorTRANSPARENT, SK_ColorBLACK,
SK_ColorWHITE};
EXPECT_CALL(observer(), OnProfileAvatarChanged(profile_path)).Times(1);
EXPECT_CALL(observer(), OnProfileThemeColorsChanged(profile_path)).Times(1);
entry->SetProfileThemeColors(colors);
EXPECT_EQ(entry->GetProfileThemeColors(), colors);
VerifyAndResetCallExpectations();
......@@ -957,6 +960,7 @@ TEST_F(ProfileAttributesStorageTest, ProfileThemeColors) {
// base::nullopt resets the colors to default.
EXPECT_CALL(observer(), OnProfileAvatarChanged(profile_path)).Times(1);
EXPECT_CALL(observer(), OnProfileThemeColorsChanged(profile_path)).Times(1);
entry->SetProfileThemeColors(base::nullopt);
EXPECT_EQ(entry->GetProfileThemeColors(),
ProfileAttributesEntry::GetDefaultProfileThemeColors(false));
......
......@@ -223,6 +223,12 @@ void ProfileInfoCache::NotifyProfileIsOmittedChanged(
observer.OnProfileIsOmittedChanged(profile_path);
}
void ProfileInfoCache::NotifyProfileThemeColorsChanged(
const base::FilePath& profile_path) {
for (auto& observer : observer_list_)
observer.OnProfileThemeColorsChanged(profile_path);
}
void ProfileInfoCache::DeleteProfileFromCache(
const base::FilePath& profile_path) {
ProfileAttributesEntry* entry;
......
......@@ -128,6 +128,7 @@ class ProfileInfoCache : public ProfileInfoInterface,
void NotifyIfProfileNamesHaveChanged();
void NotifyProfileSupervisedUserIdChanged(const base::FilePath& profile_path);
void NotifyProfileIsOmittedChanged(const base::FilePath& profile_path);
void NotifyProfileThemeColorsChanged(const base::FilePath& profile_path);
private:
FRIEND_TEST_ALL_PREFIXES(ProfileAttributesStorageTest,
......
......@@ -36,6 +36,8 @@ class ProfileInfoCacheObserver {
const base::FilePath& profile_path) {}
virtual void OnProfileIsOmittedChanged(
const base::FilePath& profile_path) {}
virtual void OnProfileThemeColorsChanged(const base::FilePath& profile_path) {
}
protected:
ProfileInfoCacheObserver() = default;
......
......@@ -16,10 +16,13 @@ js_type_check("closure_compile") {
js_library("profile_customization_app") {
deps = [
":profile_customization_browser_proxy",
"//third_party/polymer/v3_0/components-chromium/iron-icon",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/cr_components/customize_themes",
"//ui/webui/resources/cr_elements/cr_button:cr_button.m",
"//ui/webui/resources/cr_elements/cr_input:cr_input.m",
"//ui/webui/resources/js:load_time_data.m",
"//ui/webui/resources/js:web_ui_listener_behavior.m",
]
}
......
......@@ -6,12 +6,70 @@
}
#header {
background-color: pink; /* TODO: use profile color */
background-color: var(--header-background-color);
border-radius: 4px;
color: var(--header-text-color);
height: 128px;
margin: 8px 8px;
}
#headerText {
font-size: 15px;
font-weight: bold;
line-height: 18px;
margin: 16px auto 9px;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
}
#avatarContainer {
--avatar-image-width: 60px;
--avatar-border: 2px;
--avatar-size: calc(var(--avatar-image-width) + 2 * var(--avatar-border));
height: var(--avatar-size);
left: calc(50% - var(--avatar-size)/2);
position: absolute;
width: var(--avatar-size);
}
#avatar {
/** The user avatar may be transparent, add a background */
background-color: var(--md-background-color);
border: var(--avatar-border) solid var(--md-background-color);
border-radius: 50%;
height: var(--avatar-image-width);
top: 43px;
width: var(--avatar-image-width);
}
.work-badge {
--badge-width: 20px;
--badge-offset: -4px;
background-color: var(--signin-work-badge-background-color);
border: 2px solid var(--header-background-color);
border-radius: 50%;
bottom: var(--badge-offset);
height: var(--badge-width);
position: absolute;
right: var(--badge-offset);
width: var(--badge-width);
}
.work-badge > iron-icon {
--work-icon-size: 15px;
bottom: 0;
color: var(--signin-work-badge-foreground-color);
height: var(--work-icon-size);
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: var(--work-icon-size);
}
#nameInput {
--cr-input-placeholder-color: var(--google-grey-900);
--cr-input-padding-bottom: 8px;
......@@ -55,10 +113,17 @@
</style>
<div id="header">
<div id="headerText">[[initialProfileName_]]</div>
<div id="avatarContainer">
<img id="avatar" src="[[pictureUrl_]]">
<div class="work-badge" id="badge" hidden="[[!isManaged_]]">
<iron-icon class="icon" icon="signin:business"></iron-icon>
</div>
</div>
</div>
<cr-input id="nameInput" placeholder="Placeholder" pattern=".*\\S.*"
auto-validate spellcheck="false" autofocus>
<cr-input id="nameInput" pattern=".*\\S.*" value="{{profileName_}}"
auto-validate required spellcheck="false">
</cr-input>
<hr id="lineSeparator">
......@@ -71,7 +136,8 @@
<div class="action-container">
<cr-button id="doneButton" class="action-button"
on-click="onDoneCustomizationClicked_">
disabled="[[isDoneButtonDisabled_(profileName_)]]"
on-click="onDoneCustomizationClicked_" autofocus>
$i18n{profileCustomizationDoneLabel}
</cr-button>
<div>
......@@ -5,29 +5,95 @@
import 'chrome://resources/cr_components/customize_themes/customize_themes.js';
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
import './strings.m.js';
import './signin_icons.js';
import './signin_shared_css.js';
import './signin_vars_css.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {ProfileCustomizationBrowserProxy, ProfileCustomizationBrowserProxyImpl} from './profile_customization_browser_proxy.js';
import {ProfileCustomizationBrowserProxy, ProfileCustomizationBrowserProxyImpl, ProfileInfo} from './profile_customization_browser_proxy.js';
Polymer({
is: 'profile-customization-app',
_template: html`{__html_template__}`,
behaviors: [
WebUIListenerBehavior,
],
properties: {
/** Whether the account is managed (Enterprise) */
isManaged_: {
type: Boolean,
value: () => loadTimeData.getBoolean('isManaged'),
},
/** Initial local profile name, non-editable */
initialProfileName_: {
type: String,
value: () => loadTimeData.getString('profileName'),
},
/** Local profile name, editable by user input */
profileName_: {
type: String,
value: '',
},
/** URL for the profile picture */
pictureUrl_: {
type: String,
},
},
/** @private {?ProfileCustomizationBrowserProxy} */
profileCustomizationBrowserProxy_: null,
/** @override */
ready() {
// profileName_ is only set now, because it triggers a validation of the
// input which crashes if it's done too early.
this.profileName_ = this.initialProfileName_;
this.profileCustomizationBrowserProxy_ =
ProfileCustomizationBrowserProxyImpl.getInstance();
this.addWebUIListener(
'on-profile-info-changed',
(/** @type {!ProfileInfo} */ info) => this.setProfileInfo_(info));
this.profileCustomizationBrowserProxy_.initialized().then(
info => this.setProfileInfo_(info));
},
/** @private */
/**
* Called when the Done button is clicked. Sends the profile name back to
* native.
* @private
*/
onDoneCustomizationClicked_() {
this.profileCustomizationBrowserProxy_.done();
this.profileCustomizationBrowserProxy_.done(this.profileName_);
},
/**
* Returns whether the Done button should be disabled.
* @return Boolean
* @private
*/
isDoneButtonDisabled_() {
return !this.profileName_ || !this.$.nameInput.validate();
},
/**
* @param {!ProfileInfo} profileInfo
* @private
*/
setProfileInfo_(profileInfo) {
this.style.setProperty('--header-text-color', profileInfo.textColor);
this.style.setProperty(
'--header-background-color', profileInfo.backgroundColor);
this.pictureUrl_ = profileInfo.pictureUrl;
},
});
......@@ -9,17 +9,41 @@
import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
/**
* Profile info (colors and avatar) sent from C++.
* @typedef {{
* textColor: string,
* backgroundColor: string,
* pictureUrl: string,
* }}
*/
export let ProfileInfo;
/** @interface */
export class ProfileCustomizationBrowserProxy {
/** Called when the user clicks the done button. */
done() {}
/**
* Called when the page is ready
* @return {!Promise<!ProfileInfo>}
*/
initialized() {}
/**
* Called when the user clicks the done button.
* @param {string} profileName
*/
done(profileName) {}
}
/** @implements {ProfileCustomizationBrowserProxy} */
export class ProfileCustomizationBrowserProxyImpl {
/** @override */
done() {
chrome.send('done');
initialized() {
return sendWithPromise('initialized');
}
/** @override */
done(profileName) {
chrome.send('done', [profileName]);
}
}
......
......@@ -8,8 +8,25 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/check.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_avatar_icon_util.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/signin/profile_colors_util.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/image/image.h"
namespace {
const size_t kAvatarSize = 60;
}
ProfileCustomizationHandler::ProfileCustomizationHandler(
base::OnceClosure done_closure)
......@@ -18,12 +35,98 @@ ProfileCustomizationHandler::ProfileCustomizationHandler(
ProfileCustomizationHandler::~ProfileCustomizationHandler() = default;
void ProfileCustomizationHandler::RegisterMessages() {
profile_path_ = Profile::FromWebUI(web_ui())->GetPath();
web_ui()->RegisterMessageCallback(
"initialized",
base::BindRepeating(&ProfileCustomizationHandler::HandleInitialized,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"done", base::BindRepeating(&ProfileCustomizationHandler::HandleDone,
base::Unretained(this)));
}
void ProfileCustomizationHandler::OnJavascriptAllowed() {
observed_profile_.Add(
&g_browser_process->profile_manager()->GetProfileAttributesStorage());
}
void ProfileCustomizationHandler::OnJavascriptDisallowed() {
observed_profile_.RemoveAll();
}
void ProfileCustomizationHandler::OnProfileAvatarChanged(
const base::FilePath& profile_path) {
if (profile_path != profile_path_)
return;
UpdateProfileInfo();
}
void ProfileCustomizationHandler::OnProfileHighResAvatarLoaded(
const base::FilePath& profile_path) {
if (profile_path != profile_path_)
return;
UpdateProfileInfo();
}
void ProfileCustomizationHandler::OnProfileThemeColorsChanged(
const base::FilePath& profile_path) {
DCHECK(IsJavascriptAllowed());
if (profile_path != profile_path_)
return;
UpdateProfileInfo();
}
void ProfileCustomizationHandler::HandleInitialized(
const base::ListValue* args) {
CHECK_EQ(1u, args->GetSize());
AllowJavascript();
const base::Value& callback_id = args->GetList()[0];
ResolveJavascriptCallback(callback_id, GetProfileInfoValue());
}
void ProfileCustomizationHandler::HandleDone(const base::ListValue* args) {
CHECK_EQ(1u, args->GetSize());
base::string16 profile_name =
base::UTF8ToUTF16(args->GetList()[0].GetString());
base::TrimWhitespace(profile_name, base::TRIM_ALL, &profile_name);
DCHECK(!profile_name.empty());
GetProfileEntry()->SetLocalProfileName(profile_name);
if (done_closure_)
std::move(done_closure_).Run();
}
void ProfileCustomizationHandler::UpdateProfileInfo() {
DCHECK(IsJavascriptAllowed());
FireWebUIListener("on-profile-info-changed", GetProfileInfoValue());
}
base::Value ProfileCustomizationHandler::GetProfileInfoValue() {
ProfileAttributesEntry* entry = GetProfileEntry();
SkColor profile_color =
entry->GetProfileThemeColors().profile_highlight_color;
base::Value dict(base::Value::Type::DICTIONARY);
dict.SetStringKey("textColor",
color_utils::SkColorToRgbaString(
GetProfileForegroundTextColor(profile_color)));
dict.SetStringKey("backgroundColor",
color_utils::SkColorToRgbaString(profile_color));
const int avatar_icon_size = kAvatarSize * web_ui()->GetDeviceScaleFactor();
gfx::Image icon =
profiles::GetSizedAvatarIcon(entry->GetAvatarIcon(avatar_icon_size), true,
avatar_icon_size, avatar_icon_size);
dict.SetStringKey("pictureUrl", webui::GetBitmapDataUrl(icon.AsBitmap()));
return dict;
}
ProfileAttributesEntry* ProfileCustomizationHandler::GetProfileEntry() const {
ProfileAttributesEntry* entry = nullptr;
g_browser_process->profile_manager()
->GetProfileAttributesStorage()
.GetProfileAttributesWithPath(profile_path_, &entry);
DCHECK(entry);
return entry;
}
......@@ -8,13 +8,19 @@
#include "content/public/browser/web_ui_message_handler.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/scoped_observer.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
namespace base {
class ListValue;
}
class ProfileAttributesEntry;
// WebUI message handler for the profile customization bubble.
class ProfileCustomizationHandler : public content::WebUIMessageHandler {
class ProfileCustomizationHandler : public content::WebUIMessageHandler,
public ProfileAttributesStorage::Observer {
public:
explicit ProfileCustomizationHandler(base::OnceClosure done_closure);
~ProfileCustomizationHandler() override;
......@@ -25,10 +31,33 @@ class ProfileCustomizationHandler : public content::WebUIMessageHandler {
// content::WebUIMessageHandler:
void RegisterMessages() override;
void OnJavascriptAllowed() override;
void OnJavascriptDisallowed() override;
// ProfileAttributesStorage::Observer:
void OnProfileAvatarChanged(const base::FilePath& profile_path) override;
void OnProfileHighResAvatarLoaded(
const base::FilePath& profile_path) override;
void OnProfileThemeColorsChanged(const base::FilePath& profile_path) override;
private:
// Handlers for messages from javascript.
void HandleInitialized(const base::ListValue* args);
void HandleDone(const base::ListValue* args);
// Sends an updated profile info (avatar and colors) to the WebUI.
void UpdateProfileInfo();
// Computes the profile info (avatar and colors) to be sent to the WebUI.
base::Value GetProfileInfoValue();
// Returns the ProfilesAttributesEntry associated with the current profile.
ProfileAttributesEntry* GetProfileEntry() const;
base::FilePath profile_path_;
ScopedObserver<ProfileAttributesStorage, ProfileAttributesStorage::Observer>
observed_profile_{this};
// Called when the "Done" button has been pressed.
base::OnceClosure done_closure_;
};
......
......@@ -4,13 +4,19 @@
#include "chrome/browser/ui/webui/signin/profile_customization_ui.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/webui/customize_themes/chrome_customize_themes_handler.h"
#include "chrome/browser/ui/webui/signin/profile_customization_handler.h"
#include "chrome/browser/ui/webui/webui_util.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/grit/browser_resources.h"
#include "chrome/grit/generated_resources.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "services/network/public/mojom/content_security_policy.mojom.h"
......@@ -27,7 +33,9 @@ ProfileCustomizationUI::ProfileCustomizationUI(content::WebUI* web_ui)
IDR_PROFILE_CUSTOMIZATION_APP_JS);
source->AddResourcePath("profile_customization_browser_proxy.js",
IDR_PROFILE_CUSTOMIZATION_BROWSER_PROXY_JS);
source->AddResourcePath("signin_icons.js", IDR_SIGNIN_ICONS_JS);
source->AddResourcePath("signin_shared_css.js", IDR_SIGNIN_SHARED_CSS_JS);
source->AddResourcePath("signin_vars_css.js", IDR_SIGNIN_VARS_CSS_JS);
// Localized strings.
source->UseStringsJs();
......@@ -46,6 +54,18 @@ ProfileCustomizationUI::ProfileCustomizationUI(content::WebUI* web_ui)
};
webui::AddLocalizedStringsBulk(source, kLocalizedStrings);
// loadTimeData.
Profile* profile = Profile::FromWebUI(web_ui);
ProfileAttributesEntry* entry = nullptr;
g_browser_process->profile_manager()
->GetProfileAttributesStorage()
.GetProfileAttributesWithPath(profile->GetPath(), &entry);
source->AddString("profileName",
base::UTF16ToUTF8(entry->GetLocalProfileName()));
source->AddBoolean("isManaged",
!entry->GetHostedDomain().empty() &&
entry->GetHostedDomain() != kNoHostedDomainFound);
// Resources for testing.
source->OverrideContentSecurityPolicy(
network::mojom::CSPDirectiveName::ScriptSrc,
......@@ -54,7 +74,7 @@ ProfileCustomizationUI::ProfileCustomizationUI(content::WebUI* web_ui)
source->AddResourcePath("test_loader.js", IDR_WEBUI_JS_TEST_LOADER_JS);
source->AddResourcePath("test_loader.html", IDR_WEBUI_HTML_TEST_LOADER_HTML);
content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source);
content::WebUIDataSource::Add(profile, source);
}
ProfileCustomizationUI::~ProfileCustomizationUI() = default;
......
......@@ -50,6 +50,8 @@ js_library("profile_customization_test") {
"..:chai_assert",
"..:test_util.m",
"//chrome/browser/resources/signin/profile_customization:profile_customization_app",
"//ui/webui/resources/js:cr.m",
"//ui/webui/resources/js:load_time_data.m",
]
externs_list = [ "$externs_path/mocha-2.5.js" ]
}
......
......@@ -5,13 +5,14 @@
import 'chrome://profile-customization/profile_customization_app.js';
import {ProfileCustomizationBrowserProxyImpl} from 'chrome://profile-customization/profile_customization_browser_proxy.js';
import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {assertTrue} from '../chai_assert.js';
import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
import {isChildVisible} from '../test_util.m.js';
import {TestProfileCustomizationBrowserProxy} from './test_profile_customization_browser_proxy.js';
suite('ProfileCustomizationTest', function() {
/** @type {!ProfileCustomizationAppElement} */
let app;
......@@ -19,19 +20,95 @@ suite('ProfileCustomizationTest', function() {
/** @type {!TestProfileCustomizationBrowserProxy} */
let browserProxy;
/** @type {string} */
const AVATAR_URL_1 = 'chrome://theme/IDR_PROFILE_AVATAR_1';
/** @type {string} */
const AVATAR_URL_2 = 'chrome://theme/IDR_PROFILE_AVATAR_2';
setup(function() {
loadTimeData.overrideValues({
isManaged: false,
profileName: 'TestName',
});
browserProxy = new TestProfileCustomizationBrowserProxy();
browserProxy.setProfileInfo({
textColor: 'rgb(255, 0, 0)',
backgroundColor: 'rgb(0, 255, 0)',
pictureUrl: AVATAR_URL_1,
});
ProfileCustomizationBrowserProxyImpl.instance_ = browserProxy;
document.body.innerHTML = '';
app = /** @type {!ProfileCustomizationAppElement} */ (
document.createElement('profile-customization-app'));
document.body.append(app);
return browserProxy.whenCalled('initialized');
});
function checkImageUrl(elementId, expectedUrl) {
assertTrue(isChildVisible(app, elementId));
const img = app.$$(elementId);
assertEquals(expectedUrl, img.src);
}
// Checks that clicking Done without interacting with the input does not
// change the name.
test('ClickDone', function() {
assertTrue(isChildVisible(app, '#doneButton'));
app.$$('#doneButton').click();
return browserProxy.whenCalled('done');
const doneButton = app.$$('#doneButton');
assertFalse(doneButton.disabled);
doneButton.click();
return browserProxy.whenCalled('done').then(
profileName => assertEquals('TestName', profileName));
});
// Checks that the name can be changed.
test('ChangeName', function() {
const nameInput = app.$$('#nameInput');
// Check the default value for the input.
assertEquals('TestName', nameInput.value);
assertFalse(nameInput.invalid);
// Invalid name (white space).
nameInput.value = ' ';
assertTrue(nameInput.invalid);
// The button is disabled.
assertTrue(isChildVisible(app, '#doneButton'));
const doneButton = app.$$('#doneButton');
assertTrue(doneButton.disabled);
// Empty name.
nameInput.value = '';
assertTrue(nameInput.invalid);
assertTrue(doneButton.disabled);
// Valid name.
nameInput.value = 'Bob';
assertFalse(nameInput.invalid);
// Click done, and check that the new name is sent.
assertTrue(isChildVisible(app, '#doneButton'));
assertFalse(doneButton.disabled);
doneButton.click();
return browserProxy.whenCalled('done').then(
profileName => assertEquals('Bob', profileName));
});
test('ProfileInfo', function() {
const header = app.$$('#header');
// Check initial info.
assertEquals('rgb(255, 0, 0)', getComputedStyle(header).color);
assertEquals('rgb(0, 255, 0)', getComputedStyle(header).backgroundColor);
checkImageUrl('#avatar', AVATAR_URL_1);
// Update the info.
const color1 = 'rgb(1, 2, 3)';
const color2 = 'rgb(4, 5, 6)';
webUIListenerCallback(
'on-profile-info-changed',
{textColor: color1, backgroundColor: color2, pictureUrl: AVATAR_URL_2});
assertEquals(color1, getComputedStyle(header).color);
assertEquals(color2, getComputedStyle(header).backgroundColor);
checkImageUrl('#avatar', AVATAR_URL_2);
});
test('ThemeSelector', function() {
......
......@@ -2,18 +2,35 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {ProfileCustomizationBrowserProxy} from 'chrome://profile-customization/profile_customization_browser_proxy.js';
import {ProfileCustomizationBrowserProxy, ProfileInfo} from 'chrome://profile-customization/profile_customization_browser_proxy.js';
import {TestBrowserProxy} from '../test_browser_proxy.m.js';
/** @implements {ProfileCustomizationBrowserProxy} */
export class TestProfileCustomizationBrowserProxy extends TestBrowserProxy {
constructor() {
super(['done']);
super(['done', 'initialized']);
/** @private {!ProfileInfo} */
this.profileInfo_ = {
textColor: '',
backgroundColor: '',
pictureUrl: '',
};
}
/** @param {!ProfileInfo} info */
setProfileInfo(info) {
this.profileInfo_ = info;
}
/** @override */
initialized() {
this.methodCalled('initialized');
return Promise.resolve(this.profileInfo_);
}
/** @override */
done() {
this.methodCalled('done');
done(profileName) {
this.methodCalled('done', profileName);
}
}
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