1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-30 00:12:50 -05:00

Clean up entire theme system

This commit is contained in:
bbedward
2025-08-20 19:30:45 -04:00
parent daaf1ae74c
commit 0a846fd1ee
7 changed files with 927 additions and 1018 deletions

View File

@@ -1,456 +0,0 @@
pragma Singleton
pragma ComponentBehavior
import Qt.labs.platform
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Services
Singleton {
id: root
readonly property string _homeUrl: StandardPaths.writableLocation(
StandardPaths.HomeLocation)
readonly property string homeDir: _homeUrl.startsWith(
"file://") ? _homeUrl.substring(
7) : _homeUrl
readonly property string _configUrl: StandardPaths.writableLocation(
StandardPaths.ConfigLocation)
readonly property string configDir: _configUrl.startsWith(
"file://") ? _configUrl.substring(
7) : _configUrl
readonly property string shellDir: Qt.resolvedUrl(".").toString().replace(
"file://",
"").replace("/Common/", "")
readonly property string wallpaperPath: SessionData.wallpaperPath
property bool matugenAvailable: false
property bool gtkThemingEnabled: false
property bool qtThemingEnabled: false
property bool systemThemeGenerationInProgress: false
property var matugenColors: ({})
property bool extractionRequested: false
property int colorUpdateTrigger: 0
property string lastWallpaperTimestamp: ""
property color primary: getMatugenColor("primary", "#42a5f5")
property color secondary: getMatugenColor("secondary", "#8ab4f8")
property color tertiary: getMatugenColor("tertiary", "#bb86fc")
property color tertiaryContainer: getMatugenColor("tertiary_container",
"#3700b3")
property color error: getMatugenColor("error", "#cf6679")
property color inversePrimary: getMatugenColor("inverse_primary", "#6200ea")
property color bg: getMatugenColor("background", "#1a1c1e")
property color surface: getMatugenColor("surface", "#1a1c1e")
property color surfaceContainer: getMatugenColor("surface_container",
"#1e2023")
property color surfaceContainerHigh: getMatugenColor(
"surface_container_high",
"#292b2f")
property color surfaceVariant: getMatugenColor("surface_variant", "#44464f")
property color surfaceText: getMatugenColor("on_background", "#e3e8ef")
property color primaryText: getMatugenColor("on_primary", "#ffffff")
property color surfaceVariantText: getMatugenColor("on_surface_variant",
"#c4c7c5")
property color primaryContainer: getMatugenColor("primary_container",
"#1976d2")
property color surfaceTint: getMatugenColor("surface_tint", "#8ab4f8")
property color outline: getMatugenColor("outline", "#8e918f")
property color accentHi: primary
property color accentLo: secondary
signal colorsUpdated
function onLightModeChanged() {
if (matugenColors && Object.keys(matugenColors).length > 0) {
colorUpdateTrigger++
colorsUpdated()
if (typeof Theme !== "undefined" && Theme.isDynamicTheme) {
generateSystemThemes()
}
}
}
function extractColors() {
extractionRequested = true
if (matugenAvailable)
fileChecker.running = true
else
matugenCheck.running = true
}
function getMatugenColor(path, fallback) {
colorUpdateTrigger
const colorMode = (typeof SessionData !== "undefined"
&& SessionData.isLightMode) ? "light" : "dark"
let cur = matugenColors && matugenColors.colors
&& matugenColors.colors[colorMode]
for (const part of path.split(".")) {
if (!cur || typeof cur !== "object" || !(part in cur))
return fallback
cur = cur[part]
}
return cur || fallback
}
function isColorDark(c) {
return (0.299 * c.r + 0.587 * c.g + 0.114 * c.b) < 0.5
}
Component.onCompleted: {
matugenCheck.running = true
checkGtkThemingAvailability()
checkQtThemingAvailability()
if (typeof SessionData !== "undefined")
SessionData.isLightModeChanged.connect(root.onLightModeChanged)
}
Process {
id: matugenCheck
command: ["which", "matugen"]
onExited: code => {
matugenAvailable = (code === 0)
if (!matugenAvailable) {
ToastService.wallpaperErrorStatus = "matugen_missing"
ToastService.showWarning(
"matugen not found - dynamic theming disabled")
return
}
if (extractionRequested) {
fileChecker.running = true
}
}
}
Process {
id: fileChecker
command: ["test", "-r", wallpaperPath]
onExited: code => {
if (code === 0) {
matugenProcess.running = true
} else {
ToastService.wallpaperErrorStatus = "error"
ToastService.showError("Wallpaper processing failed")
}
}
}
Process {
id: matugenProcess
command: ["matugen", "image", wallpaperPath, "--json", "hex"]
stdout: StdioCollector {
id: matugenCollector
onStreamFinished: {
if (!matugenCollector.text) {
ToastService.wallpaperErrorStatus = "error"
ToastService.showError(
"Wallpaper Processing Failed: Empty JSON extracted from matugen output.")
return
}
const extractedJson = extractJsonFromText(matugenCollector.text)
if (!extractedJson) {
ToastService.wallpaperErrorStatus = "error"
ToastService.showError(
"Wallpaper Processing Failed: Invalid JSON extracted from matugen output.")
console.log("Raw matugen output:", matugenCollector.text)
return
}
try {
root.matugenColors = JSON.parse(extractedJson)
root.colorsUpdated()
generateAppConfigs()
ToastService.clearWallpaperError()
} catch (e) {
ToastService.wallpaperErrorStatus = "error"
ToastService.showError(
"Wallpaper processing failed (JSON parse error after extraction)")
}
}
}
onExited: code => {
if (code !== 0) {
ToastService.wallpaperErrorStatus = "error"
ToastService.showError(
"Matugen command failed with exit code " + code)
}
}
}
function generateAppConfigs() {
if (!matugenColors || !matugenColors.colors) {
return
}
generateNiriConfig()
generateGhosttyConfig()
if (gtkThemingEnabled && typeof SettingsData !== "undefined"
&& SettingsData.gtkThemingEnabled) {
generateSystemThemes()
} else if (qtThemingEnabled && typeof SettingsData !== "undefined"
&& SettingsData.qtThemingEnabled) {
generateSystemThemes()
}
}
function generateNiriConfig() {
var dark = matugenColors.colors.dark
if (!dark)
return
var bg = dark.background || "#1a1c1e"
var primary = dark.primary || "#42a5f5"
var secondary = dark.secondary || "#8ab4f8"
var inverse = dark.inverse_primary || "#6200ea"
var content = `layout {
border {
active-color "${primary}"
inactive-color "${secondary}"
}
focus-ring {
active-color "${inverse}"
}
background-color "${bg}"
}`
Quickshell.execDetached(
["bash", "-c", `echo '${content}' > niri-colors.generated.kdl`])
}
function generateGhosttyConfig() {
var dark = matugenColors.colors.dark
var light = matugenColors.colors.light
if (!dark || !light)
return
var bg = dark.background || "#1a1c1e"
var fg = dark.on_background || "#e3e8ef"
var primary = dark.primary || "#42a5f5"
var secondary = dark.secondary || "#8ab4f8"
var tertiary = dark.tertiary || "#bb86fc"
var tertiary_ctr = dark.tertiary_container || "#3700b3"
var error = dark.error || "#cf6679"
var inverse = dark.inverse_primary || "#6200ea"
var bg_b = light.background || "#fef7ff"
var fg_b = light.on_background || "#1d1b20"
var primary_b = light.primary || "#1976d2"
var secondary_b = light.secondary || "#1565c0"
var tertiary_b = light.tertiary || "#7b1fa2"
var tertiary_ctr_b = light.tertiary_container || "#e1bee7"
var error_b = light.error || "#b00020"
var inverse_b = light.inverse_primary || "#bb86fc"
var content = `background = ${bg}
foreground = ${fg}
cursor-color = ${inverse}
selection-background = ${secondary}
selection-foreground = #ffffff
palette = 0=${bg}
palette = 1=${error}
palette = 2=${tertiary}
palette = 3=${secondary}
palette = 4=${primary}
palette = 5=${tertiary_ctr}
palette = 6=${inverse}
palette = 7=${fg}
palette = 8=${bg_b}
palette = 9=${error_b}
palette = 10=${tertiary_b}
palette = 11=${secondary_b}
palette = 12=${primary_b}
palette = 13=${tertiary_ctr_b}
palette = 14=${inverse_b}
palette = 15=${fg_b}`
var ghosttyConfigDir = configDir + "/ghostty"
var ghosttyConfigPath = ghosttyConfigDir + "/config-dankcolors"
Quickshell.execDetached(
["bash", "-c", `mkdir -p '${ghosttyConfigDir}' && echo '${content}' > '${ghosttyConfigPath}'`])
}
function checkGtkThemingAvailability() {
gtkAvailabilityChecker.running = true
}
function checkQtThemingAvailability() {
qtAvailabilityChecker.running = true
}
function generateSystemThemes() {
if (systemThemeGenerationInProgress) {
return
}
if (!matugenAvailable) {
return
}
if (!wallpaperPath || wallpaperPath === "") {
return
}
const isLight = (typeof SessionData !== "undefined"
&& SessionData.isLightMode) ? "true" : "false"
const iconTheme = (typeof SettingsData !== "undefined"
&& SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"
const gtkTheming = (typeof SettingsData !== "undefined"
&& SettingsData.gtkThemingEnabled) ? "true" : "false"
const qtTheming = (typeof SettingsData !== "undefined"
&& SettingsData.qtThemingEnabled) ? "true" : "false"
systemThemeGenerationInProgress = true
systemThemeGenerator.command = [shellDir + "/generate-themes.sh", wallpaperPath, shellDir, configDir, "generate", isLight, iconTheme, gtkTheming, qtTheming]
systemThemeGenerator.running = true
}
function restoreSystemThemes() {
const shellDir = root.shellDir
if (!shellDir) {
return
}
const isLight = (typeof SessionData !== "undefined"
&& SessionData.isLightMode) ? "true" : "false"
const iconTheme = (typeof SettingsData !== "undefined"
&& SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"
const gtkTheming = (typeof SettingsData !== "undefined"
&& SettingsData.gtkThemingEnabled) ? "true" : "false"
const qtTheming = (typeof SettingsData !== "undefined"
&& SettingsData.qtThemingEnabled) ? "true" : "false"
systemThemeRestoreProcess.command = [shellDir + "/generate-themes.sh", "", shellDir, configDir, "restore", isLight, iconTheme, gtkTheming, qtTheming]
systemThemeRestoreProcess.running = true
}
// Returns the first complete JSON substring (object or array) or null.
function extractJsonFromText(text) {
if (!text)
return null
const start = text.search(/[{\[]/)
if (start === -1)
return null
const open = text[start]
const pairs = {
"{": '}',
"[": ']'
}
const close = pairs[open]
if (!close)
return null
let inString = false
let escape = false
const stack = [open]
for (var i = start + 1; i < text.length; i++) {
const ch = text[i]
if (inString) {
if (escape) {
escape = false
} else if (ch === '\\') {
escape = true
} else if (ch === '"') {
inString = false
}
continue
}
if (ch === '"') {
inString = true
continue
}
if (ch === '{' || ch === '[') {
stack.push(ch)
continue
}
if (ch === '}' || ch === ']') {
const last = stack.pop()
if (!last || pairs[last] !== ch) {
return null
}
if (stack.length === 0) {
return text.slice(start, i + 1)
}
}
}
return null
}
Process {
id: gtkAvailabilityChecker
command: ["bash", "-c", "command -v gsettings >/dev/null && [ -d "
+ configDir + "/gtk-3.0 -o -d " + configDir + "/gtk-4.0 ]"]
running: false
onExited: exitCode => {
gtkThemingEnabled = (exitCode === 0)
}
}
Process {
id: qtAvailabilityChecker
command: ["bash", "-c", "command -v qt5ct >/dev/null || command -v qt6ct >/dev/null"]
running: false
onExited: exitCode => {
qtThemingEnabled = (exitCode === 0)
}
}
Process {
id: systemThemeGenerator
running: false
stdout: StdioCollector {
id: systemThemeStdout
}
stderr: StdioCollector {
id: systemThemeStderr
}
onExited: exitCode => {
systemThemeGenerationInProgress = false
if (exitCode !== 0) {
ToastService.showError(
"Failed to generate system themes: " + systemThemeStderr.text)
}
}
}
Process {
id: systemThemeRestoreProcess
running: false
stdout: StdioCollector {
id: restoreThemeStdout
}
stderr: StdioCollector {
id: restoreThemeStderr
}
onExited: exitCode => {
if (exitCode === 0) {
ToastService.showInfo("System themes restored to default")
} else {
ToastService.showWarning(
"Failed to restore system themes: " + restoreThemeStderr.text)
}
}
}
}

View File

@@ -129,9 +129,9 @@ Singleton {
wallpaperPath = imagePath wallpaperPath = imagePath
saveSettings() saveSettings()
if (typeof Colors !== "undefined" && typeof SettingsData !== "undefined" if (typeof Theme !== "undefined" && typeof SettingsData !== "undefined"
&& SettingsData.wallpaperDynamicTheming) { && SettingsData.wallpaperDynamicTheming) {
Colors.extractColors() Theme.extractColors()
} }
} }

View File

@@ -10,8 +10,8 @@ pragma ComponentBehavior
Singleton { Singleton {
id: root id: root
property int themeIndex: 0 // Theme settings
property bool themeIsDynamic: false property string currentThemeName: "blue"
property real topBarTransparency: 0.75 property real topBarTransparency: 0.75
property real topBarWidgetTransparency: 0.85 property real topBarWidgetTransparency: 0.85
property real popupTransparency: 0.92 property real popupTransparency: 0.92
@@ -114,9 +114,18 @@ Singleton {
try { try {
if (content && content.trim()) { if (content && content.trim()) {
var settings = JSON.parse(content) var settings = JSON.parse(content)
themeIndex = settings.themeIndex !== undefined ? settings.themeIndex : 0 // Auto-migrate from old theme system
themeIsDynamic = settings.themeIsDynamic if (settings.themeIndex !== undefined || settings.themeIsDynamic !== undefined) {
!== undefined ? settings.themeIsDynamic : false const themeNames = ["blue", "deepBlue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral"]
if (settings.themeIsDynamic) {
currentThemeName = "dynamic"
} else if (settings.themeIndex >= 0 && settings.themeIndex < themeNames.length) {
currentThemeName = themeNames[settings.themeIndex]
}
console.log("Auto-migrated theme from index", settings.themeIndex, "to", currentThemeName)
} else {
currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "blue"
}
topBarTransparency = settings.topBarTransparency topBarTransparency = settings.topBarTransparency
!== undefined ? (settings.topBarTransparency !== undefined ? (settings.topBarTransparency
> 1 ? settings.topBarTransparency > 1 ? settings.topBarTransparency
@@ -278,8 +287,7 @@ Singleton {
function saveSettings() { function saveSettings() {
settingsFile.setText(JSON.stringify({ settingsFile.setText(JSON.stringify({
"themeIndex": themeIndex, "currentThemeName": currentThemeName,
"themeIsDynamic": themeIsDynamic,
"topBarTransparency": topBarTransparency, "topBarTransparency": topBarTransparency,
"topBarWidgetTransparency": topBarWidgetTransparency, "topBarWidgetTransparency": topBarWidgetTransparency,
"popupTransparency": popupTransparency, "popupTransparency": popupTransparency,
@@ -438,18 +446,16 @@ Singleton {
function applyStoredTheme() { function applyStoredTheme() {
if (typeof Theme !== "undefined") if (typeof Theme !== "undefined")
Theme.switchTheme(themeIndex, themeIsDynamic, false) Theme.switchTheme(currentThemeName, false)
else else
Qt.callLater(() => { Qt.callLater(() => {
if (typeof Theme !== "undefined") if (typeof Theme !== "undefined")
Theme.switchTheme(themeIndex, Theme.switchTheme(currentThemeName, false)
themeIsDynamic, false)
}) })
} }
function setTheme(index, isDynamic) { function setTheme(themeName) {
themeIndex = index currentThemeName = themeName
themeIsDynamic = isDynamic
saveSettings() saveSettings()
} }
@@ -717,9 +723,8 @@ Singleton {
updateGtkIconTheme(themeName) updateGtkIconTheme(themeName)
updateQtIconTheme(themeName) updateQtIconTheme(themeName)
saveSettings() saveSettings()
if (typeof Theme !== "undefined" && Theme.isDynamicTheme if (typeof Theme !== "undefined" && Theme.isDynamicTheme)
&& typeof Colors !== "undefined") Theme.generateSystemThemes()
Colors.generateSystemThemes()
} }
function updateGtkIconTheme(themeName) { function updateGtkIconTheme(themeName) {

380
Common/StockThemes.js Normal file
View File

@@ -0,0 +1,380 @@
// Stock theme definitions for DankMaterialShell
// Separated from Theme.qml to keep that file clean
const StockThemes = {
DARK: {
blue: {
name: "Blue",
primary: "#42a5f5",
primaryText: "#ffffff",
primaryContainer: "#1976d2",
secondary: "#8ab4f8",
surface: "#1a1c1e",
surfaceText: "#e3e8ef",
surfaceVariant: "#44464f",
surfaceVariantText: "#c4c7c5",
surfaceTint: "#8ab4f8",
background: "#1a1c1e",
backgroundText: "#e3e8ef",
outline: "#8e918f",
surfaceContainer: "#1e2023",
surfaceContainerHigh: "#292b2f"
},
deepBlue: {
name: "Deep Blue",
primary: "#0061a4",
primaryText: "#ffffff",
primaryContainer: "#004881",
secondary: "#42a5f5",
surface: "#1a1c1e",
surfaceText: "#e3e8ef",
surfaceVariant: "#44464f",
surfaceVariantText: "#c4c7c5",
surfaceTint: "#8ab4f8",
background: "#1a1c1e",
backgroundText: "#e3e8ef",
outline: "#8e918f",
surfaceContainer: "#1e2023",
surfaceContainerHigh: "#292b2f"
},
purple: {
name: "Purple",
primary: "#D0BCFF",
primaryText: "#381E72",
primaryContainer: "#4F378B",
secondary: "#CCC2DC",
surface: "#10121E",
surfaceText: "#E6E0E9",
surfaceVariant: "#49454F",
surfaceVariantText: "#CAC4D0",
surfaceTint: "#D0BCFF",
background: "#10121E",
backgroundText: "#E6E0E9",
outline: "#938F99",
surfaceContainer: "#1D1B20",
surfaceContainerHigh: "#2B2930"
},
green: {
name: "Green",
primary: "#4caf50",
primaryText: "#ffffff",
primaryContainer: "#388e3c",
secondary: "#81c995",
surface: "#0f1411",
surfaceText: "#e1f5e3",
surfaceVariant: "#404943",
surfaceVariantText: "#c1cbc4",
surfaceTint: "#81c995",
background: "#0f1411",
backgroundText: "#e1f5e3",
outline: "#8b938c",
surfaceContainer: "#1a1f1b",
surfaceContainerHigh: "#252a26"
},
orange: {
name: "Orange",
primary: "#ff6d00",
primaryText: "#ffffff",
primaryContainer: "#e65100",
secondary: "#ffb74d",
surface: "#1c1410",
surfaceText: "#f5f1ea",
surfaceVariant: "#4a453a",
surfaceVariantText: "#cbc5b8",
surfaceTint: "#ffb74d",
background: "#1c1410",
backgroundText: "#f5f1ea",
outline: "#958f84",
surfaceContainer: "#211e17",
surfaceContainerHigh: "#2c291f"
},
red: {
name: "Red",
primary: "#f44336",
primaryText: "#ffffff",
primaryContainer: "#d32f2f",
secondary: "#f28b82",
surface: "#1c1011",
surfaceText: "#f5e8ea",
surfaceVariant: "#4a3f41",
surfaceVariantText: "#cbc2c4",
surfaceTint: "#f28b82",
background: "#1c1011",
backgroundText: "#f5e8ea",
outline: "#958b8d",
surfaceContainer: "#211b1c",
surfaceContainerHigh: "#2c2426"
},
cyan: {
name: "Cyan",
primary: "#00bcd4",
primaryText: "#ffffff",
primaryContainer: "#0097a7",
secondary: "#4dd0e1",
surface: "#0f1617",
surfaceText: "#e8f4f5",
surfaceVariant: "#3f474a",
surfaceVariantText: "#c2c9cb",
surfaceTint: "#4dd0e1",
background: "#0f1617",
backgroundText: "#e8f4f5",
outline: "#8c9194",
surfaceContainer: "#1a1f20",
surfaceContainerHigh: "#252b2c"
},
pink: {
name: "Pink",
primary: "#e91e63",
primaryText: "#ffffff",
primaryContainer: "#c2185b",
secondary: "#f8bbd9",
surface: "#1a1014",
surfaceText: "#f3e8ee",
surfaceVariant: "#483f45",
surfaceVariantText: "#c9c2c7",
surfaceTint: "#f8bbd9",
background: "#1a1014",
backgroundText: "#f3e8ee",
outline: "#938a90",
surfaceContainer: "#1f1b1e",
surfaceContainerHigh: "#2a2428"
},
amber: {
name: "Amber",
primary: "#ffc107",
primaryText: "#000000",
primaryContainer: "#ff8f00",
secondary: "#ffd54f",
surface: "#1a1710",
surfaceText: "#f3f0e8",
surfaceVariant: "#49453a",
surfaceVariantText: "#cac5b8",
surfaceTint: "#ffd54f",
background: "#1a1710",
backgroundText: "#f3f0e8",
outline: "#949084",
surfaceContainer: "#1f1e17",
surfaceContainerHigh: "#2a281f"
},
coral: {
name: "Coral",
primary: "#ffb4ab",
primaryText: "#5f1412",
primaryContainer: "#8c1d18",
secondary: "#f9dedc",
surface: "#1a1110",
surfaceText: "#f1e8e7",
surfaceVariant: "#4a4142",
surfaceVariantText: "#cdc2c1",
surfaceTint: "#ffb4ab",
background: "#1a1110",
backgroundText: "#f1e8e7",
outline: "#968b8a",
surfaceContainer: "#201a19",
surfaceContainerHigh: "#2b2221"
}
},
LIGHT: {
blue: {
name: "Blue Light",
primary: "#1976d2",
primaryText: "#ffffff",
primaryContainer: "#e3f2fd",
secondary: "#42a5f5",
surface: "#fefefe",
surfaceText: "#1a1c1e",
surfaceVariant: "#e7e0ec",
surfaceVariantText: "#49454f",
surfaceTint: "#1976d2",
background: "#fefefe",
backgroundText: "#1a1c1e",
outline: "#79747e",
surfaceContainer: "#f3f3f3",
surfaceContainerHigh: "#ececec"
},
deepBlue: {
name: "Deep Blue Light",
primary: "#0061a4",
primaryText: "#ffffff",
primaryContainer: "#cfe5ff",
secondary: "#1976d2",
surface: "#fefefe",
surfaceText: "#1a1c1e",
surfaceVariant: "#e7e0ec",
surfaceVariantText: "#49454f",
surfaceTint: "#0061a4",
background: "#fefefe",
backgroundText: "#1a1c1e",
outline: "#79747e",
surfaceContainer: "#f3f3f3",
surfaceContainerHigh: "#ececec"
},
purple: {
name: "Purple Light",
primary: "#6750A4",
primaryText: "#ffffff",
primaryContainer: "#EADDFF",
secondary: "#625B71",
surface: "#FFFBFE",
surfaceText: "#1C1B1F",
surfaceVariant: "#E7E0EC",
surfaceVariantText: "#49454F",
surfaceTint: "#6750A4",
background: "#FFFBFE",
backgroundText: "#1C1B1F",
outline: "#79747E",
surfaceContainer: "#F3EDF7",
surfaceContainerHigh: "#ECE6F0"
},
green: {
name: "Green Light",
primary: "#2e7d32",
primaryText: "#ffffff",
primaryContainer: "#e8f5e8",
secondary: "#4caf50",
surface: "#fefefe",
surfaceText: "#1a1c1e",
surfaceVariant: "#e7e0ec",
surfaceVariantText: "#49454f",
surfaceTint: "#2e7d32",
background: "#fefefe",
backgroundText: "#1a1c1e",
outline: "#79747e",
surfaceContainer: "#f3f3f3",
surfaceContainerHigh: "#ececec"
},
orange: {
name: "Orange Light",
primary: "#e65100",
primaryText: "#ffffff",
primaryContainer: "#ffecb3",
secondary: "#ff9800",
surface: "#fefefe",
surfaceText: "#1a1c1e",
surfaceVariant: "#e7e0ec",
surfaceVariantText: "#49454f",
surfaceTint: "#e65100",
background: "#fefefe",
backgroundText: "#1a1c1e",
outline: "#79747e",
surfaceContainer: "#f3f3f3",
surfaceContainerHigh: "#ececec"
},
red: {
name: "Red Light",
primary: "#d32f2f",
primaryText: "#ffffff",
primaryContainer: "#ffebee",
secondary: "#f44336",
surface: "#fefefe",
surfaceText: "#1a1c1e",
surfaceVariant: "#e7e0ec",
surfaceVariantText: "#49454f",
surfaceTint: "#d32f2f",
background: "#fefefe",
backgroundText: "#1a1c1e",
outline: "#79747e",
surfaceContainer: "#f3f3f3",
surfaceContainerHigh: "#ececec"
},
cyan: {
name: "Cyan Light",
primary: "#0097a7",
primaryText: "#ffffff",
primaryContainer: "#e0f2f1",
secondary: "#00bcd4",
surface: "#fefefe",
surfaceText: "#1a1c1e",
surfaceVariant: "#e7e0ec",
surfaceVariantText: "#49454f",
surfaceTint: "#0097a7",
background: "#fefefe",
backgroundText: "#1a1c1e",
outline: "#79747e",
surfaceContainer: "#f3f3f3",
surfaceContainerHigh: "#ececec"
},
pink: {
name: "Pink Light",
primary: "#c2185b",
primaryText: "#ffffff",
primaryContainer: "#fce4ec",
secondary: "#e91e63",
surface: "#fefefe",
surfaceText: "#1a1c1e",
surfaceVariant: "#e7e0ec",
surfaceVariantText: "#49454f",
surfaceTint: "#c2185b",
background: "#fefefe",
backgroundText: "#1a1c1e",
outline: "#79747e",
surfaceContainer: "#f3f3f3",
surfaceContainerHigh: "#ececec"
},
amber: {
name: "Amber Light",
primary: "#ff8f00",
primaryText: "#000000",
primaryContainer: "#fff8e1",
secondary: "#ffc107",
surface: "#fefefe",
surfaceText: "#1a1c1e",
surfaceVariant: "#e7e0ec",
surfaceVariantText: "#49454f",
surfaceTint: "#ff8f00",
background: "#fefefe",
backgroundText: "#1a1c1e",
outline: "#79747e",
surfaceContainer: "#f3f3f3",
surfaceContainerHigh: "#ececec"
},
coral: {
name: "Coral Light",
primary: "#8c1d18",
primaryText: "#ffffff",
primaryContainer: "#ffdad6",
secondary: "#ff5449",
surface: "#fefefe",
surfaceText: "#1a1c1e",
surfaceVariant: "#e7e0ec",
surfaceVariantText: "#49454f",
surfaceTint: "#8c1d18",
background: "#fefefe",
backgroundText: "#1a1c1e",
outline: "#79747e",
surfaceContainer: "#f3f3f3",
surfaceContainerHigh: "#ececec"
}
}
}
const ThemeNames = {
BLUE: "blue",
DEEP_BLUE: "deepBlue",
PURPLE: "purple",
GREEN: "green",
ORANGE: "orange",
RED: "red",
CYAN: "cyan",
PINK: "pink",
AMBER: "amber",
CORAL: "coral",
DYNAMIC: "dynamic"
}
function isStockTheme(themeName) {
return Object.keys(StockThemes.DARK).includes(themeName)
}
function getAvailableThemes(isLight = false) {
return isLight ? StockThemes.LIGHT : StockThemes.DARK
}
function getThemeByName(themeName, isLight = false) {
const themes = getAvailableThemes(isLight)
return themes[themeName] || themes.blue
}
function getAllThemeNames() {
return Object.keys(StockThemes.DARK)
}

File diff suppressed because it is too large Load Diff

View File

@@ -625,9 +625,9 @@ Item {
enabled: ToastService.wallpaperErrorStatus !== "matugen_missing" enabled: ToastService.wallpaperErrorStatus !== "matugen_missing"
onToggled: toggled => { onToggled: toggled => {
if (toggled) if (toggled)
Theme.switchTheme(10, true) Theme.switchTheme(Theme.dynamic)
else else
Theme.switchTheme(0) Theme.switchTheme("blue")
} }
} }
} }

View File

@@ -138,7 +138,7 @@ Item {
spacing: Theme.spacingS spacing: Theme.spacingS
StyledText { StyledText {
text: "Current Theme: " + (Theme.isDynamicTheme ? "Auto" : (Theme.currentThemeIndex < Theme.themes.length ? Theme.themes[Theme.currentThemeIndex].name : "Blue")) text: "Current Theme: " + (Theme.isDynamicTheme ? "Dynamic" : Theme.getThemeColors(Theme.currentThemeName).name)
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
@@ -150,9 +150,19 @@ Item {
if (Theme.isDynamicTheme) if (Theme.isDynamicTheme)
return "Wallpaper-based dynamic colors" return "Wallpaper-based dynamic colors"
var descriptions = ["Material blue inspired by modern interfaces", "Deep blue inspired by material 3", "Rich purple tones for BB elegance", "Natural green for productivity", "Energetic orange for creativity", "Bold red for impact", "Cool cyan for tranquility", "Vibrant pink for expression", "Warm amber for comfort", "Soft coral for gentle warmth"] var descriptions = {
return descriptions[Theme.currentThemeIndex] "blue": "Material blue inspired by modern interfaces",
|| "Select a theme" "deepBlue": "Deep blue inspired by material 3",
"purple": "Rich purple tones for elegance",
"green": "Natural green for productivity",
"orange": "Energetic orange for creativity",
"red": "Bold red for impact",
"cyan": "Cool cyan for tranquility",
"pink": "Vibrant pink for expression",
"amber": "Warm amber for comfort",
"coral": "Soft coral for gentle warmth"
}
return descriptions[Theme.currentThemeName] || "Select a theme"
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
@@ -172,17 +182,18 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
Repeater { Repeater {
model: 5 model: Theme.availableThemeNames.slice(0, 5)
Rectangle { Rectangle {
property string themeName: modelData
width: 32 width: 32
height: 32 height: 32
radius: 16 radius: 16
color: Theme.themes[index].primary color: Theme.getThemeColors(themeName).primary
border.color: Theme.outline border.color: Theme.outline
border.width: (Theme.currentThemeIndex === index border.width: (Theme.currentThemeName === themeName
&& !Theme.isDynamicTheme) ? 2 : 1 && !Theme.isDynamicTheme) ? 2 : 1
scale: (Theme.currentThemeIndex === index scale: (Theme.currentThemeName === themeName
&& !Theme.isDynamicTheme) ? 1.1 : 1 && !Theme.isDynamicTheme) ? 1.1 : 1
Rectangle { Rectangle {
@@ -200,7 +211,7 @@ Item {
StyledText { StyledText {
id: nameText id: nameText
text: Theme.themes[index].name text: Theme.getThemeColors(themeName).name
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
anchors.centerIn: parent anchors.centerIn: parent
@@ -214,7 +225,7 @@ Item {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
Theme.switchTheme(index, false) Theme.switchTheme(themeName, false)
} }
} }
@@ -240,19 +251,19 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
Repeater { Repeater {
model: 5 model: Theme.availableThemeNames.slice(5, 10)
Rectangle { Rectangle {
property int themeIndex: index + 5 property string themeName: modelData
width: 32 width: 32
height: 32 height: 32
radius: 16 radius: 16
color: themeIndex < Theme.themes.length ? Theme.themes[themeIndex].primary : "transparent" color: Theme.getThemeColors(themeName).primary
border.color: Theme.outline border.color: Theme.outline
border.width: Theme.currentThemeIndex === themeIndex ? 2 : 1 border.width: Theme.currentThemeName === themeName ? 2 : 1
visible: themeIndex < Theme.themes.length visible: true
scale: Theme.currentThemeIndex === themeIndex ? 1.1 : 1 scale: Theme.currentThemeName === themeName ? 1.1 : 1
Rectangle { Rectangle {
width: nameText2.contentWidth + Theme.spacingS * 2 width: nameText2.contentWidth + Theme.spacingS * 2
@@ -265,12 +276,11 @@ Item {
anchors.bottomMargin: Theme.spacingXS anchors.bottomMargin: Theme.spacingXS
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: mouseArea2.containsMouse visible: mouseArea2.containsMouse
&& themeIndex < Theme.themes.length
StyledText { StyledText {
id: nameText2 id: nameText2
text: themeIndex < Theme.themes.length ? Theme.themes[themeIndex].name : "" text: Theme.getThemeColors(themeName).name
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
anchors.centerIn: parent anchors.centerIn: parent
@@ -284,8 +294,7 @@ Item {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if (themeIndex < Theme.themes.length) Theme.switchTheme(themeName)
Theme.switchTheme(themeIndex)
} }
} }
@@ -404,7 +413,7 @@ Item {
ToastService.showError( ToastService.showError(
"Wallpaper processing failed - check wallpaper path") "Wallpaper processing failed - check wallpaper path")
else else
Theme.switchTheme(10, true) Theme.switchTheme(Theme.dynamic)
} }
} }
@@ -691,7 +700,7 @@ Item {
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2) Theme.outline.b, 0.2)
border.width: 1 border.width: 1
visible: Theme.isDynamicTheme && Colors.matugenAvailable visible: Theme.isDynamicTheme && Theme.matugenAvailable
Column { Column {
id: systemThemingSection id: systemThemingSection
@@ -723,9 +732,9 @@ Item {
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Theme GTK Applications" text: "Theme GTK Applications"
description: Colors.gtkThemingEnabled ? "File managers, text editors, and system dialogs will match your theme" : "GTK theming not available (install gsettings)" description: Theme.gtkThemingEnabled ? "File managers, text editors, and system dialogs will match your theme" : "GTK theming not available (install gsettings)"
enabled: Colors.gtkThemingEnabled enabled: Theme.gtkThemingEnabled
checked: Colors.gtkThemingEnabled checked: Theme.gtkThemingEnabled
&& SettingsData.gtkThemingEnabled && SettingsData.gtkThemingEnabled
onToggled: function (checked) { onToggled: function (checked) {
SettingsData.setGtkThemingEnabled(checked) SettingsData.setGtkThemingEnabled(checked)
@@ -735,9 +744,9 @@ Item {
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Theme Qt Applications" text: "Theme Qt Applications"
description: Colors.qtThemingEnabled ? "Qt applications will match your theme colors" : "Qt theming not available (install qt5ct or qt6ct)" description: Theme.qtThemingEnabled ? "Qt applications will match your theme colors" : "Qt theming not available (install qt5ct or qt6ct)"
enabled: Colors.qtThemingEnabled enabled: Theme.qtThemingEnabled
checked: Colors.qtThemingEnabled checked: Theme.qtThemingEnabled
&& SettingsData.qtThemingEnabled && SettingsData.qtThemingEnabled
onToggled: function (checked) { onToggled: function (checked) {
SettingsData.setQtThemingEnabled(checked) SettingsData.setQtThemingEnabled(checked)