mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2025-12-06 06:36:15 +00:00
ColorSchemeTab: auto-detect themabale discord client
This commit is contained in:
@@ -558,9 +558,9 @@
|
||||
"description": "Schreibt {filepath} und lädt neu",
|
||||
"description-missing": "Erfordert fuzzel Starter"
|
||||
},
|
||||
"vesktop": {
|
||||
"description": "Schreibt {filepath}",
|
||||
"description-missing": "Erfordert vesktop Discord-Client"
|
||||
"discord": {
|
||||
"description": "Schreibt {filepath} für {client}",
|
||||
"description-missing": "Kein Discord-Client erkannt. Installieren Sie vesktop, webcord, armcord, equibop, lightcord oder dorion."
|
||||
},
|
||||
"pywalfox": {
|
||||
"description": "Schreibt {filepath} und führt pywalfox update aus",
|
||||
|
||||
@@ -560,9 +560,9 @@
|
||||
"description": "Write {filepath} and reload",
|
||||
"description-missing": "Requires {app} to be installed"
|
||||
},
|
||||
"vesktop": {
|
||||
"description": "Write {filepath}",
|
||||
"description-missing": "Requires {app} to be installed"
|
||||
"discord": {
|
||||
"description": "Write {filepath} for {client}",
|
||||
"description-missing": "No Discord client detected. Install vesktop, webcord, armcord, equibop, lightcord, or dorion."
|
||||
},
|
||||
"pywalfox": {
|
||||
"description": "Write {filepath} and run pywalfox update",
|
||||
|
||||
@@ -554,9 +554,9 @@
|
||||
"description": "Escribir {filepath} y recargar",
|
||||
"description-missing": "Requiere que {app} esté instalado"
|
||||
},
|
||||
"vesktop": {
|
||||
"description": "Escribir {filepath}",
|
||||
"description-missing": "Requiere que {app} esté instalado"
|
||||
"discord": {
|
||||
"description": "Escribir {filepath} para {client}",
|
||||
"description-missing": "No se detectó cliente de Discord. Instala vesktop, webcord, armcord, equibop, lightcord o dorion."
|
||||
},
|
||||
"pywalfox": {
|
||||
"description": "Escribir {filepath} y ejecutar pywalfox update",
|
||||
|
||||
@@ -554,9 +554,9 @@
|
||||
"description": "Écrire ~/.config/fuzzel/themes/noctalia et recharger",
|
||||
"description-missing": "Nécessite que le lanceur fuzzel soit installé"
|
||||
},
|
||||
"vesktop": {
|
||||
"description": "Écrire ~/.config/vesktop/themes/noctalia.theme.css",
|
||||
"description-missing": "Nécessite que le client Discord vesktop soit installé"
|
||||
"discord": {
|
||||
"description": "Écrire {filepath} pour {client}",
|
||||
"description-missing": "Aucun client Discord détecté. Installez vesktop, webcord, armcord, equibop, lightcord ou dorion."
|
||||
},
|
||||
"pywalfox": {
|
||||
"description": "Écrire ~/.cache/wal/colors.json et exécuter pywalfox update",
|
||||
|
||||
@@ -520,9 +520,9 @@
|
||||
"description": "Escrever {filepath} e recarregar",
|
||||
"description-missing": "Requer que o {app} esteja instalado"
|
||||
},
|
||||
"vesktop": {
|
||||
"description": "Escrever {filepath}",
|
||||
"description-missing": "Requer que o {app} esteja instalado"
|
||||
"discord": {
|
||||
"description": "Escrever {filepath} para {client}",
|
||||
"description-missing": "Nenhum cliente Discord detectado. Instale vesktop, webcord, armcord, equibop, lightcord ou dorion."
|
||||
},
|
||||
"pywalfox": {
|
||||
"description": "Escrever {filepath} e executar pywalfox update",
|
||||
|
||||
@@ -554,9 +554,9 @@
|
||||
"description": "写入 {filepath} 并重新加载",
|
||||
"description-missing": "需要安装 {app}"
|
||||
},
|
||||
"vesktop": {
|
||||
"description": "写入 {filepath}",
|
||||
"description-missing": "需要安装 {app}"
|
||||
"discord": {
|
||||
"description": "为 {client} 写入 {filepath}",
|
||||
"description-missing": "未检测到 Discord 客户端。请安装 vesktop、webcord、armcord、equibop、lightcord 或 dorion。"
|
||||
},
|
||||
"pywalfox": {
|
||||
"description": "写入 {filepath} 并运行 pywalfox update",
|
||||
|
||||
@@ -176,7 +176,13 @@
|
||||
"ghostty": false,
|
||||
"foot": false,
|
||||
"fuzzel": false,
|
||||
"vesktop": false,
|
||||
"discord": false,
|
||||
"discord_vesktop": false,
|
||||
"discord_webcord": false,
|
||||
"discord_armcord": false,
|
||||
"discord_equibop": false,
|
||||
"discord_lightcord": false,
|
||||
"discord_dorion": false,
|
||||
"pywalfox": false,
|
||||
"enableUserTemplates": false
|
||||
},
|
||||
|
||||
@@ -327,7 +327,13 @@ Singleton {
|
||||
property bool ghostty: false
|
||||
property bool foot: false
|
||||
property bool fuzzel: false
|
||||
property bool vesktop: false
|
||||
property bool discord: false
|
||||
property bool discord_vesktop: false
|
||||
property bool discord_webcord: false
|
||||
property bool discord_armcord: false
|
||||
property bool discord_equibop: false
|
||||
property bool discord_lightcord: false
|
||||
property bool discord_dorion: false
|
||||
property bool pywalfox: false
|
||||
property bool enableUserTemplates: false
|
||||
}
|
||||
|
||||
@@ -494,22 +494,29 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
NCheckbox {
|
||||
label: "Vesktop"
|
||||
description: ProgramCheckerService.vesktopAvailable ? I18n.tr("settings.color-scheme.templates.programs.vesktop.description", {
|
||||
"filepath": "~/.config/vesktop/themes/noctalia.theme.css"
|
||||
}) : I18n.tr("settings.color-scheme.templates.programs.vesktop.description-missing", {
|
||||
"app": "vesktop"
|
||||
})
|
||||
checked: Settings.data.templates.vesktop
|
||||
enabled: ProgramCheckerService.vesktopAvailable
|
||||
opacity: ProgramCheckerService.vesktopAvailable ? 1.0 : 0.6
|
||||
onToggled: checked => {
|
||||
if (ProgramCheckerService.vesktopAvailable) {
|
||||
Settings.data.templates.vesktop = checked
|
||||
// Show individual checkboxes for each detected Discord client
|
||||
Repeater {
|
||||
model: ProgramCheckerService.availableDiscordClients
|
||||
delegate: NCheckbox {
|
||||
label: modelData.name.charAt(0).toUpperCase() + modelData.name.slice(1)
|
||||
description: I18n.tr("settings.color-scheme.templates.programs.discord.description", {
|
||||
"client": modelData.name.charAt(0).toUpperCase() + modelData.name.slice(1),
|
||||
"filepath": modelData.themePath
|
||||
})
|
||||
checked: Settings.data.templates["discord_" + modelData.name] || false
|
||||
onToggled: checked => {
|
||||
Settings.data.templates["discord_" + modelData.name] = checked
|
||||
AppThemeService.generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show message if no Discord clients detected
|
||||
NText {
|
||||
visible: ProgramCheckerService.availableDiscordClients.length === 0
|
||||
text: I18n.tr("settings.color-scheme.templates.programs.discord.description-missing")
|
||||
color: Color.mOnSurfaceVariant
|
||||
pointSize: Style.fontSizeS * scaling
|
||||
}
|
||||
|
||||
NCheckbox {
|
||||
|
||||
@@ -161,7 +161,8 @@ Singleton {
|
||||
|
||||
// Check if any Matugen templates are enabled
|
||||
function hasEnabledMatugenTemplates() {
|
||||
return Settings.data.templates.gtk || Settings.data.templates.qt || Settings.data.templates.kitty || Settings.data.templates.ghostty || Settings.data.templates.foot || Settings.data.templates.fuzzel || Settings.data.templates.vesktop || Settings.data.templates.pywalfox
|
||||
return Settings.data.templates.gtk || Settings.data.templates.qt || Settings.data.templates.kitty || Settings.data.templates.ghostty || Settings.data.templates.foot || Settings.data.templates.fuzzel || Settings.data.templates.discord || Settings.data.templates.discord_vesktop || Settings.data.templates.discord_webcord
|
||||
|| Settings.data.templates.discord_armcord || Settings.data.templates.discord_equibop || Settings.data.templates.discord_lightcord || Settings.data.templates.discord_dorion || Settings.data.templates.pywalfox
|
||||
}
|
||||
|
||||
// Writer to colors.json using a JsonAdapter for safety
|
||||
|
||||
@@ -69,65 +69,127 @@ Singleton {
|
||||
})
|
||||
}
|
||||
|
||||
// Applications configuration
|
||||
readonly property var applications: [{
|
||||
"name": "gtk",
|
||||
"templates": [{
|
||||
"version": "gtk3",
|
||||
"output": "~/.config/gtk-3.0/gtk.css"
|
||||
}, {
|
||||
"version": "gtk4",
|
||||
"output": "~/.config/gtk-4.0/gtk.css"
|
||||
}],
|
||||
"input": "gtk.css",
|
||||
"postHook": "gsettings set org.gnome.desktop.interface color-scheme prefer-{mode}"
|
||||
}, {
|
||||
"name": "qt",
|
||||
"templates": [{
|
||||
"version": "qt5",
|
||||
"output": "~/.config/qt5ct/colors/noctalia.conf"
|
||||
}, {
|
||||
"version": "qt6",
|
||||
"output": "~/.config/qt6ct/colors/noctalia.conf"
|
||||
}],
|
||||
"input": "qtct.conf"
|
||||
}, {
|
||||
"name": "fuzzel",
|
||||
"templates": [{
|
||||
"version": "fuzzel",
|
||||
"output": "~/.config/fuzzel/themes/noctalia"
|
||||
}],
|
||||
"input": "fuzzel.conf",
|
||||
"postHook": AppThemeService.colorsApplyScript + " fuzzel"
|
||||
}, {
|
||||
"name": "pywalfox",
|
||||
"templates": [{
|
||||
"version": "pywalfox",
|
||||
"output": "~/.cache/wal/colors.json"
|
||||
}],
|
||||
"input": "pywalfox.json",
|
||||
"postHook": AppThemeService.colorsApplyScript + " pywalfox"
|
||||
}, {
|
||||
"name": "discord_vesktop",
|
||||
"templates": [{
|
||||
"version": "discord_vesktop",
|
||||
"output": "~/.config/vesktop/themes/noctalia.theme.css"
|
||||
}],
|
||||
"input": "vesktop.css"
|
||||
}, {
|
||||
"name": "discord_webcord",
|
||||
"templates": [{
|
||||
"version": "discord_webcord",
|
||||
"output": "~/.config/webcord/themes/noctalia.theme.css"
|
||||
}],
|
||||
"input": "vesktop.css"
|
||||
}, {
|
||||
"name": "discord_armcord",
|
||||
"templates": [{
|
||||
"version": "discord_armcord",
|
||||
"output": "~/.config/armcord/themes/noctalia.theme.css"
|
||||
}],
|
||||
"input": "vesktop.css"
|
||||
}, {
|
||||
"name": "discord_equibop",
|
||||
"templates": [{
|
||||
"version": "discord_equibop",
|
||||
"output": "~/.config/equibop/themes/noctalia.theme.css"
|
||||
}],
|
||||
"input": "vesktop.css"
|
||||
}, {
|
||||
"name": "discord_lightcord",
|
||||
"templates": [{
|
||||
"version": "discord_lightcord",
|
||||
"output": "~/.config/lightcord/themes/noctalia.theme.css"
|
||||
}],
|
||||
"input": "vesktop.css"
|
||||
}, {
|
||||
"name": "discord_dorion",
|
||||
"templates": [{
|
||||
"version": "discord_dorion",
|
||||
"output": "~/.config/dorion/themes/noctalia.theme.css"
|
||||
}],
|
||||
"input": "vesktop.css"
|
||||
}]
|
||||
|
||||
// --------------------------------
|
||||
function addApplicationTemplates(lines, mode) {
|
||||
var applications = [{
|
||||
"name": "gtk",
|
||||
"templates": [{
|
||||
"version": "gtk3",
|
||||
"output": "~/.config/gtk-3.0/gtk.css"
|
||||
}, {
|
||||
"version": "gtk4",
|
||||
"output": "~/.config/gtk-4.0/gtk.css"
|
||||
}],
|
||||
"input": "gtk.css",
|
||||
"postHook": "gsettings set org.gnome.desktop.interface color-scheme prefer-" + mode
|
||||
}, {
|
||||
"name": "qt",
|
||||
"templates": [{
|
||||
"version": "qt5",
|
||||
"output": "~/.config/qt5ct/colors/noctalia.conf"
|
||||
}, {
|
||||
"version": "qt6",
|
||||
"output": "~/.config/qt6ct/colors/noctalia.conf"
|
||||
}],
|
||||
"input": "qtct.conf"
|
||||
}, {
|
||||
"name": "fuzzel",
|
||||
"templates": [{
|
||||
"version": "fuzzel",
|
||||
"output": "~/.config/fuzzel/themes/noctalia"
|
||||
}],
|
||||
"input": "fuzzel.conf",
|
||||
"postHook": AppThemeService.colorsApplyScript + " fuzzel"
|
||||
}, {
|
||||
"name": "pywalfox",
|
||||
"templates": [{
|
||||
"version": "pywalfox",
|
||||
"output": "~/.cache/wal/colors.json"
|
||||
}],
|
||||
"input": "pywalfox.json",
|
||||
"postHook": AppThemeService.colorsApplyScript + " pywalfox"
|
||||
}, {
|
||||
"name": "vesktop",
|
||||
"templates": [{
|
||||
"version": "vesktop",
|
||||
"output": "~/.config/vesktop/themes/noctalia.theme.css"
|
||||
}],
|
||||
"input": "vesktop.css"
|
||||
}]
|
||||
|
||||
applications.forEach(function (app) {
|
||||
if (Settings.data.templates[app.name]) {
|
||||
// Check if app has a condition and if it's met
|
||||
var shouldInclude = true
|
||||
if (app.condition !== undefined) {
|
||||
shouldInclude = app.condition
|
||||
}
|
||||
|
||||
if (Settings.data.templates[app.name] && shouldInclude) {
|
||||
app.templates.forEach(function (template) {
|
||||
lines.push("\n[templates." + template.version + "]")
|
||||
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/MatugenTemplates/' + app.input + '"')
|
||||
lines.push('output_path = "' + template.output + '"')
|
||||
if (app.postHook) {
|
||||
lines.push('post_hook = "' + app.postHook + '"')
|
||||
var postHook = app.postHook.replace("{mode}", mode)
|
||||
lines.push('post_hook = "' + postHook + '"')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Extract Discord clients from applications array
|
||||
readonly property var discordClients: {
|
||||
var clients = []
|
||||
for (var i = 0; i < applications.length; i++) {
|
||||
var app = applications[i]
|
||||
if (app.name && app.name.startsWith("discord_")) {
|
||||
var clientName = app.name.replace("discord_", "")
|
||||
var themePath = app.templates[0].output
|
||||
var configPath = themePath.replace("/themes/noctalia.theme.css", "")
|
||||
clients.push({
|
||||
"name": clientName,
|
||||
"configPath": configPath,
|
||||
"themePath": themePath
|
||||
})
|
||||
}
|
||||
}
|
||||
return clients
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,8 @@ Singleton {
|
||||
|
||||
if (title1) {
|
||||
for (var j = 0; j < genericPlayers.length; j++) {
|
||||
if (matchedGenericIndices[j]) continue
|
||||
if (matchedGenericIndices[j])
|
||||
continue
|
||||
let genericPlayer = genericPlayers[j]
|
||||
let title2 = String(genericPlayer.trackTitle || "").trim()
|
||||
|
||||
@@ -71,27 +72,29 @@ Singleton {
|
||||
|
||||
let scoreSpecific = (specificPlayer.trackArtUrl ? 1 : 0)
|
||||
let scoreGeneric = (genericPlayer.trackArtUrl ? 1 : 0)
|
||||
if(scoreSpecific > scoreGeneric){ dataPlayer = specificPlayer }
|
||||
if (scoreSpecific > scoreGeneric) {
|
||||
dataPlayer = specificPlayer
|
||||
}
|
||||
|
||||
let virtualPlayer = {
|
||||
identity: identityPlayer.identity,
|
||||
desktopEntry: identityPlayer.desktopEntry,
|
||||
trackTitle: dataPlayer.trackTitle,
|
||||
trackArtist: dataPlayer.trackArtist,
|
||||
trackAlbum: dataPlayer.trackAlbum,
|
||||
trackArtUrl: dataPlayer.trackArtUrl,
|
||||
length: dataPlayer.length || 0,
|
||||
position: dataPlayer.position || 0,
|
||||
playbackState: dataPlayer.playbackState,
|
||||
isPlaying: dataPlayer.isPlaying || false,
|
||||
canPlay: dataPlayer.canPlay || false,
|
||||
canPause: dataPlayer.canPause || false,
|
||||
canGoNext: dataPlayer.canGoNext || false,
|
||||
canGoPrevious: dataPlayer.canGoPrevious || false,
|
||||
canSeek: dataPlayer.canSeek || false,
|
||||
canControl: dataPlayer.canControl || false,
|
||||
_stateSource: dataPlayer,
|
||||
_controlTarget: identityPlayer
|
||||
"identity": identityPlayer.identity,
|
||||
"desktopEntry": identityPlayer.desktopEntry,
|
||||
"trackTitle": dataPlayer.trackTitle,
|
||||
"trackArtist": dataPlayer.trackArtist,
|
||||
"trackAlbum": dataPlayer.trackAlbum,
|
||||
"trackArtUrl": dataPlayer.trackArtUrl,
|
||||
"length": dataPlayer.length || 0,
|
||||
"position": dataPlayer.position || 0,
|
||||
"playbackState": dataPlayer.playbackState,
|
||||
"isPlaying": dataPlayer.isPlaying || false,
|
||||
"canPlay": dataPlayer.canPlay || false,
|
||||
"canPause": dataPlayer.canPause || false,
|
||||
"canGoNext": dataPlayer.canGoNext || false,
|
||||
"canGoPrevious": dataPlayer.canGoPrevious || false,
|
||||
"canSeek": dataPlayer.canSeek || false,
|
||||
"canControl": dataPlayer.canControl || false,
|
||||
"_stateSource": dataPlayer,
|
||||
"_controlTarget": identityPlayer
|
||||
}
|
||||
finalPlayers.push(virtualPlayer)
|
||||
matchedGenericIndices[j] = true
|
||||
|
||||
@@ -16,13 +16,67 @@ Singleton {
|
||||
property bool ghosttyAvailable: false
|
||||
property bool footAvailable: false
|
||||
property bool fuzzelAvailable: false
|
||||
property bool vesktopAvailable: false
|
||||
property bool gpuScreenRecorderAvailable: false
|
||||
property bool wlsunsetAvailable: false
|
||||
|
||||
// Discord client auto-detection
|
||||
property var availableDiscordClients: []
|
||||
|
||||
// Signal emitted when all checks are complete
|
||||
signal checksCompleted
|
||||
|
||||
// Function to detect Discord client by checking config directories
|
||||
function detectDiscordClient() {
|
||||
// Build list of client names from MatugenTemplates
|
||||
var clientNames = []
|
||||
for (var i = 0; i < MatugenTemplates.discordClients.length; i++) {
|
||||
clientNames.push(MatugenTemplates.discordClients[i].name)
|
||||
}
|
||||
|
||||
// Use a Process to check directory existence for all clients
|
||||
discordDetector.command = ["sh", "-c", "available_clients=\"\"; " + "for client in " + clientNames.join(" ") + "; do " + " if [ -d \"$HOME/.config/$client\" ]; then " + " available_clients=\"$available_clients $client\"; " + " fi; " + "done; " + "echo \"$available_clients\""]
|
||||
discordDetector.running = true
|
||||
}
|
||||
|
||||
// Process to detect Discord client directories
|
||||
Process {
|
||||
id: discordDetector
|
||||
running: false
|
||||
|
||||
onExited: function (exitCode) {
|
||||
availableDiscordClients = []
|
||||
|
||||
if (exitCode === 0) {
|
||||
var detectedClients = stdout.text.trim().split(/\s+/).filter(function (client) {
|
||||
return client.length > 0
|
||||
})
|
||||
|
||||
if (detectedClients.length > 0) {
|
||||
// Build list of available clients
|
||||
for (var i = 0; i < detectedClients.length; i++) {
|
||||
var clientName = detectedClients[i]
|
||||
for (var j = 0; j < MatugenTemplates.discordClients.length; j++) {
|
||||
var client = MatugenTemplates.discordClients[j]
|
||||
if (client.name === clientName) {
|
||||
availableDiscordClients.push(client)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.log("ProgramChecker", "Detected Discord clients:", detectedClients.join(", "))
|
||||
}
|
||||
}
|
||||
|
||||
if (availableDiscordClients.length === 0) {
|
||||
Logger.log("ProgramChecker", "No Discord clients detected")
|
||||
}
|
||||
}
|
||||
|
||||
stdout: StdioCollector {}
|
||||
stderr: StdioCollector {}
|
||||
}
|
||||
|
||||
// Programs to check - maps property names to commands
|
||||
readonly property var programsToCheck: ({
|
||||
"matugenAvailable": ["which", "matugen"],
|
||||
@@ -31,7 +85,6 @@ Singleton {
|
||||
"ghosttyAvailable": ["which", "ghostty"],
|
||||
"footAvailable": ["which", "foot"],
|
||||
"fuzzelAvailable": ["which", "fuzzel"],
|
||||
"vesktopAvailable": ["which", "vesktop"],
|
||||
"gpuScreenRecorderAvailable": ["sh", "-c", "command -v gpu-screen-recorder >/dev/null 2>&1 || (command -v flatpak >/dev/null 2>&1 && flatpak list --app | grep -q 'com.dec05eba.gpu_screen_recorder')"],
|
||||
"wlsunsetAvailable": ["which", "wlsunset"]
|
||||
})
|
||||
@@ -59,6 +112,8 @@ Singleton {
|
||||
|
||||
// Check next program or emit completion signal
|
||||
if (root.completedChecks >= root.totalChecks) {
|
||||
// Run Discord client detection after all checks are complete
|
||||
root.detectDiscordClient()
|
||||
root.checksCompleted()
|
||||
} else {
|
||||
root.checkNextProgram()
|
||||
@@ -113,6 +168,21 @@ Singleton {
|
||||
checker.running = true
|
||||
}
|
||||
|
||||
// Manual function to test Discord detection (for debugging)
|
||||
function testDiscordDetection() {
|
||||
Logger.log("ProgramChecker", "Testing Discord detection...")
|
||||
Logger.log("ProgramChecker", "HOME:", Quickshell.env("HOME"))
|
||||
|
||||
// Test each client directory
|
||||
for (var i = 0; i < MatugenTemplates.discordClients.length; i++) {
|
||||
var client = MatugenTemplates.discordClients[i]
|
||||
var configDir = client.configPath.replace("~", Quickshell.env("HOME"))
|
||||
Logger.log("ProgramChecker", "Checking:", configDir)
|
||||
}
|
||||
|
||||
detectDiscordClient()
|
||||
}
|
||||
|
||||
// Initialize checks when service is created
|
||||
Component.onCompleted: {
|
||||
checkAllPrograms()
|
||||
|
||||
Reference in New Issue
Block a user