From 242660c51d90254d469e85b9284af0278cc04ebe Mon Sep 17 00:00:00 2001 From: bbedward Date: Fri, 13 Feb 2026 10:31:59 -0500 Subject: [PATCH] theme: improve handling of custom themes with variants and accents in light/dark mode (e.g. catpuccin will react to light/dark changes and remember theme per-mode) fixes #1094 --- quickshell/Common/SettingsData.qml | 33 ++++++++++++++----- quickshell/Common/Theme.qml | 6 ++-- .../Modules/Settings/ThemeColorsTab.qml | 23 ++++++++++--- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 67510f24..3935c360 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -2210,19 +2210,34 @@ Singleton { Theme.reloadCustomThemeVariant(); } - function getRegistryThemeMultiVariant(themeId, defaults) { + function getRegistryThemeMultiVariant(themeId, defaults, mode) { var stored = registryThemeVariants[themeId]; - if (stored && typeof stored === "object") - return stored; - return defaults || {}; + if (!stored || typeof stored !== "object") + return defaults || {}; + if ((stored.dark && typeof stored.dark === "object") || (stored.light && typeof stored.light === "object")) { + if (!mode) + return stored.dark || stored.light || defaults || {}; + var modeData = stored[mode]; + if (modeData && typeof modeData === "object") + return modeData; + return defaults || {}; + } + return stored; } - function setRegistryThemeMultiVariant(themeId, flavor, accent) { + function setRegistryThemeMultiVariant(themeId, flavor, accent, mode) { var variants = JSON.parse(JSON.stringify(registryThemeVariants)); - variants[themeId] = { - flavor: flavor, - accent: accent - }; + var existing = variants[themeId]; + var perMode = {}; + if (existing && typeof existing === "object") { + if ((existing.dark && typeof existing.dark === "object") || (existing.light && typeof existing.light === "object")) { + perMode = existing; + } else if (typeof existing.flavor === "string") { + perMode.dark = {flavor: existing.flavor, accent: existing.accent || ""}; + } + } + perMode[mode || "dark"] = {flavor: flavor, accent: accent}; + variants[themeId] = perMode; registryThemeVariants = variants; saveSettings(); if (typeof Theme !== "undefined") diff --git a/quickshell/Common/Theme.qml b/quickshell/Common/Theme.qml index 02e0cf1c..e8316be8 100644 --- a/quickshell/Common/Theme.qml +++ b/quickshell/Common/Theme.qml @@ -971,7 +971,7 @@ Singleton { if (themeData.variants.type === "multi" && themeData.variants.flavors && themeData.variants.accents) { const defaults = themeData.variants.defaults || {}; const modeDefaults = defaults[colorMode] || defaults.dark || {}; - const stored = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, modeDefaults) : modeDefaults; + const stored = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, modeDefaults, colorMode) : modeDefaults; var flavorId = stored.flavor || modeDefaults.flavor || ""; const accentId = stored.accent || modeDefaults.accent || ""; var flavor = findVariant(themeData.variants.flavors, flavorId); @@ -1365,8 +1365,8 @@ Singleton { const defaults = customThemeRawData.variants.defaults || {}; const darkDefaults = defaults.dark || {}; const lightDefaults = defaults.light || defaults.dark || {}; - const storedDark = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, darkDefaults) : darkDefaults; - const storedLight = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, lightDefaults) : lightDefaults; + const storedDark = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, darkDefaults, "dark") : darkDefaults; + const storedLight = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, lightDefaults, "light") : lightDefaults; const darkFlavorId = storedDark.flavor || darkDefaults.flavor || ""; const lightFlavorId = storedLight.flavor || lightDefaults.flavor || ""; const accentId = storedDark.accent || darkDefaults.accent || ""; diff --git a/quickshell/Modules/Settings/ThemeColorsTab.qml b/quickshell/Modules/Settings/ThemeColorsTab.qml index bd48828d..f4aac4c8 100644 --- a/quickshell/Modules/Settings/ThemeColorsTab.qml +++ b/quickshell/Modules/Settings/ThemeColorsTab.qml @@ -777,13 +777,26 @@ Item { return {}; return activeThemeVariants.defaults[colorMode] || activeThemeVariants.defaults.dark || {}; } - property var storedMulti: activeThemeId ? SettingsData.getRegistryThemeMultiVariant(activeThemeId, multiDefaults) : multiDefaults - property string selectedFlavor: storedMulti.flavor || multiDefaults.flavor || "" + property var storedMulti: activeThemeId ? SettingsData.getRegistryThemeMultiVariant(activeThemeId, multiDefaults, colorMode) : multiDefaults + property string selectedFlavor: { + var sf = storedMulti.flavor || multiDefaults.flavor || ""; + for (var i = 0; i < flavorOptions.length; i++) { + if (flavorOptions[i].id === sf) + return sf; + } + if (flavorOptions.length > 0) + return flavorOptions[0].id; + return sf; + } property string selectedAccent: storedMulti.accent || multiDefaults.accent || "" property var flavorOptions: { if (!isMultiVariant || !activeThemeVariants?.flavors) return []; - return activeThemeVariants.flavors.filter(f => f.mode === colorMode || f.mode === "both"); + return activeThemeVariants.flavors.filter(f => { + if (f.mode) + return f.mode === colorMode || f.mode === "both"; + return !!f[colorMode]; + }); } property var flavorNames: flavorOptions.map(f => f.name) property int flavorIndex: { @@ -842,7 +855,7 @@ Item { if (!flavorId || flavorId === variantSelector.selectedFlavor) return; Theme.screenTransition(); - SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, flavorId, variantSelector.selectedAccent); + SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, flavorId, variantSelector.selectedAccent, variantSelector.colorMode); } } } @@ -905,7 +918,7 @@ Item { if (parent.isSelected) return; Theme.screenTransition(); - SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, variantSelector.selectedFlavor, parent.accentId); + SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, variantSelector.selectedFlavor, parent.accentId, variantSelector.colorMode); } }