// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import './theme_snapshot.js';
import './hover_button.js';
import './strings.m.js'; // Required by <managed-dialog>.
import 'chrome://resources/cr_components/customize_color_scheme_mode/customize_color_scheme_mode.js';
import 'chrome://resources/cr_components/theme_color_picker/theme_color_picker.js';
import 'chrome://resources/cr_components/managed_dialog/managed_dialog.js';
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js';
import type {CrA11yAnnouncerElement} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
import type {CrToggleElement} from 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js';
import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js';
import {assert} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {getCss} from './appearance.css.js';
import {getHtml} from './appearance.html.js';
import {CustomizeChromeAction, recordCustomizeChromeAction} from './common.js';
import type {CustomizeChromePageCallbackRouter, CustomizeChromePageHandlerInterface, Theme} from './customize_chrome.mojom-webui.js';
import {CustomizeChromeApiProxy} from './customize_chrome_api_proxy.js';
export interface AppearanceElement {
$: {
chromeColors: HTMLElement,
editThemeButton: HTMLButtonElement,
themeSnapshot: HTMLElement,
setClassicChromeButton: HTMLButtonElement,
thirdPartyThemeLinkButton: HTMLButtonElement,
followThemeToggle: HTMLElement,
followThemeToggleControl: CrToggleElement,
uploadedImageButton: HTMLButtonElement,
searchedImageButton: HTMLButtonElement,
};
}
const AppearanceElementBase = I18nMixinLit(CrLitElement);
export class AppearanceElement extends AppearanceElementBase {
static get is() {
return 'customize-chrome-appearance';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
static override get properties() {
return {
theme_: {type: Object},
editThemeButtonText_: {type: String},
thirdPartyThemeId_: {
type: String,
reflect: true,
},
thirdPartyThemeName_: {
type: String,
reflect: true,
},
showBottomDivider_: {type: Boolean},
showClassicChromeButton_: {type: Boolean},
showColorPicker_: {type: Boolean},
showDeviceThemeToggle_: {type: Boolean},
showThemeSnapshot_: {type: Boolean},
showUploadedImageButton_: {type: Boolean},
showSearchedImageButton_: {type: Boolean},
showManagedDialog_: {type: Boolean},
isSourceTabFirstPartyNtp_: {type: Boolean},
wallpaperSearchButtonEnabled_: {
type: Boolean,
reflect: true,
},
wallpaperSearchEnabled_: {type: Boolean},
};
}
protected theme_?: Theme;
protected editThemeButtonText_: string = '';
protected thirdPartyThemeId_: string|null = null;
protected thirdPartyThemeName_: string|null = null;
protected showBottomDivider_: boolean = false;
protected showClassicChromeButton_: boolean = false;
protected showColorPicker_: boolean = false;
protected showDeviceThemeToggle_: boolean = false;
protected showThemeSnapshot_: boolean = false;
protected showUploadedImageButton_: boolean = false;
protected showSearchedImageButton_: boolean = false;
protected showManagedDialog_: boolean = false;
protected wallpaperSearchButtonEnabled_: boolean =
loadTimeData.getBoolean('wallpaperSearchButtonEnabled');
private wallpaperSearchEnabled_: boolean =
loadTimeData.getBoolean('wallpaperSearchEnabled');
protected isSourceTabFirstPartyNtp_: boolean = true;
protected ntpManagedByName_: string = '';
private setThemeListenerId_: number|null = null;
private attachedTabStateUpdatedId_: number|null = null;
private ntpManagedByNameUpdatedId_: number|null = null;
private callbackRouter_: CustomizeChromePageCallbackRouter;
private pageHandler_: CustomizeChromePageHandlerInterface;
constructor() {
super();
this.pageHandler_ = CustomizeChromeApiProxy.getInstance().handler;
this.callbackRouter_ = CustomizeChromeApiProxy.getInstance().callbackRouter;
}
override connectedCallback() {
super.connectedCallback();
this.setThemeListenerId_ =
this.callbackRouter_.setTheme.addListener((theme: Theme) => {
this.theme_ = theme;
});
this.pageHandler_.updateTheme();
this.attachedTabStateUpdatedId_ =
CustomizeChromeApiProxy.getInstance()
.callbackRouter.attachedTabStateUpdated.addListener(
(isSourceTabFirstPartyNtp: boolean) => {
this.isSourceTabFirstPartyNtp_ = isSourceTabFirstPartyNtp;
});
this.pageHandler_.updateAttachedTabState();
this.ntpManagedByNameUpdatedId_ =
CustomizeChromeApiProxy.getInstance()
.callbackRouter.ntpManagedByNameUpdated.addListener(
(ntpManagedByName: string) => {
this.ntpManagedByName_ = ntpManagedByName;
});
this.pageHandler_.updateNtpManagedByName();
}
override disconnectedCallback() {
super.disconnectedCallback();
assert(this.setThemeListenerId_);
this.callbackRouter_.removeListener(this.setThemeListenerId_);
assert(this.attachedTabStateUpdatedId_);
CustomizeChromeApiProxy.getInstance().callbackRouter.removeListener(
this.attachedTabStateUpdatedId_);
assert(this.ntpManagedByNameUpdatedId_);
CustomizeChromeApiProxy.getInstance().callbackRouter.removeListener(
this.ntpManagedByNameUpdatedId_);
}
override willUpdate(changedProperties: PropertyValues<this>) {
super.willUpdate(changedProperties);
const changedPrivateProperties =
changedProperties as Map<PropertyKey, unknown>;
this.editThemeButtonText_ = this.computeEditThemeButtonText_();
if (changedPrivateProperties.has('theme_') ||
changedPrivateProperties.has('isSourceTabFirstPartyNtp_')) {
this.thirdPartyThemeId_ = this.computeThirdPartyThemeId_();
this.thirdPartyThemeName_ = this.computeThirdPartyThemeName_();
this.showClassicChromeButton_ = this.computeShowClassicChromeButton_();
this.showColorPicker_ = this.computeShowColorPicker_();
this.showDeviceThemeToggle_ = this.computeShowDeviceThemeToggle_();
this.showThemeSnapshot_ = this.computeShowThemeSnapshot_();
this.showUploadedImageButton_ = this.computeShowUploadedImageButton_();
this.showSearchedImageButton_ = this.computeShowSearchedImageButton_();
}
this.showBottomDivider_ = this.computeShowBottomDivider_();
// Announce when theme is set to Classic Chrome.
// This should only be triggered if the classic chrome's button is hidden
// after the initial theme value has already been set.
if (changedPrivateProperties.has('theme_') &&
changedPrivateProperties.has('showClassicChromeButton_') &&
!!changedPrivateProperties.get('theme_') &&
!this.showClassicChromeButton_) {
const announcer = getAnnouncerInstance() as CrA11yAnnouncerElement;
announcer.announce(this.i18n('updatedToClassicChrome'));
// If the classicChrome button has focus, change focus to editTheme
// button, since the button is disappearing.
if (this.shadowRoot!.activeElement === this.$.setClassicChromeButton) {
this.focusOnThemeButton();
}
}
}
focusOnThemeButton() {
this.$.editThemeButton.focus();
}
private computeEditThemeButtonText_(): string {
return this.i18n(
this.wallpaperSearchButtonEnabled_ ? 'categoriesHeader' :
'changeTheme');
}
private computeThirdPartyThemeId_(): string|null {
if (this.theme_ && this.theme_.thirdPartyThemeInfo) {
return this.theme_.thirdPartyThemeInfo.id;
} else {
return null;
}
}
private computeThirdPartyThemeName_(): string|null {
if (this.theme_ && this.theme_.thirdPartyThemeInfo) {
return this.theme_.thirdPartyThemeInfo.name;
} else {
return null;
}
}
private computeShowBottomDivider_(): boolean {
return !!(this.showClassicChromeButton_ || this.showDeviceThemeToggle_);
}
private computeShowClassicChromeButton_(): boolean {
return !!(
this.theme_ &&
(this.theme_.backgroundImage || this.theme_.thirdPartyThemeInfo));
}
private computeShowColorPicker_(): boolean {
return !!this.theme_ && !this.theme_.thirdPartyThemeInfo;
}
private computeShowDeviceThemeToggle_(): boolean {
return loadTimeData.getBoolean('showDeviceThemeToggle') &&
!(!!this.theme_ && !!this.theme_.thirdPartyThemeInfo);
}
private computeShowThemeSnapshot_(): boolean {
return !!this.theme_ && !this.theme_.thirdPartyThemeInfo &&
(!(this.theme_.backgroundImage &&
this.theme_.backgroundImage.isUploadedImage)) &&
this.isSourceTabFirstPartyNtp_;
}
private computeShowUploadedImageButton_(): boolean {
return !!(
this.theme_ && this.theme_.backgroundImage &&
this.theme_.backgroundImage.isUploadedImage &&
!this.theme_.backgroundImage.localBackgroundId);
}
private computeShowSearchedImageButton_(): boolean {
return !!(
this.theme_ && this.theme_.backgroundImage &&
this.theme_.backgroundImage.localBackgroundId);
}
protected onEditThemeClicked_() {
recordCustomizeChromeAction(CustomizeChromeAction.EDIT_THEME_CLICKED);
if (this.handleClickForManagedThemes_()) {
return;
}
this.dispatchEvent(new Event('edit-theme-click'));
}
protected onWallpaperSearchClicked_() {
recordCustomizeChromeAction(
CustomizeChromeAction.WALLPAPER_SEARCH_APPEARANCE_BUTTON_CLICKED);
if (this.handleClickForManagedThemes_()) {
return;
}
this.dispatchEvent(new Event('wallpaper-search-click'));
}
protected onThirdPartyThemeLinkButtonClick_() {
if (this.thirdPartyThemeId_) {
this.pageHandler_.openThirdPartyThemePage(this.thirdPartyThemeId_);
}
}
protected onUploadedImageButtonClick_() {
this.pageHandler_.chooseLocalCustomBackground();
}
protected onSearchedImageButtonClick_() {
if (this.wallpaperSearchEnabled_) {
this.dispatchEvent(new CustomEvent('wallpaper-search-click'));
} else {
this.dispatchEvent(new Event('edit-theme-click'));
}
}
protected onSetClassicChromeClicked_() {
if (this.handleClickForManagedThemes_()) {
return;
}
this.pageHandler_.removeBackgroundImage();
this.pageHandler_.setDefaultColor();
recordCustomizeChromeAction(
CustomizeChromeAction.SET_CLASSIC_CHROME_THEME_CLICKED);
}
protected onFollowThemeToggleChange_(e: CustomEvent<boolean>) {
this.pageHandler_.setFollowDeviceTheme(e.detail);
}
protected onManagedDialogClosed_() {
this.showManagedDialog_ = false;
}
protected onNewTabPageManageByButtonClicked_() {
this.pageHandler_.openNtpManagedByPage();
}
private handleClickForManagedThemes_(): boolean {
if (!this.theme_ || !this.theme_.backgroundManagedByPolicy) {
return false;
}
this.showManagedDialog_ = true;
return true;
}
}
declare global {
interface HTMLElementTagNameMap {
'customize-chrome-appearance': AppearanceElement;
}
}
customElements.define(AppearanceElement.is, AppearanceElement);