diff --git a/src/panels/profile/ha-pick-theme-row.ts b/src/panels/profile/ha-pick-theme-row.ts index 2e761ee766..37c983d3ce 100644 --- a/src/panels/profile/ha-pick-theme-row.ts +++ b/src/panels/profile/ha-pick-theme-row.ts @@ -1,11 +1,14 @@ -import "@material/mwc-button/mwc-button"; -import "@material/mwc-list/mwc-list-item"; +import { mdiAlertCircleOutline } from "@mdi/js"; import type { PropertyValues, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; +import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-formfield"; import "../../components/ha-radio"; +import "../../components/ha-button"; +import "../../components/ha-circular-progress"; +import "../../components/ha-svg-icon"; +import "../../components/ha-list-item"; import type { HaRadio } from "../../components/ha-radio"; import "../../components/ha-select"; import "../../components/ha-settings-row"; @@ -14,9 +17,10 @@ import { DEFAULT_ACCENT_COLOR, DEFAULT_PRIMARY_COLOR, } from "../../resources/styles-data"; -import type { HomeAssistant } from "../../types"; +import type { HomeAssistant, ThemeSettings } from "../../types"; import { documentationUrl } from "../../util/documentation-url"; import type { StorageLocation } from "../../state/themes-mixin"; +import { subscribeSelectedTheme } from "../../data/ws-themes"; const USE_DEFAULT_THEME = "__USE_DEFAULT_THEME__"; const HOME_ASSISTANT_THEME = "default"; @@ -32,55 +36,73 @@ export class HaPickThemeRow extends LitElement { @state() _themeNames: string[] = []; + @state() private _selectedTheme?: ThemeSettings; + + @state() private _loading = false; + protected render(): TemplateResult { + if (this._loading) { + return html``; + } + const hasThemes = this.hass.themes.themes && Object.keys(this.hass.themes.themes).length; - const curThemeIsUseDefault = this.hass.selectedTheme?.theme === ""; - const curTheme = this.hass.selectedTheme?.theme - ? this.hass.selectedTheme?.theme - : this.hass.themes.darkMode + const curThemeIsUseDefault = this._selectedTheme?.theme === ""; + const curTheme = this._selectedTheme?.theme + ? this._selectedTheme?.theme + : this._selectedTheme?.dark ? this.hass.themes.default_dark_theme || this.hass.themes.default_theme : this.hass.themes.default_theme; - const themeSettings = this.hass.selectedTheme; - return html` ${this.hass.localize("ui.panel.profile.themes.header")} - - ${!hasThemes + + ${!hasThemes && + !(this.storageLocation === "user" && this.hass.browserThemeEnabled) ? this.hass.localize("ui.panel.profile.themes.error_no_theme") : ""} - - ${this.hass.localize("ui.panel.profile.themes.link_promo")} - + ${this.storageLocation === "user" && this.hass.browserThemeEnabled + ? html` + ${this.hass.localize( + "ui.panel.profile.themes.device.user_theme_info" + )}` + : html` + ${this.hass.localize("ui.panel.profile.themes.link_promo")} + `} - + ${this.hass.localize("ui.panel.profile.themes.use_default")} - - + + Home Assistant - + ${this._themeNames.map( (theme) => html` - ${theme} + ${theme} ` )} @@ -90,7 +112,7 @@ export class HaPickThemeRow extends LitElement { this.hass.themes.default_dark_theme && this.hass.themes.default_theme) || this._supportsModeSelection(curTheme) - ? html`
+ ? html`
@@ -125,14 +147,14 @@ export class HaPickThemeRow extends LitElement { @change=${this._handleDarkMode} name="dark_mode" value="dark" - .checked=${themeSettings?.dark === true} + .checked=${this._selectedTheme?.dark === true} > ${curTheme === HOME_ASSISTANT_THEME ? html`
- ${themeSettings?.primaryColor || themeSettings?.accentColor - ? html` + ${this._selectedTheme?.primaryColor || + this._selectedTheme?.accentColor + ? html` ${this.hass.localize("ui.panel.profile.themes.reset")} - ` - : ""} + ` + : nothing}
` - : ""} + : nothing}
` - : ""} + : nothing} `; } public willUpdate(changedProperties: PropertyValues) { + if (!this.hasUpdated) { + if (this.storageLocation === "browser") { + this._selectedTheme = this.hass.selectedTheme ?? undefined; + } else { + this._loading = true; + this._selectedTheme = undefined; + subscribeSelectedTheme( + this.hass, + (selectedTheme?: ThemeSettings | null) => { + this._selectedTheme = selectedTheme ?? undefined; + this._loading = false; + } + ); + } + } + const oldHass = changedProperties.get("hass") as undefined | HomeAssistant; const themesChanged = changedProperties.has("hass") && @@ -173,21 +213,36 @@ export class HaPickThemeRow extends LitElement { } } - private _handleColorChange(ev: CustomEvent) { - const target = ev.target as any; + private _shouldSaveHass() { + return ( + this.storageLocation === "browser" || + (this.storageLocation === "user" && !this.hass.browserThemeEnabled) + ); + } + + private _updateSelectedTheme(updatedTheme: Partial) { + this._selectedTheme = { + ...this._selectedTheme, + ...updatedTheme, + theme: updatedTheme.theme ?? this._selectedTheme?.theme ?? "", + }; + fireEvent(this, "settheme", { - settings: { [target.name]: target.value }, + settings: this._selectedTheme, storageLocation: this.storageLocation, + saveHass: this._shouldSaveHass(), }); } + private _handleColorChange(ev: CustomEvent) { + const target = ev.target as any; + this._updateSelectedTheme({ [target.name]: target.value }); + } + private _resetColors() { - fireEvent(this, "settheme", { - settings: { - primaryColor: undefined, - accentColor: undefined, - }, - storageLocation: this.storageLocation, + this._updateSelectedTheme({ + primaryColor: undefined, + accentColor: undefined, }); } @@ -208,38 +263,29 @@ export class HaPickThemeRow extends LitElement { dark = true; break; } - fireEvent(this, "settheme", { - settings: { dark }, - storageLocation: this.storageLocation, - }); + this._updateSelectedTheme({ dark }); } private _handleThemeSelection(ev) { const theme = ev.target.value; - if (theme === this.hass.selectedTheme?.theme) { + if (theme === this._selectedTheme?.theme) { return; } if (theme === USE_DEFAULT_THEME) { if (this.hass.selectedTheme?.theme) { - fireEvent(this, "settheme", { - settings: { - theme: "", - primaryColor: undefined, - accentColor: undefined, - }, - storageLocation: this.storageLocation, + this._updateSelectedTheme({ + theme: "", + primaryColor: undefined, + accentColor: undefined, }); } return; } - fireEvent(this, "settheme", { - settings: { - theme, - primaryColor: undefined, - accentColor: undefined, - }, - storageLocation: this.storageLocation, + this._updateSelectedTheme({ + theme, + primaryColor: undefined, + accentColor: undefined, }); } @@ -268,6 +314,12 @@ export class HaPickThemeRow extends LitElement { flex-grow: 1; margin: 0 4px; } + .device-info { + color: var(--warning-color); + display: flex; + align-items: center; + gap: 8px; + } `; } diff --git a/src/panels/profile/ha-profile-section-general.ts b/src/panels/profile/ha-profile-section-general.ts index 3f48b4dcea..aaad0f7283 100644 --- a/src/panels/profile/ha-profile-section-general.ts +++ b/src/panels/profile/ha-profile-section-general.ts @@ -1,4 +1,3 @@ -import { mdiAlertCircleOutline } from "@mdi/js"; import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import type { CSSResultGroup, TemplateResult } from "lit"; import { css, html, LitElement, nothing } from "lit"; @@ -8,7 +7,6 @@ import "../../components/ha-card"; import "../../components/ha-button"; import "../../components/ha-expansion-panel"; import "../../components/ha-switch"; -import "../../components/ha-svg-icon"; import "../../layouts/hass-tabs-subpage"; import { profileSections } from "./ha-panel-profile"; import { isExternal } from "../../data/external"; @@ -135,26 +133,12 @@ class HaProfileSectionGeneral extends LitElement { .narrow=${this.narrow} .hass=${this.hass} > - ${this.hass.browserThemeEnabled || this._browserThemeActivated - ? html` - - - ${this.hass.localize("ui.panel.profile.themes.header")} - - - - ${this.hass.localize( - "ui.panel.profile.themes.device.user_theme_info" - )} - - - ` - : html``} + ${this.hass.user!.is_admin ? html` ; + settings: ThemeSettings; storageLocation: StorageLocation; + saveHass: boolean; } declare global { @@ -45,21 +46,21 @@ export default >(superClass: T) => protected firstUpdated(changedProps) { super.firstUpdated(changedProps); this.addEventListener("settheme", (ev) => { - const selectedTheme = { - ...this.hass!.selectedTheme!, - ...ev.detail.settings, - }; - this._updateHass({ - selectedTheme, - browserThemeEnabled: ev.detail.storageLocation === "browser", - }); - this._applyTheme(mql.matches); + if (ev.detail.saveHass) { + this._updateHass({ + selectedTheme: ev.detail.settings, + browserThemeEnabled: ev.detail.storageLocation === "browser", + }); + this._applyTheme(mql.matches); + } if (ev.detail.storageLocation === "browser") { storeState(this.hass!); } else { - clearStateKey(SELECTED_THEME_KEY); - saveSelectedTheme(this.hass!, selectedTheme); + if (ev.detail.saveHass) { + clearStateKey(SELECTED_THEME_KEY); + } + saveSelectedTheme(this.hass!, ev.detail.settings); } }); diff --git a/src/translations/en.json b/src/translations/en.json index e8a303a107..9d3bee837d 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -7583,7 +7583,7 @@ "description": "Overwrite user theme with custom device settings", "delete_header": "Delete device theme", "delete_description": "Are you sure you want to delete the device specific theme?", - "user_theme_info": "Device theme is active. Delete it to edit the user theme." + "user_theme_info": "Device theme is active. You won't see changes on user theme settings." } }, "dashboard": {