diff --git a/src/domain/session/settings/SettingsViewModel.js b/src/domain/session/settings/SettingsViewModel.js index aae83fb6..bf05c9ec 100644 --- a/src/domain/session/settings/SettingsViewModel.js +++ b/src/domain/session/settings/SettingsViewModel.js @@ -51,7 +51,6 @@ export class SettingsViewModel extends ViewModel { this.maxSentImageSizeLimit = 4000; this.pushNotifications = new PushNotificationStatus(); this._activeTheme = undefined; - this._activeVariant = undefined; } get _session() { @@ -80,7 +79,6 @@ export class SettingsViewModel extends ViewModel { this.pushNotifications.enabled = await this._session.arePushNotificationsEnabled(); if (!import.meta.env.DEV) { this._activeTheme = await this.platform.themeLoader.getActiveTheme(); - this._activeVariant = await this.platform.themeLoader.getCurrentVariant(); } this.emitChange(""); } @@ -141,14 +139,6 @@ export class SettingsViewModel extends ViewModel { return this._activeTheme; } - get activeVariant() { - return this._activeVariant; - } - - setTheme(name) { - this.platform.themeLoader.setTheme(name); - } - _formatBytes(n) { if (typeof n === "number") { return Math.round(n / (1024 * 1024)).toFixed(1) + " MB"; @@ -192,9 +182,12 @@ export class SettingsViewModel extends ViewModel { } } - changeThemeOption(themeId) { - if (themeId) { - this.setTheme(themeId); + changeThemeOption(themeName, themeVariant) { + if (themeName && "id" in this.themeMapping[themeName]) { + this.platform.themeLoader.setTheme(themeName); + } + else { + this.platform.themeLoader.setTheme(themeName, themeVariant); } // if there's no themeId, then the theme is going to be set via radio-buttons // emit so that radio-buttons become displayed/hidden @@ -204,13 +197,5 @@ export class SettingsViewModel extends ViewModel { get preferredColorScheme() { return this.platform.themeLoader.preferredColorScheme; } - - persistVariantToStorage(variant) { - this.platform.themeLoader.persistVariantToStorage(variant); - } - - removeVariantFromStorage() { - this.platform.themeLoader.removeVariantFromStorage(); - } } diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 8e079c85..45226032 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -189,7 +189,8 @@ export class Platform { ); const manifests = this.config["themeManifests"]; await this._themeLoader?.init(manifests); - this._themeLoader?.setTheme(await this._themeLoader.getActiveTheme(), log); + const { themeName, themeVariant } = await this._themeLoader.getActiveTheme(); + this._themeLoader?.setTheme(themeName, themeVariant, log); }); } catch (err) { this._container.innerText = err.message; diff --git a/src/platform/web/ThemeLoader.ts b/src/platform/web/ThemeLoader.ts index f302bc0e..bd53ff30 100644 --- a/src/platform/web/ThemeLoader.ts +++ b/src/platform/web/ThemeLoader.ts @@ -33,6 +33,11 @@ type DefaultVariant = { cssLocation: string; variantName: string; }; + default: { + id: string; + cssLocation: string; + variantName: string; + }; } type ThemeInformation = NormalVariant | DefaultVariant; @@ -67,13 +72,12 @@ export class ThemeLoader { information which includes the location of the CSS file. (see type ThemeInformation above) */ - // Object.assign(this._themeMapping, body["source"]["built-assets"]); //Add the default-theme as an additional option to the mapping const defaultThemeId = this.getDefaultTheme(); if (defaultThemeId) { - const cssLocation = this._findThemeLocationFromId(defaultThemeId); - if (cssLocation) { - this._themeMapping["Default"] = { id: "default", cssLocation }; + const themeDetails = this._findThemeDetailsFromId(defaultThemeId); + if (themeDetails) { + this._themeMapping["Default"] = { id: "default", cssLocation: themeDetails.cssLocation }; } } } @@ -115,7 +119,8 @@ export class ThemeLoader { * As mentioned above, if there's both a default dark and a default light variant, * add them to themeMapping separately. */ - this._themeMapping[themeName] = { dark: defaultDarkVariant, light: defaultLightVariant }; + const defaultVariant = this.preferredColorScheme === ColorSchemePreference.Dark ? defaultDarkVariant : defaultLightVariant; + this._themeMapping[themeName] = { dark: defaultDarkVariant, light: defaultLightVariant, default: defaultVariant }; } else { /** @@ -127,14 +132,24 @@ export class ThemeLoader { } } - setTheme(themeId: string, log?: ILogItem) { - this._platform.logger.wrapOrRun(log, { l: "change theme", id: themeId }, () => { - const themeLocation = this._findThemeLocationFromId(themeId); - if (!themeLocation) { - throw new Error(`Cannot find theme location for theme "${themeId}"!`); + setTheme(themeName: string, themeVariant: "light" | "dark" | "default", log?: ILogItem) { + this._platform.logger.wrapOrRun(log, { l: "change theme", name: themeName, variant: themeVariant }, () => { + let cssLocation: string; + let themeDetails = this._themeMapping[themeName]; + if ("id" in themeDetails) { + cssLocation = themeDetails.cssLocation; + } + else { + cssLocation = themeDetails[themeVariant ?? "default"].cssLocation; + } + this._platform.replaceStylesheet(cssLocation); + this._platform.settingsStorage.setString("theme-name", themeName); + if (themeVariant) { + this._platform.settingsStorage.setString("theme-variant", themeVariant); + } + else { + this._platform.settingsStorage.remove("theme-variant"); } - this._platform.replaceStylesheet(themeLocation); - this._platform.settingsStorage.setString("theme", themeId); }); } @@ -142,12 +157,10 @@ export class ThemeLoader { return this._themeMapping; } - async getActiveTheme(): Promise { - const theme = await this._platform.settingsStorage.getString("theme") ?? "default"; - if (theme) { - return theme; - } - throw new Error("Cannot find active theme!"); + async getActiveTheme(): Promise<{themeName: string, themeVariant?: string}> { + const themeName = await this._platform.settingsStorage.getString("theme-name") ?? "Default"; + const themeVariant = await this._platform.settingsStorage.getString("theme-variant"); + return { themeName, themeVariant }; } getDefaultTheme(): string | undefined { @@ -159,16 +172,16 @@ export class ThemeLoader { } } - private _findThemeLocationFromId(themeId: string): string | undefined { - for (const themeData of Object.values(this._themeMapping)) { + private _findThemeDetailsFromId(themeId: string): {themeName: string, cssLocation: string, variant?: string} | undefined { + for (const [themeName, themeData] of Object.entries(this._themeMapping)) { if ("id" in themeData && themeData.id === themeId) { - return themeData.cssLocation; + return { themeName, cssLocation: themeData.cssLocation }; } else if ("light" in themeData && themeData.light?.id === themeId) { - return themeData.light.cssLocation; + return { themeName, cssLocation: themeData.light.cssLocation, variant: "light" }; } else if ("dark" in themeData && themeData.dark?.id === themeId) { - return themeData.dark.cssLocation; + return { themeName, cssLocation: themeData.dark.cssLocation, variant: "dark" }; } } } @@ -182,16 +195,4 @@ export class ThemeLoader { } throw new Error("Cannot find preferred colorscheme!"); } - - async persistVariantToStorage(variant: string) { - await this._platform.settingsStorage.setString("theme-variant", variant); - } - - async getCurrentVariant(): Promise { - return await this._platform.settingsStorage.getString("theme-variant"); - } - - async removeVariantFromStorage(): Promise { - await this._platform.settingsStorage.remove("theme-variant"); - } } diff --git a/src/platform/web/ui/session/settings/SettingsView.js b/src/platform/web/ui/session/settings/SettingsView.js index 1571135f..63fc330a 100644 --- a/src/platform/web/ui/session/settings/SettingsView.js +++ b/src/platform/web/ui/session/settings/SettingsView.js @@ -141,56 +141,47 @@ export class SettingsView extends TemplateView { } _themeOptions(t, vm) { - const activeTheme = vm.activeTheme; + const { themeName: activeThemeName, themeVariant: activeThemeVariant } = vm.activeTheme; const optionTags = []; - const isDarkSelected = vm.activeVariant === "dark"; - const isLightSelected = vm.activeVariant === "light"; // 1. render the dropdown containing the themes - for (const [name, details] of Object.entries(vm.themeMapping)) { - const isSelected = details.id === activeTheme || - details.dark?.id === activeTheme || - details.light?.id === activeTheme; - optionTags.push( t.option({ value: details.id ?? "", selected: isSelected} , name)); + for (const name of Object.keys(vm.themeMapping)) { + optionTags.push( t.option({ value: name, selected: name === activeThemeName} , name)); } const select = t.select({ onChange: (e) => { - const themeId = e.target.value; - if (themeId) { - /* if the