From f79d9ce85204e78ce892299618ae0fdcd50aa2cc Mon Sep 17 00:00:00 2001 From: Aiser <2912778691@qq.com> Date: Tue, 25 Nov 2025 22:34:41 +0800 Subject: [PATCH 01/27] Programcheck: support flatpak for telegram --- Services/System/ProgramCheckerService.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Services/System/ProgramCheckerService.qml b/Services/System/ProgramCheckerService.qml index a4d2f71a..da49fbc8 100644 --- a/Services/System/ProgramCheckerService.qml +++ b/Services/System/ProgramCheckerService.qml @@ -184,7 +184,7 @@ Singleton { "codeAvailable": ["which", "code"], "gnomeCalendarAvailable": ["which", "gnome-calendar"], "spicetifyAvailable": ["which", "spicetify"], - "telegramAvailable": ["sh", "-c", "which telegram-desktop || which Telegram"], + "telegramAvailable": ["sh", "-c", "command -v telegram-desktop >/dev/null 2>&1 || command -v Telegram >/dev/null 2>&1 || (command -v flatpak >/dev/null 2>&1 && flatpak list --app | grep -q 'org.telegram.desktop')"], "cavaAvailable": ["which", "cava"] }) From 8277ce163139ff7f60b533a612143220196db0af Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Tue, 25 Nov 2025 18:15:57 +0100 Subject: [PATCH 02/27] IPCService: add state IPC call --- Assets/noctalia-shape.svg | 43 --------------------------------- Commons/Settings.qml | 26 ++++++++++++++++++++ Services/Control/IPCService.qml | 28 ++++++++++++++++++--- 3 files changed, 50 insertions(+), 47 deletions(-) delete mode 100644 Assets/noctalia-shape.svg diff --git a/Assets/noctalia-shape.svg b/Assets/noctalia-shape.svg deleted file mode 100644 index 631dabf5..00000000 --- a/Assets/noctalia-shape.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 0ec81bd3..2bbb1bae 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -5,6 +5,8 @@ import Quickshell import Quickshell.Io import "../Helpers/QtObj2JS.js" as QtObj2JS import qs.Commons +import qs.Services.Power +import qs.Services.System import qs.Services.UI Singleton { @@ -1143,4 +1145,28 @@ Singleton { const widgetAfter = JSON.stringify(widget); return (widgetAfter !== widgetBefore); } + + function buildStateSnapshot() { + try { + const settingsData = QtObj2JS.qtObjectToPlainObject(adapter); + const shellStateData = (typeof ShellState !== "undefined" && ShellState.data) ? QtObj2JS.qtObjectToPlainObject(ShellState.data) || {} : {}; + + return { + settings: settingsData, + state: { + doNotDisturb: NotificationService.doNotDisturb, + noctaliaPerformanceMode: PowerProfileService.noctaliaPerformanceMode, + barVisible: BarService.isVisible, + display: shellStateData.display || {}, + wallpapers: shellStateData.wallpapers || {}, + notificationsState: shellStateData.notificationsState || {}, + changelogState: shellStateData.changelogState || {}, + colorSchemesList: shellStateData.colorSchemesList || {} + } + }; + } catch (error) { + Logger.e("Settings", "Failed to build state snapshot:", error); + return null; + } + } } diff --git a/Services/Control/IPCService.qml b/Services/Control/IPCService.qml index 4b3a51b4..856311d3 100644 --- a/Services/Control/IPCService.qml +++ b/Services/Control/IPCService.qml @@ -96,7 +96,7 @@ Item { root.withTargetScreen(screen => { var launcherPanel = PanelService.getPanel("launcherPanel", screen); if (!launcherPanel?.windowActive || (launcherPanel?.windowActive && !launcherPanel?.activePlugin)) - launcherPanel?.toggle(); + launcherPanel?.toggle(); launcherPanel?.setSearchText(""); }); } @@ -104,7 +104,7 @@ Item { root.withTargetScreen(screen => { var launcherPanel = PanelService.getPanel("launcherPanel", screen); if (!launcherPanel?.windowActive || (launcherPanel?.windowActive && launcherPanel?.searchText.startsWith(">clip"))) - launcherPanel?.toggle(); + launcherPanel?.toggle(); launcherPanel?.setSearchText(">clip "); }); } @@ -112,7 +112,7 @@ Item { root.withTargetScreen(screen => { var launcherPanel = PanelService.getPanel("launcherPanel", screen); if (!launcherPanel?.windowActive || (launcherPanel?.windowActive && launcherPanel?.searchText.startsWith(">calc"))) - launcherPanel?.toggle(); + launcherPanel?.toggle(); launcherPanel?.setSearchText(">calc "); }); } @@ -120,7 +120,7 @@ Item { root.withTargetScreen(screen => { var launcherPanel = PanelService.getPanel("launcherPanel", screen); if (!launcherPanel?.windowActive || (launcherPanel?.windowActive && launcherPanel?.searchText.startsWith(">emoji"))) - launcherPanel?.toggle(); + launcherPanel?.toggle(); launcherPanel?.setSearchText(">emoji "); }); } @@ -380,6 +380,26 @@ Item { } } + IpcHandler { + target: "state" + + // Returns all settings and shell state as JSON + function all(): string { + try { + var snapshot = Settings.buildStateSnapshot(); + if (!snapshot) { + throw new Error("State snapshot unavailable"); + } + return JSON.stringify(snapshot, null, 2); + } catch (error) { + Logger.e("IPC", "Failed to serialize state:", error); + return JSON.stringify({ + "error": "Failed to serialize state: " + error + }, null, 2); + } + } + } + /** * For IPC calls on multi-monitors setup that will open panels on screen, * we need to open a QS PanelWindow and wait for it's "screen" property to stabilize. From 82c629278de15a6cf2bdf3a844937028109e77bd Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 15:11:57 -0500 Subject: [PATCH 03/27] Battery: removed unecessary property --- Modules/Panels/Battery/BatteryPanel.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/Panels/Battery/BatteryPanel.qml b/Modules/Panels/Battery/BatteryPanel.qml index dcac2cbd..74f15517 100644 --- a/Modules/Panels/Battery/BatteryPanel.qml +++ b/Modules/Panels/Battery/BatteryPanel.qml @@ -19,8 +19,7 @@ SmartPanel { readonly property bool isReady: battery && battery.ready && battery.isLaptopBattery && battery.isPresent readonly property int percent: isReady ? Math.round(battery.percentage * 100) : -1 readonly property bool charging: isReady ? battery.state === UPowerDeviceState.Charging : false - readonly property bool healthSupported: isReady && battery.healthSupported - readonly property bool healthAvailable: healthSupported + readonly property bool healthAvailable: isReady && battery.healthSupported readonly property int healthPercent: healthAvailable ? Math.round(battery.healthPercentage) : -1 readonly property bool powerProfileAvailable: PowerProfileService.available readonly property var powerProfiles: [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance] From 764acef4e765ace2212048869850474cb9d970a9 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 15:20:30 -0500 Subject: [PATCH 04/27] settings-defaul --- Assets/settings-default.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Assets/settings-default.json b/Assets/settings-default.json index ec5773a1..0cc60a46 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -280,7 +280,12 @@ }, "osd": { "enabled": true, - "enabledTypes": [0, 1, 2, 3], + "enabledTypes": [ + 0, + 1, + 2, + 3 + ], "location": "top_right", "monitors": [], "autoHideMs": 2000, From a35123918c6200df178aa1bf242818fdbc208024 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 15:20:51 -0500 Subject: [PATCH 05/27] Battery Panel: Charge Level => Battery Level --- Assets/Translations/de.json | 52 ++++++++++++------------- Assets/Translations/en.json | 44 ++++++++++----------- Assets/Translations/es.json | 52 ++++++++++++------------- Assets/Translations/fr.json | 52 ++++++++++++------------- Assets/Translations/nl.json | 52 ++++++++++++------------- Assets/Translations/pt.json | 52 ++++++++++++------------- Assets/Translations/ru.json | 52 ++++++++++++------------- Assets/Translations/tr.json | 52 ++++++++++++------------- Assets/Translations/uk-UA.json | 52 ++++++++++++------------- Assets/Translations/zh-CN.json | 52 ++++++++++++------------- Modules/Panels/Battery/BatteryPanel.qml | 2 +- 11 files changed, 239 insertions(+), 275 deletions(-) diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index 31aa467a..321bf3e0 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -227,14 +227,14 @@ "description": "Künstler - Titel anstatt Titel - Künstler anzeigen.", "label": "Künstler zuerst anzeigen" }, - "show-visualizer": { - "description": "Audio-Visualizer anzeigen, wenn Musik abgespielt wird.", - "label": "Visualizer anzeigen" - }, "show-progress-ring": { "description": "Runden Fortschrittsindikator anzeigen, der den Titelfortschritt anzeigt.", "label": "Fortschrittsring anzeigen" }, + "show-visualizer": { + "description": "Audio-Visualizer anzeigen, wenn Musik abgespielt wird.", + "label": "Visualizer anzeigen" + }, "use-fixed-width": { "description": "Wenn aktiviert, verwendet das Widget immer die maximale Breite, anstatt sich dynamisch an den Inhalt anzupassen.", "label": "Feste Breite verwenden" @@ -373,14 +373,14 @@ "description": "Anzahl der Zeichen, die von Arbeitsbereichsnamen angezeigt werden (1-10).", "label": "Zeichenanzahl" }, - "hide-unoccupied": { - "description": "Arbeitsbereiche ohne Fenster nicht anzeigen.", - "label": "Unbesetzte ausblenden" - }, "follow-focused-screen": { "description": "Zeigt Arbeitsbereiche vom aktuell fokussierten Bildschirm an, statt vom Bildschirm, auf dem sich die Leiste befindet.", "label": "Fokussiertem Bildschirm folgen" }, + "hide-unoccupied": { + "description": "Arbeitsbereiche ohne Fenster nicht anzeigen.", + "label": "Unbesetzte ausblenden" + }, "label-mode": { "description": "Wählen Sie, wie Arbeitsbereichs-Beschriftungen angezeigt werden.", "label": "Beschriftungsmodus" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "Akkustand", "brightness": "Helligkeit", - "charge-level": "Ladestand", "charging": "Wird geladen.", "charging-rate": "Laderate: {rate} W.", "discharging": "Wird entladen.", @@ -519,13 +519,13 @@ "title": "Benachrichtigungen" }, "time": { - "now": "jetzt", - "diffM": "vor 1 Minute", - "diffMM": "vor {diff} Minuten", + "diffD": "vor 1 Tag", + "diffDD": "vor {diff} Tagen", "diffH": "vor 1 Stunde", "diffHH": "vor {diff} Stunden", - "diffD": "vor 1 Tag", - "diffDD": "vor {diff} Tagen" + "diffM": "vor 1 Minute", + "diffMM": "vor {diff} Minuten", + "now": "jetzt" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "Schreibe {filepath}.", + "description-missing": "Benötigt die Installation von {app}" + }, "code": { "description": "Schreibe {Dateipfad}. Das Hyprluna-Theme muss manuell installiert und aktiviert werden", "description-missing": "Kein Code-Client erkannt. Installieren Sie VSCode oder VSCodium." @@ -1075,10 +1079,6 @@ "description": "Schreibe {filepath}.", "description-missing": "Benötigt die Installation von {app}" }, - "cava": { - "description": "Schreibe {filepath}.", - "description-missing": "Benötigt die Installation von {app}" - }, "vicinae": { "description": "Schreibt {filepath} und lädt neu", "description-missing": "Erfordert die Installation von {app}" @@ -1446,14 +1446,14 @@ "description": "Verwenden Sie ein benutzerdefiniertes Präfix zum Starten von Anwendungen anstelle der Standardmethode.", "label": "Benutzerdefiniertes Start-Präfix aktivieren" }, - "position": { - "description": "Wählen Sie, wo das Starter-Panel erscheint.", - "label": "Position" - }, "grid-view": { "description": "Elemente in einem Raster statt in einer Liste anzeigen.", "label": "Rasteransicht" }, + "position": { + "description": "Wählen Sie, wo das Starter-Panel erscheint.", + "label": "Position" + }, "section": { "description": "Verhalten und Erscheinungsbild des Starters anpassen.", "label": "Erscheinungsbild" @@ -1675,6 +1675,7 @@ "label": "Allgemein" } }, + "title": "On-Screen Display", "types": { "brightness": { "description": "OSD anzeigen, wenn sich die Bildschirmhelligkeit ändert.", @@ -1696,12 +1697,7 @@ "description": "OSD anzeigen, wenn sich die Ausgabelautstärke ändert.", "label": "Ausgangslautstärke" } - }, - "show-lock-key-notifications": { - "description": "Benachrichtigungen anzeigen, wenn sich der Status von Feststelltaste, Num-Taste oder Rollen-Taste ändert.", - "label": "Tastensperr-Benachrichtigungen anzeigen" - }, - "title": "On-Screen Display" + } }, "screen-recorder": { "audio": { diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 7f14d91b..f9df474c 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -227,14 +227,14 @@ "description": "Display artist - title instead of title - artist.", "label": "Show artist first" }, - "show-visualizer": { - "description": "Display an audio visualizer when music is playing.", - "label": "Show visualizer" - }, "show-progress-ring": { "description": "Display a circular progress indicator showing track progress.", "label": "Show progress ring" }, + "show-visualizer": { + "description": "Display an audio visualizer when music is playing.", + "label": "Show visualizer" + }, "use-fixed-width": { "description": "When enabled, the widget will always use the maximum width instead of dynamically adjusting to content.", "label": "Use Fixed Width" @@ -373,14 +373,14 @@ "description": "Number of characters to display from workspace names (1-10).", "label": "Character count" }, - "hide-unoccupied": { - "description": "Don't display workspaces without windows.", - "label": "Hide unoccupied" - }, "follow-focused-screen": { "description": "Display workspaces from the currently focused screen, rather than the screen where the bar is located.", "label": "Follow Focused Screen" }, + "hide-unoccupied": { + "description": "Don't display workspaces without windows.", + "label": "Hide unoccupied" + }, "label-mode": { "description": "Choose how workspace labels are displayed.", "label": "Label Mode" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "Battery level", "brightness": "Brightness", - "charge-level": "Charge level", "charging": "Charging", "charging-rate": "Charging rate: {rate} W", "discharging": "Discharging", @@ -519,13 +519,13 @@ "title": "Notifications" }, "time": { - "now": "now", - "diffM": "1 minute ago", - "diffMM": "{diff} minutes ago", + "diffD": "1 day ago", + "diffDD": "{diff} days ago", "diffH": "1 hour ago", "diffHH": "{diff} hours ago", - "diffD": "1 day ago", - "diffDD": "{diff} days ago" + "diffM": "1 minute ago", + "diffMM": "{diff} minutes ago", + "now": "now" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "Write {filepath}.", + "description-missing": "Requires {app} to be installed" + }, "code": { "description": "Write {filepath}. Hyprluna theme needs to be installed and activated manually.", "description-missing": "No Code client detected. Install VSCode or VSCodium." @@ -1075,10 +1079,6 @@ "description": "Write {filepath}.", "description-missing": "Requires {app} to be installed" }, - "cava": { - "description": "Write {filepath}.", - "description-missing": "Requires {app} to be installed" - }, "vicinae": { "description": "Write {filepath} and reload", "description-missing": "Requires {app} to be installed" @@ -1446,14 +1446,14 @@ "description": "Use a custom prefix for launching applications instead of the default method.", "label": "Enable custom launch prefix" }, - "position": { - "description": "Choose where the launcher panel appears.", - "label": "Position" - }, "grid-view": { "description": "Display items in a grid layout instead of a list.", "label": "Grid view" }, + "position": { + "description": "Choose where the launcher panel appears.", + "label": "Position" + }, "section": { "description": "Customize the launcher's behavior and appearance.", "label": "Appearance" diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 1ec9b651..95ed6b87 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -227,14 +227,14 @@ "description": "Mostrar artista - título en lugar de título - artista.", "label": "Mostrar primero al artista" }, - "show-visualizer": { - "description": "Mostrar un visualizador de audio cuando se reproduce música.", - "label": "Mostrar visualizador" - }, "show-progress-ring": { "description": "Mostrar un indicador de progreso circular que muestre el progreso de la pista.", "label": "Mostrar anillo de progreso" }, + "show-visualizer": { + "description": "Mostrar un visualizador de audio cuando se reproduce música.", + "label": "Mostrar visualizador" + }, "use-fixed-width": { "description": "Cuando está activado, el widget siempre usará el ancho máximo en lugar de ajustarse dinámicamente al contenido.", "label": "Usar Ancho Fijo" @@ -373,14 +373,14 @@ "description": "Número de caracteres a mostrar de los nombres de espacios de trabajo (1-10).", "label": "Número de caracteres" }, - "hide-unoccupied": { - "description": "No mostrar espacios de trabajo sin ventanas.", - "label": "Ocultar desocupados" - }, "follow-focused-screen": { "description": "Mostrar espacios de trabajo de la pantalla actualmente enfocada, en lugar de la pantalla donde se encuentra la barra.", "label": "Seguir Pantalla Enfocada" }, + "hide-unoccupied": { + "description": "No mostrar espacios de trabajo sin ventanas.", + "label": "Ocultar desocupados" + }, "label-mode": { "description": "Elegir cómo se muestran las etiquetas de los espacios de trabajo.", "label": "Modo de etiqueta" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "Nivel de batería", "brightness": "Brillo", - "charge-level": "Nivel de carga", "charging": "Cargando.", "charging-rate": "Tasa de carga: {rate} W.", "discharging": "Descargando.", @@ -519,13 +519,13 @@ "title": "Notificaciones" }, "time": { - "now": "ahora", - "diffM": "hace 1 minuto", - "diffMM": "hace {diff} minutos", + "diffD": "hace 1 día", + "diffDD": "hace {diff} días", "diffH": "hace 1 hora", "diffHH": "hace {diff} horas", - "diffD": "hace 1 día", - "diffDD": "hace {diff} días" + "diffM": "hace 1 minuto", + "diffMM": "hace {diff} minutos", + "now": "ahora" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "Escribe {filepath}.", + "description-missing": "Requiere que {app} esté instalado/a." + }, "code": { "description": "Escribe {filepath}. El tema Hyprluna debe ser instalado y activado manualmente.", "description-missing": "No se detectó cliente de Code. Instala VSCode o VSCodium." @@ -1075,10 +1079,6 @@ "description": "Escribe {filepath}.", "description-missing": "Requiere que {app} esté instalado/a." }, - "cava": { - "description": "Escribe {filepath}.", - "description-missing": "Requiere que {app} esté instalado/a." - }, "vicinae": { "description": "Escribir {filepath} y recargar", "description-missing": "Requiere que {app} esté instalado" @@ -1446,14 +1446,14 @@ "description": "Usar un prefijo personalizado para lanzar aplicaciones en lugar del método predeterminado.", "label": "Habilitar prefijo de lanzamiento personalizado" }, - "position": { - "description": "Elige dónde aparece el panel del lanzador.", - "label": "Posición" - }, "grid-view": { "description": "Mostrar elementos en una cuadrícula en lugar de una lista.", "label": "Vista de cuadrícula" }, + "position": { + "description": "Elige dónde aparece el panel del lanzador.", + "label": "Posición" + }, "section": { "description": "Personaliza el comportamiento y la apariencia del lanzador.", "label": "Apariencia" @@ -1675,6 +1675,7 @@ "label": "General" } }, + "title": "Visualización en pantalla", "types": { "brightness": { "description": "Mostrar el OSD cuando cambie el brillo de la pantalla.", @@ -1696,12 +1697,7 @@ "description": "Mostrar el OSD cuando cambie el volumen de salida de audio.", "label": "Volumen de salida" } - }, - "show-lock-key-notifications": { - "description": "Mostrar notificaciones cuando se activen o desactiven las teclas Bloq Mayús, Bloq Num o Bloq Despl.", - "label": "Mostrar notificaciones de teclas de bloqueo" - }, - "title": "Visualización en pantalla" + } }, "screen-recorder": { "audio": { diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 763e8094..8a366f98 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -227,14 +227,14 @@ "description": "Afficher artiste - titre au lieu de titre - artiste.", "label": "Afficher l'artiste en premier" }, - "show-visualizer": { - "description": "Afficher un visualiseur audio quand la musique est en cours de lecture.", - "label": "Afficher le visualiseur" - }, "show-progress-ring": { "description": "Afficher un indicateur de progression circulaire montrant la progression de la piste.", "label": "Afficher l'anneau de progression" }, + "show-visualizer": { + "description": "Afficher un visualiseur audio quand la musique est en cours de lecture.", + "label": "Afficher le visualiseur" + }, "use-fixed-width": { "description": "Lorsque activé, le widget utilisera toujours la largeur maximale au lieu de s'ajuster dynamiquement au contenu.", "label": "Utiliser une Largeur Fixe" @@ -373,14 +373,14 @@ "description": "Nombre de caractères à afficher des noms d'espaces de travail (1-10).", "label": "Nombre de caractères" }, - "hide-unoccupied": { - "description": "Ne pas afficher les espaces de travail sans fenêtres.", - "label": "Masquer les inoccupés" - }, "follow-focused-screen": { "description": "Afficher les espaces de travail de l'écran actuellement ciblé, plutôt que de l'écran où se trouve la barre.", "label": "Suivre l'Écran Ciblé" }, + "hide-unoccupied": { + "description": "Ne pas afficher les espaces de travail sans fenêtres.", + "label": "Masquer les inoccupés" + }, "label-mode": { "description": "Choisir comment les étiquettes d'espace de travail sont affichées.", "label": "Mode d'étiquette" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "Niveau de batterie", "brightness": "Luminosité", - "charge-level": "Niveau de charge", "charging": "En charge.", "charging-rate": "Taux de charge : {rate} W.", "discharging": "En décharge.", @@ -519,13 +519,13 @@ "title": "Notifications" }, "time": { - "now": "maintenant", - "diffM": "il y a 1 minute", - "diffMM": "il y a {diff} minutes", + "diffD": "il y a 1 jour", + "diffDD": "il y a {diff} jours", "diffH": "il y a 1 heure", "diffHH": "il y a {diff} heures", - "diffD": "il y a 1 jour", - "diffDD": "il y a {diff} jours" + "diffM": "il y a 1 minute", + "diffMM": "il y a {diff} minutes", + "now": "maintenant" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "Écrire {filepath}.", + "description-missing": "Nécessite l'installation de {app}" + }, "code": { "description": "Écrire {filepath}. Le thème Hyprluna doit être installé et activé manuellement.", "description-missing": "Aucun client Code détecté. Installez VSCode ou VSCodium." @@ -1075,10 +1079,6 @@ "description": "Écrire {filepath}.", "description-missing": "Nécessite l'installation de {app}" }, - "cava": { - "description": "Écrire {filepath}.", - "description-missing": "Nécessite l'installation de {app}" - }, "vicinae": { "description": "Écrire {filepath} et recharger", "description-missing": "Nécessite que le lanceur {app} soit installé" @@ -1446,14 +1446,14 @@ "description": "Utiliser un préfixe personnalisé pour lancer les applications au lieu de la méthode par défaut.", "label": "Activer le préfixe de lancement personnalisé" }, - "position": { - "description": "Choisissez où le panneau du lanceur apparaît.", - "label": "Position" - }, "grid-view": { "description": "Afficher les éléments dans une grille au lieu d'une liste.", "label": "Vue grille" }, + "position": { + "description": "Choisissez où le panneau du lanceur apparaît.", + "label": "Position" + }, "section": { "description": "Personnalisez le comportement et l'apparence du lanceur.", "label": "Apparence" @@ -1675,6 +1675,7 @@ "label": "Général" } }, + "title": "Affichage à l'écran", "types": { "brightness": { "description": "Afficher l'OSD lorsque la luminosité de l'écran change.", @@ -1696,12 +1697,7 @@ "description": "Afficher l'OSD lorsque le volume de sortie audio change.", "label": "Volume de sortie" } - }, - "show-lock-key-notifications": { - "description": "Afficher les notifications lorsque les touches Verr. Maj., Verr. Num. ou Arrêt défil. sont activées/désactivées.", - "label": "Afficher les notifications des touches de verrouillage" - }, - "title": "Affichage à l'écran" + } }, "screen-recorder": { "audio": { diff --git a/Assets/Translations/nl.json b/Assets/Translations/nl.json index 8927d2f5..c73c4978 100644 --- a/Assets/Translations/nl.json +++ b/Assets/Translations/nl.json @@ -227,14 +227,14 @@ "description": "Toon artiest - titel in plaats van titel - artiest.", "label": "Toon eerst de artiest" }, - "show-visualizer": { - "description": "Toon een audiovisualizer wanneer muziek wordt afgespeeld.", - "label": "Visualizer tonen" - }, "show-progress-ring": { "description": "Toon een circulaire voortgangsindicator die het bestandsspoor voortgang toont.", "label": "Voortgangscirkel tonen" }, + "show-visualizer": { + "description": "Toon een audiovisualizer wanneer muziek wordt afgespeeld.", + "label": "Visualizer tonen" + }, "use-fixed-width": { "description": "Indien ingeschakeld gebruikt de widget altijd de maximale breedte in plaats van zich aan te passen aan de inhoud.", "label": "Vaste breedte gebruiken" @@ -373,14 +373,14 @@ "description": "Aantal tekens dat wordt weergegeven van werkruimtenamen (1-10).", "label": "Aantal tekens" }, - "hide-unoccupied": { - "description": "Werkruimten zonder vensters niet weergeven.", - "label": "Ongebruikte verbergen" - }, "follow-focused-screen": { "description": "Werkruimten weergeven van het momenteel gefocuste scherm, in plaats van het scherm waar de balk zich bevindt.", "label": "Gefocust Scherm Volgen" }, + "hide-unoccupied": { + "description": "Werkruimten zonder vensters niet weergeven.", + "label": "Ongebruikte verbergen" + }, "label-mode": { "description": "Kies hoe labels van werkruimten worden weergegeven.", "label": "Labelmodus" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "Batterijniveau", "brightness": "Helderheid", - "charge-level": "Laadniveau", "charging": "Opladen.", "charging-rate": "Laadsnelheid: {rate} W.", "discharging": "Ontladen.", @@ -519,13 +519,13 @@ "title": "Meldingen" }, "time": { - "now": "nu", - "diffM": "1 minuut geleden", - "diffMM": "{diff} minuten geleden", + "diffD": "1 dag geleden", + "diffDD": "{diff} dagen geleden", "diffH": "1 uur geleden", "diffHH": "{diff} uur geleden", - "diffD": "1 dag geleden", - "diffDD": "{diff} dagen geleden" + "diffM": "1 minuut geleden", + "diffMM": "{diff} minuten geleden", + "now": "nu" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "Schrijf {filepath}.", + "description-missing": "Vereist dat {app} is geïnstalleerd." + }, "code": { "description": "Schrijf {filepath}. Het Hyprluna-thema moet handmatig worden geïnstalleerd en geactiveerd.", "description-missing": "Geen Code-client gedetecteerd. Installeer VSCode of VSCodium." @@ -1075,10 +1079,6 @@ "description": "Schrijf {filepath}.", "description-missing": "Vereist dat {app} is geïnstalleerd." }, - "cava": { - "description": "Schrijf {filepath}.", - "description-missing": "Vereist dat {app} is geïnstalleerd." - }, "vicinae": { "description": "Schrijf {filepath} en herlaad.", "description-missing": "Vereist dat {app} is geïnstalleerd." @@ -1446,14 +1446,14 @@ "description": "Gebruik een aangepaste prefix om applicaties te starten in plaats van de standaardmethode.", "label": "Aangepaste startprefix inschakelen" }, - "position": { - "description": "Kies waar het launcher-paneel verschijnt.", - "label": "Positie" - }, "grid-view": { "description": "Items in een raster weergeven in plaats van een lijst.", "label": "Rasterweergave" }, + "position": { + "description": "Kies waar het launcher-paneel verschijnt.", + "label": "Positie" + }, "section": { "description": "Pas het gedrag en uiterlijk van de launcher aan.", "label": "Uiterlijk" @@ -1675,6 +1675,7 @@ "label": "Algemeen" } }, + "title": "On-screenweergave", "types": { "brightness": { "description": "Toon het OSD wanneer de schermhelderheid verandert.", @@ -1696,12 +1697,7 @@ "description": "Toon het OSD wanneer het uitvoervolume verandert.", "label": "Uitvoervolume" } - }, - "show-lock-key-notifications": { - "description": "Toon meldingen wanneer Caps Lock, Num Lock of Scroll Lock toetsen worden omgeschakeld.", - "label": "Vergrendeltoetsmeldingen tonen" - }, - "title": "On-screenweergave" + } }, "screen-recorder": { "audio": { diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index 02b449e6..540a9534 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -227,14 +227,14 @@ "description": "Exibir artista - título em vez de título - artista.", "label": "Mostrar o artista primeiro" }, - "show-visualizer": { - "description": "Exibir um visualizador de áudio quando música está sendo reproduzida.", - "label": "Mostrar visualizador" - }, "show-progress-ring": { "description": "Exibir um indicador de progresso circular mostrando o progresso da faixa.", "label": "Mostrar anel de progresso" }, + "show-visualizer": { + "description": "Exibir um visualizador de áudio quando música está sendo reproduzida.", + "label": "Mostrar visualizador" + }, "use-fixed-width": { "description": "Quando ativado, o widget sempre usará a largura máxima em vez de ajustar dinamicamente ao conteúdo.", "label": "Usar Largura Fixa" @@ -373,14 +373,14 @@ "description": "Número de caracteres a exibir dos nomes de espaços de trabalho (1-10).", "label": "Número de caracteres" }, - "hide-unoccupied": { - "description": "Não exibir áreas de trabalho sem janelas.", - "label": "Ocultar desocupados" - }, "follow-focused-screen": { "description": "Exibir áreas de trabalho da tela atualmente em foco, em vez da tela onde a barra está localizada.", "label": "Seguir Tela em Foco" }, + "hide-unoccupied": { + "description": "Não exibir áreas de trabalho sem janelas.", + "label": "Ocultar desocupados" + }, "label-mode": { "description": "Escolher como os rótulos de espaço de trabalho são exibidos.", "label": "Modo de rótulo" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "Nível da bateria", "brightness": "Brilho", - "charge-level": "Nível de carga", "charging": "Carregando.", "charging-rate": "Taxa de carregamento: {rate} W.", "discharging": "Descarregando.", @@ -519,13 +519,13 @@ "title": "Notificações" }, "time": { - "now": "agora", - "diffM": "há 1 minuto", - "diffMM": "há {diff} minutos", + "diffD": "há 1 dia", + "diffDD": "há {diff} dias", "diffH": "há 1 hora", "diffHH": "há {diff} horas", - "diffD": "há 1 dia", - "diffDD": "há {diff} dias" + "diffM": "há 1 minuto", + "diffMM": "há {diff} minutos", + "now": "agora" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "Escreva em {filepath}.", + "description-missing": "Requer que o {app} esteja instalado." + }, "code": { "description": "Escreva em {filepath}. O tema Hyprluna precisa ser instalado e ativado manualmente.", "description-missing": "Nenhum cliente Code detectado. Instale VSCode ou VSCodium." @@ -1075,10 +1079,6 @@ "description": "Escreva em {filepath}.", "description-missing": "Requer que o {app} esteja instalado." }, - "cava": { - "description": "Escreva em {filepath}.", - "description-missing": "Requer que o {app} esteja instalado." - }, "vicinae": { "description": "Escrever {filepath} e recarregar", "description-missing": "Requer que o {app} esteja instalado" @@ -1446,14 +1446,14 @@ "description": "Usar um prefixo personalizado para inicializar aplicativos em vez do método padrão.", "label": "Habilitar prefixo de inicialização personalizado" }, - "position": { - "description": "Escolha onde o painel do lançador aparece.", - "label": "Posição" - }, "grid-view": { "description": "Exibir itens em uma grade em vez de uma lista.", "label": "Visualização em grade" }, + "position": { + "description": "Escolha onde o painel do lançador aparece.", + "label": "Posição" + }, "section": { "description": "Personalize o comportamento e a aparência do lançador.", "label": "Aparência" @@ -1675,6 +1675,7 @@ "label": "Geral" } }, + "title": "Exibição na tela", "types": { "brightness": { "description": "Mostrar o OSD quando o brilho da tela mudar.", @@ -1696,12 +1697,7 @@ "description": "Mostrar o OSD quando o volume de saída de áudio mudar.", "label": "Volume de saída" } - }, - "show-lock-key-notifications": { - "description": "Mostrar notificações quando as teclas Caps Lock, Num Lock ou Scroll Lock forem alternadas.", - "label": "Mostrar notificações das teclas de bloqueio" - }, - "title": "Exibição na tela" + } }, "screen-recorder": { "audio": { diff --git a/Assets/Translations/ru.json b/Assets/Translations/ru.json index 9fa89468..f361e5a5 100644 --- a/Assets/Translations/ru.json +++ b/Assets/Translations/ru.json @@ -227,14 +227,14 @@ "description": "Исполнитель - название вместо название - исполнитель.", "label": "Сначала исполнитель" }, - "show-visualizer": { - "description": "Отображать аудиовизуализатор при воспроизведении музыки.", - "label": "Показывать визуализатор" - }, "show-progress-ring": { "description": "Отображать круговой индикатор прогресса воспроизведения трека.", "label": "Показывать кольцо прогресса" }, + "show-visualizer": { + "description": "Отображать аудиовизуализатор при воспроизведении музыки.", + "label": "Показывать визуализатор" + }, "use-fixed-width": { "description": "Если включено, виджет всегда будет использовать максимальную ширину вместо динамической подстройки под содержимое.", "label": "Использовать фиксированную ширину" @@ -373,14 +373,14 @@ "description": "Количество символов для отображения из имен рабочих пространств (1-10).", "label": "Количество символов" }, - "hide-unoccupied": { - "description": "Не отображать рабочие пространства без окон.", - "label": "Скрыть незанятые" - }, "follow-focused-screen": { "description": "Отображать рабочие пространства с текущего активного экрана, а не с экрана, на котором расположена панель.", "label": "Следовать за Активным Экраном" }, + "hide-unoccupied": { + "description": "Не отображать рабочие пространства без окон.", + "label": "Скрыть незанятые" + }, "label-mode": { "description": "Выберите, как отображаются метки рабочих пространств.", "label": "Режим метки" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "Уровень заряда батареи", "brightness": "Яркость", - "charge-level": "Уровень заряда", "charging": "Зарядка.", "charging-rate": "Скорость зарядки: {rate} Вт.", "discharging": "Разрядка.", @@ -519,13 +519,13 @@ "title": "Уведомления" }, "time": { - "now": "сейчас", - "diffM": "1 минуту назад", - "diffMM": "{diff} минут назад", + "diffD": "1 день назад", + "diffDD": "{diff} дней назад", "diffH": "1 час назад", "diffHH": "{diff} часов назад", - "diffD": "1 день назад", - "diffDD": "{diff} дней назад" + "diffM": "1 минуту назад", + "diffMM": "{diff} минут назад", + "now": "сейчас" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "Записать {filepath}.", + "description-missing": "Требуется установка {app}" + }, "code": { "description": "Записать {filepath}. Тему Hyprluna нужно установить и активировать вручную.", "description-missing": "Клиент Code не обнаружен. Установите VSCode или VSCodium." @@ -1075,10 +1079,6 @@ "description": "Записать {filepath}.", "description-missing": "Требуется установка {app}" }, - "cava": { - "description": "Записать {filepath}.", - "description-missing": "Требуется установка {app}" - }, "vicinae": { "description": "Записать {filepath} и перезагрузить", "description-missing": "Требуется установка {app}" @@ -1446,14 +1446,14 @@ "description": "Использовать пользовательский префикс для запуска приложений вместо метода по умолчанию.", "label": "Включить пользовательский префикс запуска" }, - "position": { - "description": "Выберите, где появляется панель запуска.", - "label": "Положение" - }, "grid-view": { "description": "Показывать элементы в виде сетки вместо списка.", "label": "Вид сетки" }, + "position": { + "description": "Выберите, где появляется панель запуска.", + "label": "Положение" + }, "section": { "description": "Настройка поведения и внешнего вида запуска.", "label": "Внешний вид" @@ -1675,6 +1675,7 @@ "label": "Общие" } }, + "title": "Экранное отображение (OSD)", "types": { "brightness": { "description": "Показывать OSD при изменении яркости экрана.", @@ -1696,12 +1697,7 @@ "description": "Показывать OSD при изменении громкости аудиовыхода.", "label": "Выходная громкость" } - }, - "show-lock-key-notifications": { - "description": "Показывать уведомления при переключении клавиш Caps Lock, Num Lock или Scroll Lock.", - "label": "Показывать уведомления о состоянии клавиш" - }, - "title": "Экранное отображение (OSD)" + } }, "screen-recorder": { "audio": { diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json index 7ffcc692..53e9b477 100644 --- a/Assets/Translations/tr.json +++ b/Assets/Translations/tr.json @@ -227,14 +227,14 @@ "description": "Sanatçı - başlık yerine başlık - sanatçı olarak göster.", "label": "Önce sanatçıyı göster" }, - "show-visualizer": { - "description": "Müzik çalarken bir ses görselleştirici göster.", - "label": "Görselleştiriciyi göster" - }, "show-progress-ring": { "description": "Parça ilerlemesini gösteren dairesel bir ilerleme göstergesi gösterin.", "label": "İlerleme halkası göster" }, + "show-visualizer": { + "description": "Müzik çalarken bir ses görselleştirici göster.", + "label": "Görselleştiriciyi göster" + }, "use-fixed-width": { "description": "Etkinleştirildiğinde, widget dinamik olarak içerik göre ayarlamak yerine her zaman maksimum genişliği kullanır.", "label": "Sabit Genişlik Kullan" @@ -373,14 +373,14 @@ "description": "Çalışma alanı adlarından gösterilecek karakter sayısı (1-10).", "label": "Karakter sayısı" }, - "hide-unoccupied": { - "description": "Penceresi olmayan çalışma alanlarını gösterme.", - "label": "Dolu olmayanları gizle" - }, "follow-focused-screen": { "description": "Çubuğun bulunduğu ekran yerine, şu anda odaklanmış ekrandaki çalışma alanlarını göster.", "label": "Odaklanmış Ekranı Takip Et" }, + "hide-unoccupied": { + "description": "Penceresi olmayan çalışma alanlarını gösterme.", + "label": "Dolu olmayanları gizle" + }, "label-mode": { "description": "Çalışma alanı etiketlerinin nasıl gösterileceğini seçin.", "label": "Etiket Modu" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "Pil seviyesi", "brightness": "Parlaklık", - "charge-level": "Şarj seviyesi", "charging": "Şarj oluyor.", "charging-rate": "Şarj oranı: {rate} W.", "discharging": "Deşarj oluyor.", @@ -519,13 +519,13 @@ "title": "Bildirimler" }, "time": { - "now": "şimdi", - "diffM": "1 dakika önce", - "diffMM": "{diff} dakika önce", + "diffD": "1 gün önce", + "diffDD": "{diff} gün önce", "diffH": "1 saat önce", "diffHH": "{diff} saat önce", - "diffD": "1 gün önce", - "diffDD": "{diff} gün önce" + "diffM": "1 dakika önce", + "diffMM": "{diff} dakika önce", + "now": "şimdi" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "{filepath} dosyasına yaz.", + "description-missing": "Kurulum için {app} gereklidir" + }, "code": { "description": "{filepath} dosyasına yaz. Hyprluna temasının kurulu ve manuel olarak etkinleştirilmiş olması gerekir.", "description-missing": "Code istemcisi tespit edilmedi. VSCode veya VSCodium kurun." @@ -1075,10 +1079,6 @@ "description": "{filepath} dosyasına yaz.", "description-missing": "Kurulum için {app} gereklidir" }, - "cava": { - "description": "{filepath} dosyasına yaz.", - "description-missing": "Kurulum için {app} gereklidir" - }, "vicinae": { "description": "{filepath} dosyasına yaz ve yeniden yükle", "description-missing": "Kurulum için {app} gereklidir" @@ -1446,14 +1446,14 @@ "description": "Uygulamaları başlatmak için varsayılan yöntem yerine özel bir ön ek kullanın.", "label": "Özel başlatma önekini etkinleştir" }, - "position": { - "description": "Başlatıcı panelinin nerede görüneceğini seçin.", - "label": "Konum" - }, "grid-view": { "description": "Öğeleri liste yerine ızgara düzeninde görüntüle.", "label": "Izgara görünümü" }, + "position": { + "description": "Başlatıcı panelinin nerede görüneceğini seçin.", + "label": "Konum" + }, "section": { "description": "Başlatıcının davranışını ve görünümünü özelleştirin.", "label": "Görünüm" @@ -1675,6 +1675,7 @@ "label": "Genel" } }, + "title": "Ekran Görüntüsü", "types": { "brightness": { "description": "Ekran parlaklığı değiştiğinde OSD'yi göster.", @@ -1696,12 +1697,7 @@ "description": "Ses çıkış düzeyi değiştiğinde OSD'yi göster.", "label": "Çıkış sesi" } - }, - "show-lock-key-notifications": { - "description": "Caps Lock, Num Lock veya Scroll Lock tuşları değiştirildiğinde bildirimleri göster.", - "label": "Kilit tuşu bildirimlerini göster" - }, - "title": "Ekran Görüntüsü" + } }, "screen-recorder": { "audio": { diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index cd51518f..ad73408d 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -227,14 +227,14 @@ "description": "Відображати виконавець - назва замість назва - виконавець.", "label": "Показувати спочатку виконавця" }, - "show-visualizer": { - "description": "Відображати аудіовізуалізатор під час відтворення музики.", - "label": "Показувати візуалізатор" - }, "show-progress-ring": { "description": "Відображати круговий індикатор прогресу, що показує просування треку.", "label": "Показувати кільце прогресу" }, + "show-visualizer": { + "description": "Відображати аудіовізуалізатор під час відтворення музики.", + "label": "Показувати візуалізатор" + }, "use-fixed-width": { "description": "Коли увімкнено, віджет завжди використовуватиме максимальну ширину замість динамічного налаштування до вмісту.", "label": "Використовувати фіксовану ширину" @@ -373,14 +373,14 @@ "description": "Кількість символів для відображення з назв робочих просторів (1-10).", "label": "Кількість символів" }, - "hide-unoccupied": { - "description": "Не відображати робочі простори без вікон.", - "label": "Приховати незайняті" - }, "follow-focused-screen": { "description": "Відображати робочі простори з поточного активного екрана, а не з екрана, на якому розташована панель.", "label": "Слідувати за Активним Екраном" }, + "hide-unoccupied": { + "description": "Не відображати робочі простори без вікон.", + "label": "Приховати незайняті" + }, "label-mode": { "description": "Виберіть, як відображаються мітки робочих просторів.", "label": "Режим міток" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "Рівень заряду акумулятора", "brightness": "Яскравість", - "charge-level": "Рівень заряду", "charging": "Зарядка.", "charging-rate": "Швидкість зарядки: {rate} Вт.", "discharging": "Розрядка.", @@ -519,13 +519,13 @@ "title": "Сповіщення" }, "time": { - "now": "зараз", - "diffM": "1 хвилину тому", - "diffMM": "{diff} хвилин тому", + "diffD": "1 день тому", + "diffDD": "{diff} днів тому", "diffH": "1 годину тому", "diffHH": "{diff} годин тому", - "diffD": "1 день тому", - "diffDD": "{diff} днів тому" + "diffM": "1 хвилину тому", + "diffMM": "{diff} хвилин тому", + "now": "зараз" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "Записати {filepath}.", + "description-missing": "Потрібна установка {app}" + }, "code": { "description": "Записати {filepath}. Тему Hyprluna потрібно встановити та активувати вручну.", "description-missing": "Клієнт Code не виявлено. Встановіть VSCode або VSCodium." @@ -1075,10 +1079,6 @@ "description": "Записати {filepath}.", "description-missing": "Потрібна установка {app}" }, - "cava": { - "description": "Записати {filepath}.", - "description-missing": "Потрібна установка {app}" - }, "vicinae": { "description": "Записати {filepath} та перезавантажити", "description-missing": "Потрібна установка {app}" @@ -1446,14 +1446,14 @@ "description": "Використовувати власний префікс для запуску програм замість стандартного методу.", "label": "Увімкнути власний префікс запуску" }, - "position": { - "description": "Виберіть, де з'являється панель запускача.", - "label": "Положення" - }, "grid-view": { "description": "Показувати елементи у вигляді сітки замість списку.", "label": "Вигляд сітки" }, + "position": { + "description": "Виберіть, де з'являється панель запускача.", + "label": "Положення" + }, "section": { "description": "Налаштуйте поведінку та зовнішній вигляд запускача.", "label": "Зовнішній вигляд" @@ -1675,6 +1675,7 @@ "label": "Загальні" } }, + "title": "Екранна індикація", "types": { "brightness": { "description": "Показувати OSD, коли змінюється яскравість екрана.", @@ -1696,12 +1697,7 @@ "description": "Показувати OSD, коли змінюється гучність аудіовиходу.", "label": "Вихідна гучність" } - }, - "show-lock-key-notifications": { - "description": "Показувати сповіщення, коли перемикаються клавіші Caps Lock, Num Lock або Scroll Lock.", - "label": "Показувати сповіщення про стан клавіш" - }, - "title": "Екранна індикація" + } }, "screen-recorder": { "audio": { diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 7efc5c35..0f3b9926 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -227,14 +227,14 @@ "description": "显示艺术家 - 标题,而不是标题 - 艺术家。", "label": "先显示艺术家" }, - "show-visualizer": { - "description": "播放音乐时显示音频可视化器。", - "label": "显示可视化器" - }, "show-progress-ring": { "description": "显示显示曲目进度的圆形进度指示器。", "label": "显示进度环" }, + "show-visualizer": { + "description": "播放音乐时显示音频可视化器。", + "label": "显示可视化器" + }, "use-fixed-width": { "description": "启用后,小部件将始终使用最大宽度,而不根据内容动态调整。", "label": "使用固定宽度" @@ -373,14 +373,14 @@ "description": "显示工作区名称的字符数量(1-10)。", "label": "字符数量" }, - "hide-unoccupied": { - "description": "不显示没有窗口的工作区。", - "label": "隐藏未占用" - }, "follow-focused-screen": { "description": "显示当前焦点屏幕的工作区,而不是任务栏所在屏幕的工作区。", "label": "跟随焦点屏幕" }, + "hide-unoccupied": { + "description": "不显示没有窗口的工作区。", + "label": "隐藏未占用" + }, "label-mode": { "description": "选择工作区标签的显示方式。", "label": "标签模式" @@ -389,8 +389,8 @@ } }, "battery": { + "battery-level": "电池电量", "brightness": "亮度", - "charge-level": "电量", "charging": "正在充电。", "charging-rate": "充电速率:{rate} W。", "discharging": "正在放电。", @@ -519,13 +519,13 @@ "title": "通知" }, "time": { - "now": "现在", - "diffM": "1 分钟前", - "diffMM": "{diff} 分钟前", + "diffD": "1 天前", + "diffDD": "{diff} 天前", "diffH": "1 小时前", "diffHH": "{diff} 小时前", - "diffD": "1 天前", - "diffDD": "{diff} 天前" + "diffM": "1 分钟前", + "diffMM": "{diff} 分钟前", + "now": "现在" } }, "options": { @@ -1049,6 +1049,10 @@ } }, "programs": { + "cava": { + "description": "写入 {filepath}。", + "description-missing": "需要安装 {app}" + }, "code": { "description": "写入 {filepath}。Hyprluna 主题需要手动安装和激活。", "description-missing": "未检测到 Code 客户端。请安装 VSCode 或 VSCodium。" @@ -1075,10 +1079,6 @@ "description": "写入 {filepath}。", "description-missing": "需要安装 {app}" }, - "cava": { - "description": "写入 {filepath}。", - "description-missing": "需要安装 {app}" - }, "vicinae": { "description": "写入 {filepath} 并重新加载", "description-missing": "需要安装 {app}" @@ -1446,14 +1446,14 @@ "description": "使用自定义前缀启动应用程序,而不是默认方法。", "label": "启用自定义启动前缀" }, - "position": { - "description": "选择启动器面板出现的位置。", - "label": "位置" - }, "grid-view": { "description": "以网格布局而非列表显示项目。", "label": "网格视图" }, + "position": { + "description": "选择启动器面板出现的位置。", + "label": "位置" + }, "section": { "description": "自定义启动器的行为和外观。", "label": "外观" @@ -1675,6 +1675,7 @@ "label": "常规" } }, + "title": "屏显菜单", "types": { "brightness": { "description": "当屏幕亮度发生变化时显示 OSD。", @@ -1696,12 +1697,7 @@ "description": "当音频输出音量发生变化时显示 OSD。", "label": "输出音量" } - }, - "show-lock-key-notifications": { - "description": "当大写锁定键、数字锁定键或滚动锁定键被切换时显示通知。", - "label": "显示锁定键通知" - }, - "title": "屏显菜单" + } }, "screen-recorder": { "audio": { diff --git a/Modules/Panels/Battery/BatteryPanel.qml b/Modules/Panels/Battery/BatteryPanel.qml index 74f15517..c554120b 100644 --- a/Modules/Panels/Battery/BatteryPanel.qml +++ b/Modules/Panels/Battery/BatteryPanel.qml @@ -116,7 +116,7 @@ SmartPanel { ColumnLayout { NText { - text: I18n.tr("battery.charge-level") + text: I18n.tr("battery.battery-level") color: Color.mOnSurface pointSize: Style.fontSizeS } From 12fe6c55591c2be9efb2838d36a32b4df8139337 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 16:55:10 -0500 Subject: [PATCH 06/27] Debug: inhibitReloadPopup onReloadFailed unless we are debugging. --- shell.qml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shell.qml b/shell.qml index 19f35a29..b542c95a 100644 --- a/shell.qml +++ b/shell.qml @@ -49,6 +49,11 @@ ShellRoot { function onReloadCompleted() { Quickshell.inhibitReloadPopup(); } + function onReloadFailed() { + if (!Settings?.isDebug) { + Quickshell.inhibitReloadPopup(); + } + } } Connections { From b7d4e7401243f0bc1daca3d63a5cd80ff71fab30 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 19:38:23 -0500 Subject: [PATCH 07/27] NImageRounded/Circled: removed shaders and used a simpler ClippingWrapperRectangle --- Modules/Bar/Widgets/MediaMini.qml | 8 +- Modules/LockScreen/LockScreen.qml | 6 +- Modules/Notification/Notification.qml | 21 ++-- .../ControlCenter/Cards/ProfileCard.qml | 3 +- Modules/Panels/Launcher/Launcher.qml | 4 +- .../NotificationHistoryPanel.qml | 5 +- .../WidgetSettings/ControlCenterSettings.qml | 3 +- Modules/Panels/Settings/Tabs/AboutTab.qml | 5 +- Modules/Panels/Settings/Tabs/GeneralTab.qml | 3 +- Shaders/frag/circled_image.frag | 30 ----- Shaders/frag/rounded_image.frag | 56 --------- Shaders/qsb/circled_image.frag.qsb | Bin 1706 -> 0 bytes Shaders/qsb/rounded_image.frag.qsb | Bin 2750 -> 0 bytes Widgets/NImageCircled.qml | 76 ------------- Widgets/NImageRounded.qml | 107 ++++++------------ 15 files changed, 69 insertions(+), 258 deletions(-) delete mode 100644 Shaders/frag/circled_image.frag delete mode 100644 Shaders/frag/rounded_image.frag delete mode 100644 Shaders/qsb/circled_image.frag.qsb delete mode 100644 Shaders/qsb/rounded_image.frag.qsb delete mode 100644 Widgets/NImageCircled.qml diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml index 43dca611..a4ca5f1b 100644 --- a/Modules/Bar/Widgets/MediaMini.qml +++ b/Modules/Bar/Widgets/MediaMini.qml @@ -409,16 +409,17 @@ Item { anchors.fill: parent anchors.margins: showProgressRing ? (3 * scaling) : 0.5 // Adjusted to align with progress circle better - NImageCircled { + NImageRounded { id: trackArt anchors.fill: parent anchors.margins: showProgressRing ? 0 : -1 * scaling // Add negative margin to make album art larger when no progress ring + radius: width * 0.5 visible: showAlbumArt && hasActivePlayer imagePath: MediaService.trackArtUrl fallbackIcon: MediaService.isPlaying ? "media-pause" : "media-play" fallbackIconSize: showProgressRing ? 10 : 12 // Larger fallback icon when no progress ring borderWidth: 0 - border.color: Color.transparent + borderColor: Color.transparent z: 1 // In front of the progress circle } @@ -649,9 +650,10 @@ Item { z: 1 // Above the visualizer and progress ring // Album Art - NImageCircled { + NImageRounded { anchors.fill: parent visible: showAlbumArt && hasActivePlayer + radius: width * 0.5 imagePath: MediaService.trackArtUrl fallbackIcon: MediaService.isPlaying ? "media-pause" : "media-play" fallbackIconSize: 12 diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml index 1612017d..325395b4 100644 --- a/Modules/LockScreen/LockScreen.qml +++ b/Modules/LockScreen/LockScreen.qml @@ -301,10 +301,11 @@ Loader { } } - NImageCircled { + NImageRounded { anchors.centerIn: parent width: 66 height: 66 + radius: width * 0.5 imagePath: Settings.preprocessPath(Settings.data.general.avatarImage) fallbackIcon: "person" @@ -631,9 +632,10 @@ Loader { color: Color.transparent clip: true - NImageCircled { + NImageRounded { anchors.fill: parent anchors.margins: 2 + radius: width * 0.5 imagePath: MediaService.trackArtUrl fallbackIcon: "disc" fallbackIconSize: Style.fontSizeM diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml index 6d39860a..d4d69db4 100644 --- a/Modules/Notification/Notification.qml +++ b/Modules/Notification/Notification.qml @@ -398,17 +398,16 @@ Variants { Layout.topMargin: Style.marginM Layout.bottomMargin: Style.marginM - ColumnLayout { - NImageCircled { - Layout.preferredWidth: Math.round(40 * Style.uiScaleRatio) - Layout.preferredHeight: Math.round(40 * Style.uiScaleRatio) - Layout.alignment: Qt.AlignVCenter - imagePath: model.originalImage || "" - borderColor: Color.transparent - borderWidth: 0 - fallbackIcon: "bell" - fallbackIconSize: 24 - } + NImageRounded { + Layout.preferredWidth: Math.round(40 * Style.uiScaleRatio) + Layout.preferredHeight: Math.round(40 * Style.uiScaleRatio) + Layout.alignment: Qt.AlignVCenter + radius: width * 0.5 + imagePath: model.originalImage || "" + borderColor: Color.transparent + borderWidth: 0 + fallbackIcon: "bell" + fallbackIconSize: 24 } ColumnLayout { diff --git a/Modules/Panels/ControlCenter/Cards/ProfileCard.qml b/Modules/Panels/ControlCenter/Cards/ProfileCard.qml index b37231ed..f827b506 100644 --- a/Modules/Panels/ControlCenter/Cards/ProfileCard.qml +++ b/Modules/Panels/ControlCenter/Cards/ProfileCard.qml @@ -25,9 +25,10 @@ NBox { anchors.margins: Style.marginM spacing: Style.marginM - NImageCircled { + NImageRounded { Layout.preferredWidth: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio) Layout.preferredHeight: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio) + radius: width * 0.5 imagePath: Settings.preprocessPath(Settings.data.general.avatarImage) fallbackIcon: "person" borderColor: Color.mPrimary diff --git a/Modules/Panels/Launcher/Launcher.qml b/Modules/Panels/Launcher/Launcher.qml index e8dfdcda..00537379 100644 --- a/Modules/Panels/Launcher/Launcher.qml +++ b/Modules/Panels/Launcher/Launcher.qml @@ -689,7 +689,7 @@ SmartPanel { id: imagePreview anchors.fill: parent visible: modelData.isImage && !modelData.emojiChar - imageRadius: Style.radiusM + radius: Style.radiusM // This property creates a dependency on the service's revision counter readonly property int _rev: ClipboardService.revision @@ -934,7 +934,7 @@ SmartPanel { id: gridImagePreview anchors.fill: parent visible: modelData.isImage && !modelData.emojiChar - imageRadius: Style.radiusM + radius: Style.radiusM readonly property int _rev: ClipboardService.revision diff --git a/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml b/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml index 8efde22c..4e25642c 100644 --- a/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml +++ b/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml @@ -197,10 +197,11 @@ SmartPanel { spacing: Style.marginM // Icon - NImageCircled { + NImageRounded { + anchors.verticalCenter: parent.verticalCenter width: Math.round(40 * Style.uiScaleRatio) height: Math.round(40 * Style.uiScaleRatio) - anchors.verticalCenter: parent.verticalCenter + radius: width * 0.5 imagePath: model.cachedImage || model.originalImage || "" borderColor: Color.transparent borderWidth: 0 diff --git a/Modules/Panels/Settings/Bar/WidgetSettings/ControlCenterSettings.qml b/Modules/Panels/Settings/Bar/WidgetSettings/ControlCenterSettings.qml index 7a0aa453..5f9eb339 100644 --- a/Modules/Panels/Settings/Bar/WidgetSettings/ControlCenterSettings.qml +++ b/Modules/Panels/Settings/Bar/WidgetSettings/ControlCenterSettings.qml @@ -59,10 +59,11 @@ ColumnLayout { description: I18n.tr("bar.widget-settings.control-center.icon.description") } - NImageCircled { + NImageRounded { Layout.preferredWidth: Style.fontSizeXL * 2 Layout.preferredHeight: Style.fontSizeXL * 2 Layout.alignment: Qt.AlignVCenter + radius: width * 0.5 imagePath: valueCustomIconPath visible: valueCustomIconPath !== "" } diff --git a/Modules/Panels/Settings/Tabs/AboutTab.qml b/Modules/Panels/Settings/Tabs/AboutTab.qml index 127ab7f5..f226afe6 100644 --- a/Modules/Panels/Settings/Tabs/AboutTab.qml +++ b/Modules/Panels/Settings/Tabs/AboutTab.qml @@ -189,10 +189,11 @@ ColumnLayout { Layout.preferredWidth: Style.baseWidgetSize * 2 * Style.uiScaleRatio Layout.preferredHeight: Style.baseWidgetSize * 2 * Style.uiScaleRatio - NImageCircled { - imagePath: modelData.avatar_url || "" + NImageRounded { anchors.fill: parent anchors.margins: Style.marginXS + radius: width * 0.5 + imagePath: modelData.avatar_url || "" fallbackIcon: "person" borderColor: contributorArea.containsMouse ? Color.mOnHover : Color.mPrimary borderWidth: Style.borderM diff --git a/Modules/Panels/Settings/Tabs/GeneralTab.qml b/Modules/Panels/Settings/Tabs/GeneralTab.qml index 481f4013..f111222b 100644 --- a/Modules/Panels/Settings/Tabs/GeneralTab.qml +++ b/Modules/Panels/Settings/Tabs/GeneralTab.qml @@ -21,9 +21,10 @@ ColumnLayout { spacing: Style.marginL // Avatar preview - NImageCircled { + NImageRounded { Layout.preferredWidth: 88 * Style.uiScaleRatio Layout.preferredHeight: width + radius: width * 0.5 imagePath: Settings.preprocessPath(Settings.data.general.avatarImage) fallbackIcon: "person" borderColor: Color.mPrimary diff --git a/Shaders/frag/circled_image.frag b/Shaders/frag/circled_image.frag deleted file mode 100644 index 308a9c5b..00000000 --- a/Shaders/frag/circled_image.frag +++ /dev/null @@ -1,30 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - float imageOpacity; -} ubuf; - -void main() { - // Center coordinates around (0, 0) - vec2 uv = qt_TexCoord0 - 0.5; - - // Calculate distance from center - float distance = length(uv); - - // Create circular mask - anything beyond radius 0.5 is transparent - float mask = 1.0 - smoothstep(0.48, 0.52, distance); - - // Sample the texture - vec4 color = texture(source, qt_TexCoord0); - - // Apply the circular mask and opacity - float finalAlpha = color.a * mask * ubuf.imageOpacity * ubuf.qt_Opacity; - fragColor = vec4(color.rgb * finalAlpha, finalAlpha); -} \ No newline at end of file diff --git a/Shaders/frag/rounded_image.frag b/Shaders/frag/rounded_image.frag deleted file mode 100644 index 9d493b21..00000000 --- a/Shaders/frag/rounded_image.frag +++ /dev/null @@ -1,56 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(binding = 1) uniform sampler2D source; - -layout(std140, binding = 0) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - // Custom properties with non-conflicting names - float itemWidth; - float itemHeight; - float cornerRadius; - float imageOpacity; -} ubuf; - -// Function to calculate the signed distance from a point to a rounded box -float roundedBoxSDF(vec2 centerPos, vec2 boxSize, float radius) { - vec2 d = abs(centerPos) - boxSize + radius; - return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0) - radius; -} - -void main() { - // Get size from uniforms - vec2 itemSize = vec2(ubuf.itemWidth, ubuf.itemHeight); - float cornerRadius = ubuf.cornerRadius; - float itemOpacity = ubuf.imageOpacity; - - // Normalize coordinates to [-0.5, 0.5] range - vec2 uv = qt_TexCoord0 - 0.5; - - // Scale by aspect ratio to maintain uniform rounding - vec2 aspectRatio = itemSize / max(itemSize.x, itemSize.y); - uv *= aspectRatio; - - // Calculate half size in normalized space - vec2 halfSize = 0.5 * aspectRatio; - - // Normalize the corner radius - float normalizedRadius = cornerRadius / max(itemSize.x, itemSize.y); - - // Calculate distance to rounded rectangle - float distance = roundedBoxSDF(uv, halfSize, normalizedRadius); - - // Create smooth alpha mask - float smoothedAlpha = 1.0 - smoothstep(0.0, fwidth(distance), distance); - - // Sample the texture - vec4 color = texture(source, qt_TexCoord0); - - // Apply the rounded mask and opacity - // Make sure areas outside the rounded rect are completely transparent - float finalAlpha = color.a * smoothedAlpha * itemOpacity * ubuf.qt_Opacity; - fragColor = vec4(color.rgb * finalAlpha, finalAlpha); -} \ No newline at end of file diff --git a/Shaders/qsb/circled_image.frag.qsb b/Shaders/qsb/circled_image.frag.qsb deleted file mode 100644 index 4faa90f9f62b6ac319e4ee498f3fa5ded2470831..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1706 zcmV;b237e002g?8ob6caZ_`#3zfIa^q#f@^83Rl^Ab~VEA$`%N4-yzipfXyqNl|CH ziIaLHcCfEYI#g-Ww6EK@{Vn^v|7p^`Oxrp49w#?$=-AK@o94=m&+oin*J&AJM;K$n za1X&f!Co-V47SNE)?p>)!jH#lOb1>JZuUD}Y`}#EPO>^En5-d`n?hZh|5Mdbw#@=i zXY2#`44)q;QgPuxM)(+E|oQ#c;#Hu2FJbXA!D(kEbN>xzdY>%9-hS5c@2@q?E zM67{|<<}{yDUCB9DiA=JRWQR?it-;iOz};xQTnVYkRFdsCD8sD6!AWxC!lrcaST-O z^V3HgkFq|mWeYRdS9VksRz`JK>7-NULiXn zJ=x{Q*))?w^Z23w(kCW`E!apO} z->ii6S-5}r`IqI8J_q+tmqu1Fo(rTqO#VM6dx)QhmA*v$=%j`81<3C*)d2N1!Y@<& zno_?rKwqO;Fp3xH>rAfX1kf4sJuGa>o@6M7QSyisu5^zr*C*#;J!(q#GA{Bf?g=!ifC}$O!3Te~&2r#D1NK(5Dp|>whuA zze;qG=4YJAnRo(TkUq-fOyK=3VaG@gdCL&h5yCIR$OLmaMfu+)9_pMRyhw91 zL9vfRR!E;G9jxtHCg*B`VnF^!OwQtYvUi#=w1@LCNwX2gG(~xR4*FR8Pe^8p^e+;& z27IhbifVOTi7`!hNZ+9Pen&CgB$*pz2WR0n%}-9zD-a&)&5&+E(VHW^Sw(N2@KA4o zbmu9DtArJ4_llImI@EMY$VjY6^Mv({DfU-r9=-?rD8EWND~ik-$$UmJ+-1ENT8Nbh z8&a?`VKFgV2@&5t(k~Hzjq+F|-fv)GUY-WSbj~ADW8EVn_T|*B<@vVjXgOU^wmqwA z3u?!1?6kFd(>3|x0oZl`O#0jls$AO+>d9A04X&2S3)%~AJT|#!cNPUEEFievHmf$@ zQ&GERHmokb4<-Z0uDf0fZE6AhQXuKsH(Twd<>kwo?*?Ag0)buA+q0d9wrf@M=xEdG zlw8-V>Bw{KnueLD(iEeR3U;+(pQtu17%4qFlU5@%YPQc!r)q(G({dVoCl&1WNwiG= zIWTiswBfg0m+$!8YJ;W1+yY+n3;DTRZua&S_~2HD2cDHLr)2J#z7+bRs@sm)Tx+&>OwdcEgoW%&?S=?94WC%t ztXlsr7;ROfY25eBM%mg*p_WgjxSb$LgI9RkxULF;DnH&G+VMxL5^G zb;}d&zN2|o1CqA9)V3Zr$#Y*CE%PhzDiSJm3L-kAJ7k~+Q9gI;b>HHtYJd8nC?yh+ zEgY0pD-o5>?xp37ZiY*}Bx72pfmAc#7|4d4*bQ!SOEaX9L1U~6`zQ?CWOBPIqlu2R z%IlwN+QE${51&3WN}lWc#zUtaaH`(`Yv6hF-WR3y^`~WBCN#jtdcY$_6t`eu{(VeG8Jjz+wPq) zXzz@}_D)9k#+!Grq4ESgFf1C>pkWy{K8LOAYgbW~$o9`>7$kLG0s~x23$7rfkcwpc z^6U+`I0P)%Hz#6XUp-jxug>w_!4hvy*-o_?)GTeOWpT4<_`KG%x0jPW+_zh`Tlg!x zvkWg8AHR<{X3O%S_?9NL27U4F9z$>Snj^Cqy^a~ZZqX_g(d(3+-r5?VX*-9kd8HEg zaJV$xs?$?P(=E$UT+63aXb}G30L`%5TU!~}1qW9|6ychfQ4o;lwumd!{gzXc2V(a; ztW?4mm6QvQKFQty0y893$fUbpB*N(ME^4p#7Z02#wv&wpF diff --git a/Shaders/qsb/rounded_image.frag.qsb b/Shaders/qsb/rounded_image.frag.qsb deleted file mode 100644 index 666f6434973c9fd0eb50651c6d43250023c55b53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2750 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 El;wG(X8-^I diff --git a/Widgets/NImageCircled.qml b/Widgets/NImageCircled.qml deleted file mode 100644 index c97e4440..00000000 --- a/Widgets/NImageCircled.qml +++ /dev/null @@ -1,76 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Widgets -import qs.Commons - -Rectangle { - id: root - - property string imagePath: "" - property color borderColor: Color.transparent - property real borderWidth: 0 - property string fallbackIcon: "" - property real fallbackIconSize: Style.fontSizeXXL - - color: Color.transparent - radius: parent.width * 0.5 - anchors.margins: Style.marginXXS - - Rectangle { - color: Color.transparent - anchors.fill: parent - - Image { - id: img - anchors.fill: parent - source: imagePath - visible: false // Hide since we're using it as shader source - mipmap: true - smooth: true - asynchronous: true - antialiasing: true - fillMode: Image.PreserveAspectCrop - } - - ShaderEffect { - anchors.fill: parent - - property var source: ShaderEffectSource { - sourceItem: img - hideSource: true - live: true - recursive: false - format: ShaderEffectSource.RGBA - } - - property real imageOpacity: root.opacity - fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/circled_image.frag.qsb") - supportsAtlasTextures: false - blending: true - } - - // Fallback icon - Loader { - active: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "") - anchors.centerIn: parent - sourceComponent: NIcon { - anchors.centerIn: parent - icon: fallbackIcon - pointSize: fallbackIconSize - z: 0 - } - } - } - - // Border - Rectangle { - anchors.fill: parent - radius: parent.radius - color: Color.transparent - border.color: parent.borderColor - border.width: parent.borderWidth - antialiasing: true - z: 10 - } -} diff --git a/Widgets/NImageRounded.qml b/Widgets/NImageRounded.qml index 67d3a178..7d28fa2d 100644 --- a/Widgets/NImageRounded.qml +++ b/Widgets/NImageRounded.qml @@ -4,91 +4,56 @@ import Quickshell import Quickshell.Widgets import qs.Commons -Rectangle { +Item { id: root + property real radius: 0 property string imagePath: "" - property color borderColor: Color.transparent - property real borderWidth: 0 - property real imageRadius: width * 0.5 - property int imageFillMode: Image.PreserveAspectCrop property string fallbackIcon: "" property real fallbackIconSize: Style.fontSizeXXL + property real borderWidth: 0 + property color borderColor: Color.transparent - property real scaledRadius: imageRadius * Settings.data.general.radiusRatio + readonly property bool showFallback: (fallbackIcon !== undefined && fallbackIcon !== "") && (imagePath === undefined || imagePath === "") signal statusChanged(int status) - color: Color.transparent - radius: scaledRadius - anchors.margins: Style.marginXXS - - Rectangle { - color: Color.transparent + ClippingWrapperRectangle { anchors.fill: parent + color: Color.transparent + radius: root.radius + border.color: root.borderColor + border.width: root.borderWidth - Image { - id: img + Item { anchors.fill: parent - source: imagePath - visible: false - mipmap: true - smooth: true - asynchronous: true - antialiasing: true - fillMode: root.imageFillMode - horizontalAlignment: Image.AlignHCenter - verticalAlignment: Image.AlignVCenter - - onStatusChanged: root.statusChanged(status) - } - - ShaderEffect { - anchors.fill: parent - - property var source: ShaderEffectSource { - sourceItem: img - hideSource: true - live: true - recursive: false - format: ShaderEffectSource.RGBA - } - - property real itemWidth: root.width - property real itemHeight: root.height - property real cornerRadius: root.radius - property real imageOpacity: root.opacity - fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/rounded_image.frag.qsb") - - supportsAtlasTextures: false - blending: true - Rectangle { - id: background + Loader { + active: true anchors.fill: parent - color: Color.transparent - z: -1 + sourceComponent: showFallback ? fallback : image + } + + Component { + id: image + Image { + source: imagePath + mipmap: true + smooth: true + asynchronous: true + antialiasing: true + fillMode: Image.PreserveAspectCrop + onStatusChanged: root.statusChanged(status) + } + } + + Component { + id: fallback + NIcon { + anchors.centerIn: parent + icon: fallbackIcon + pointSize: fallbackIconSize + } } } - - Loader { - active: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "") - anchors.centerIn: parent - sourceComponent: NIcon { - anchors.centerIn: parent - icon: fallbackIcon - pointSize: fallbackIconSize - z: 0 - } - } - } - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: Color.transparent - border.color: parent.borderColor - border.width: parent.borderWidth - antialiasing: true - z: 10 } } From a2e686bb2100184420470d44844deb232e4890f6 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 19:59:06 -0500 Subject: [PATCH 08/27] AudioService: proper volume clamping --- Services/Media/AudioService.qml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Services/Media/AudioService.qml b/Services/Media/AudioService.qml index 6fb76e29..22b2f7ca 100644 --- a/Services/Media/AudioService.qml +++ b/Services/Media/AudioService.qml @@ -169,11 +169,14 @@ Singleton { if (volume >= maxVolume) { return; } - setVolume(volume + stepVolume); + setVolume(Math.min(maxVolume, volume + stepVolume)); } function decreaseVolume() { - setVolume(volume - stepVolume); + if (volume <= 0) { + return; + } + setVolume(Math.max(0, volume - stepVolume)); } function setVolume(newVolume: real) { From 7742bb5cc068b990d98f41c95b67f86eaffe961d Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 19:59:23 -0500 Subject: [PATCH 09/27] OSD: fix non existing fontWeight --- Modules/OSD/OSD.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/OSD/OSD.qml b/Modules/OSD/OSD.qml index b73a749b..f5ea0a1a 100644 --- a/Modules/OSD/OSD.qml +++ b/Modules/OSD/OSD.qml @@ -488,7 +488,7 @@ Variants { color: root.currentOSDType === OSD.Type.LockKey ? root.getProgressColor() : Color.mOnSurface pointSize: root.currentOSDType === OSD.Type.LockKey ? Style.fontSizeM : Style.fontSizeS family: Settings.data.ui.fontFixed - font.weight: root.currentOSDType === OSD.Type.LockKey ? Style.fontWeightMedium : Style.fontWeightNormal + font.weight: root.currentOSDType === OSD.Type.LockKey ? Style.fontWeightMedium : Style.fontWeightRegular Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter horizontalAlignment: Text.AlignHCenter From ad044882a904b34aad6e8452d93bb760f21c0cd1 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 19:59:37 -0500 Subject: [PATCH 10/27] NIcon: always center icon --- Widgets/NIcon.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml index 371c1867..eeabc712 100644 --- a/Widgets/NIcon.qml +++ b/Widgets/NIcon.qml @@ -26,4 +26,5 @@ Text { font.pointSize: applyUiScale ? root.pointSize * Style.uiScaleRatio : root.pointSize color: Color.mOnSurface verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter } From 58d47308142688f260736bd5bfe648d0bded5b12 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 20:25:01 -0500 Subject: [PATCH 11/27] Restore rounded_image shader for the SetupWizard for now. --- Shaders/frag/rounded_image.frag | 56 +++++++++++++++++++++++++++++ Shaders/qsb/rounded_image.frag.qsb | Bin 0 -> 2750 bytes 2 files changed, 56 insertions(+) create mode 100644 Shaders/frag/rounded_image.frag create mode 100644 Shaders/qsb/rounded_image.frag.qsb diff --git a/Shaders/frag/rounded_image.frag b/Shaders/frag/rounded_image.frag new file mode 100644 index 00000000..9d493b21 --- /dev/null +++ b/Shaders/frag/rounded_image.frag @@ -0,0 +1,56 @@ +#version 450 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D source; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + // Custom properties with non-conflicting names + float itemWidth; + float itemHeight; + float cornerRadius; + float imageOpacity; +} ubuf; + +// Function to calculate the signed distance from a point to a rounded box +float roundedBoxSDF(vec2 centerPos, vec2 boxSize, float radius) { + vec2 d = abs(centerPos) - boxSize + radius; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0) - radius; +} + +void main() { + // Get size from uniforms + vec2 itemSize = vec2(ubuf.itemWidth, ubuf.itemHeight); + float cornerRadius = ubuf.cornerRadius; + float itemOpacity = ubuf.imageOpacity; + + // Normalize coordinates to [-0.5, 0.5] range + vec2 uv = qt_TexCoord0 - 0.5; + + // Scale by aspect ratio to maintain uniform rounding + vec2 aspectRatio = itemSize / max(itemSize.x, itemSize.y); + uv *= aspectRatio; + + // Calculate half size in normalized space + vec2 halfSize = 0.5 * aspectRatio; + + // Normalize the corner radius + float normalizedRadius = cornerRadius / max(itemSize.x, itemSize.y); + + // Calculate distance to rounded rectangle + float distance = roundedBoxSDF(uv, halfSize, normalizedRadius); + + // Create smooth alpha mask + float smoothedAlpha = 1.0 - smoothstep(0.0, fwidth(distance), distance); + + // Sample the texture + vec4 color = texture(source, qt_TexCoord0); + + // Apply the rounded mask and opacity + // Make sure areas outside the rounded rect are completely transparent + float finalAlpha = color.a * smoothedAlpha * itemOpacity * ubuf.qt_Opacity; + fragColor = vec4(color.rgb * finalAlpha, finalAlpha); +} \ No newline at end of file diff --git a/Shaders/qsb/rounded_image.frag.qsb b/Shaders/qsb/rounded_image.frag.qsb new file mode 100644 index 0000000000000000000000000000000000000000..666f6434973c9fd0eb50651c6d43250023c55b53 GIT binary patch literal 2750 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 El;wG(X8-^I literal 0 HcmV?d00001 From 3c5dfd87db582bf9056d83f41d53b90ba08023c6 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 25 Nov 2025 20:56:00 -0500 Subject: [PATCH 12/27] NImageRounded: attempt to fix crash on older Qt versions --- Widgets/NImageRounded.qml | 44 ++++++++++++++------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/Widgets/NImageRounded.qml b/Widgets/NImageRounded.qml index 7d28fa2d..588f5c60 100644 --- a/Widgets/NImageRounded.qml +++ b/Widgets/NImageRounded.qml @@ -18,42 +18,30 @@ Item { signal statusChanged(int status) - ClippingWrapperRectangle { + ClippingRectangle { anchors.fill: parent color: Color.transparent radius: root.radius border.color: root.borderColor border.width: root.borderWidth - Item { + Image { anchors.fill: parent - Loader { - active: true - anchors.fill: parent - sourceComponent: showFallback ? fallback : image - } + visible: !showFallback + source: imagePath + mipmap: true + smooth: true + asynchronous: true + antialiasing: true + fillMode: Image.PreserveAspectCrop + onStatusChanged: root.statusChanged(status) + } - Component { - id: image - Image { - source: imagePath - mipmap: true - smooth: true - asynchronous: true - antialiasing: true - fillMode: Image.PreserveAspectCrop - onStatusChanged: root.statusChanged(status) - } - } - - Component { - id: fallback - NIcon { - anchors.centerIn: parent - icon: fallbackIcon - pointSize: fallbackIconSize - } - } + NIcon { + anchors.centerIn: parent + visible: showFallback + icon: fallbackIcon + pointSize: fallbackIconSize } } } From b3cd4568f3a38496dc84e487e472fd377f28d8f0 Mon Sep 17 00:00:00 2001 From: loner <2788892716@qq.com> Date: Wed, 26 Nov 2025 14:36:03 +0800 Subject: [PATCH 13/27] feat(shader): Add progress_border.frag shader source file --- Shaders/frag/progress_border.frag | 67 +++++++++++++++++++++++++++ Shaders/qsb/progress_border.frag.qsb | Bin 4181 -> 3330 bytes 2 files changed, 67 insertions(+) create mode 100644 Shaders/frag/progress_border.frag diff --git a/Shaders/frag/progress_border.frag b/Shaders/frag/progress_border.frag new file mode 100644 index 00000000..331386c4 --- /dev/null +++ b/Shaders/frag/progress_border.frag @@ -0,0 +1,67 @@ +#version 450 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D source; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + float progress; + float borderWidth; + vec4 progressColor; + vec4 borderColor; + vec4 backgroundColor; + float borderRadius; +} ubuf; + +void main() { + vec2 coord = qt_TexCoord0; + float p = clamp(ubuf.progress, 0.0, 1.0); + + if (ubuf.borderRadius > 0.0) { + // Circular progress + vec2 center = vec2(0.5, 0.5); + vec2 dir = coord - center; + float dist = length(dir); + + float outerRadius = 0.5; + float innerRadius = outerRadius - ubuf.borderWidth; + + float angle = atan(dir.y, dir.x) + radians(90.0); + if (angle < 0.0) angle += radians(360.0); + float maxAngle = radians(360.0) * p; + + bool inBorder = dist >= innerRadius && dist <= outerRadius; + bool inProgress = inBorder && angle <= maxAngle; + + if (inProgress) { + fragColor = ubuf.progressColor * ubuf.qt_Opacity; + } else if (inBorder) { + fragColor = ubuf.borderColor * ubuf.qt_Opacity; + } else if (dist < innerRadius) { + fragColor = ubuf.backgroundColor * ubuf.qt_Opacity; + } else { + fragColor = vec4(0.0, 0.0, 0.0, 0.0); + } + } else { + // Rectangular progress + bool inBorder = + coord.x < ubuf.borderWidth || + coord.x > (1.0 - ubuf.borderWidth) || + coord.y < ubuf.borderWidth || + coord.y > (1.0 - ubuf.borderWidth); + + float progressPos = p; + bool inProgress = inBorder && coord.x <= progressPos; + + if (inProgress) { + fragColor = ubuf.progressColor * ubuf.qt_Opacity; + } else if (inBorder) { + fragColor = ubuf.borderColor * ubuf.qt_Opacity; + } else { + fragColor = ubuf.backgroundColor * ubuf.qt_Opacity; + } + } +} \ No newline at end of file diff --git a/Shaders/qsb/progress_border.frag.qsb b/Shaders/qsb/progress_border.frag.qsb index e6e8f3153317d9ce9cd9b349c78219dac9c41438..94e1628ded1367f58f5c367fc2d042f7b5e85a55 100644 GIT binary patch literal 3330 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 Mh>rXEFKzyR7{VLA$N&HU literal 4181 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 Date: Wed, 26 Nov 2025 07:28:23 +0000 Subject: [PATCH 14/27] Update es.json translation for 'play' to 'Reproducir' spanish has a lot words for the same thing (in spanish (jugar) play it is used to play ...games (jugar juegos), but play music is "reproducir musica" --- Assets/Translations/es.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 95ed6b87..c9b06176 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -479,7 +479,7 @@ "open-mixer": "Mezclador de audio", "open-settings": "Abrir ajustes", "pause": "Pausa", - "play": "Jugar", + "play": "Reproducir", "previous": "Anterior", "random-wallpaper": "Fondo de pantalla aleatorio", "toggle-mute": "Activar/desactivar silencio", From bc9c27baf86015ae24e61636746f549b6f34efd4 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 26 Nov 2025 10:31:36 +0100 Subject: [PATCH 15/27] Matugen/Vesktop: fix thread text color --- Assets/MatugenTemplates/vesktop.css | 18 ++++++++++++ Assets/noctalia-shape.svg | 43 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 Assets/noctalia-shape.svg diff --git a/Assets/MatugenTemplates/vesktop.css b/Assets/MatugenTemplates/vesktop.css index 6a85df16..00f9b76e 100644 --- a/Assets/MatugenTemplates/vesktop.css +++ b/Assets/MatugenTemplates/vesktop.css @@ -173,3 +173,21 @@ body { .timestampInline_c19a55 time { color: var(--text-4) !important; } + +.postTitleText_faa96b { + color: var(--text-3) !important; +} + +.postTitleText_faa96b .highlight { + color: var(--text-2) !important; +} + +.messageContent_c19a55, +.messageContent_faa96b { + color: var(--text-3) !important; +} + +.messageContent_c19a55 .highlight, +.messageContent_faa96b .highlight { + color: var(--text-2) !important; +} diff --git a/Assets/noctalia-shape.svg b/Assets/noctalia-shape.svg new file mode 100644 index 00000000..631dabf5 --- /dev/null +++ b/Assets/noctalia-shape.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + From 737bde0a6aae414b6adc61a5f4dc76e5c6489dd5 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 26 Nov 2025 10:34:55 +0100 Subject: [PATCH 16/27] Matugen/Vesktop: fix noctalia logo display --- Assets/MatugenTemplates/vesktop.css | 2 +- Assets/noctalia-shape.svg | 43 ----------------------------- 2 files changed, 1 insertion(+), 44 deletions(-) delete mode 100644 Assets/noctalia-shape.svg diff --git a/Assets/MatugenTemplates/vesktop.css b/Assets/MatugenTemplates/vesktop.css index 00f9b76e..a509fdcd 100644 --- a/Assets/MatugenTemplates/vesktop.css +++ b/Assets/MatugenTemplates/vesktop.css @@ -42,7 +42,7 @@ body { /* dms button options */ --custom-dms-icon: custom; /* off: use default discord icon, hide: remove icon entirely, custom: use custom icon */ - --dms-icon-svg-url: url('https://raw.githubusercontent.com/noctalia-dev/noctalia-shell/main/Assets/noctalia-shape.svg'); /* icon svg url. MUST BE A SVG. */ + --dms-icon-svg-url: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB3aWR0aD0iMjU2IgogICBoZWlnaHQ9IjI1NiIKICAgdmlld0JveD0iMCAwIDY3LjczMzMzNCA2Ny43MzMzMzQiCiAgIHZlcnNpb249IjEuMSIKICAgaWQ9InN2ZzEiCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczEiIC8+CiAgPGcKICAgICBpZD0iZzEiCiAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4xMDEwODY5LDAsMCwxLjEwMTA4NjksLTMuNDIzODM0NywtMy40MjM0ODkzKSI+CiAgICA8ZwogICAgICAgaWQ9Imc1NSIKICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCg0LjIwNTU5MDUsMCwwLDQuMjA1NTkwNSwtMTQuNzg4ODk4LC0xODAuNDMzNjIpIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGg1NSIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6OS4xO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtwYWludC1vcmRlcjpmaWxsIG1hcmtlcnMgc3Ryb2tlIgogICAgICAgICBkPSJtIDExLjY0NjQ4NCw0My42NDI1NzggYSA3LjMxNDEzNTYsNy4zMTQxMzU2IDAgMCAwIC03LjMxMjQ5OTYsNy4zMTI1IDcuMzE0MTM1Niw3LjMxNDEzNTYgMCAwIDAgNy4zMTI0OTk2LDcuMzE0NDUzIDcuMzE0MTM1Niw3LjMxNDEzNTYgMCAwIDAgNy4xNTgyMDQsLTUuODk4NDM3IDYuMjIwMzMwMiw2LjIyMDMzMDIgMCAwIDEgLTMuNDE2MDE2LDMuNDY0ODQ0IGMgMC4wMDE1LDAuMjc3NDA2IDAuMDAzOSwwLjUzMjU1IDAuMDAzOSwwLjcyNjU2MiAtMC43Mzk0NDUsMCAtMS4zNzU4MzUsLTAuMTAxODg2IC0xLjkyMTg3NSwtMC4yNzE0ODQgYSA2LjIyMDMzMDIsNi4yMjAzMzAyIDAgMCAxIC0wLjQ0MTQwNiwwLjAzNTE2IDYuMjIwMzMwMiw2LjIyMDMzMDIgMCAwIDEgLTYuMjIwNzAzMiwtNi4yMjA3MDMgNi4yMjAzMzAyLDYuMjIwMzMwMiAwIDAgMSA2LjIyMDcwMzIsLTYuMjIwNzAzIDYuMjIwMzMwMiw2LjIyMDMzMDIgMCAwIDEgMC41NzYxNzIsMC4wMjczNCA3LjMxNDEzNTYsNy4zMTQxMzU2IDAgMCAwIC0xLjk1ODk4NSwtMC4yNjk1MzEgeiIgLz4KICAgIDwvZz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDU2IgogICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS4zNDYwODtzdHJva2UtbWl0ZXJsaW1pdDo5LjE7cGFpbnQtb3JkZXI6ZmlsbCBtYXJrZXJzIHN0cm9rZSIKICAgICAgIGQ9Im0gNDIuNjY0NDQsMzEuMjkxNDc0IGMgLTEuODAyODgyLDIuMDIzMTA1IC00Ljk1MDEzOSwyLjQ5MjY2MSAtOC41MjU0LDIuNTAyOCAtMi43MTgxNiwtMC4wMDc3IC01LjQ1MDQ3NiwtMC4xMjgyMjcgLTcuMjY5NTYsLTEuMzg5NTUxIC0xLjgxNjU0MiwwLjMyNDE4MiAtMi41NzkxNTcsMi4zNDQwMzMgLTIuNDE1ODY2LDQuNzAyNzc3IDEuMTY0NjQ3LDE2LjgyMjk2NyAxMS44MTY3MiwxNS43MzQ2NDUgMTEuOTEyMTk4LDE1LjcwNzE0NSAtNy43OTMzNjYsLTMuODAyNDQ3IC02LjUxNjQ5OCwtMTAuMDAwNDggLTYuNzcyNjIyLC0xMS45NzUyOTMgMC4zMjA5MjgsMy4zNDIzMyAzLjg5NTkyNiwxMi44NTY3NjQgMTcuMjM1NDk0LDEyLjg1Njc2NCAwLC00LjAwOTY1NSAwLjAxOTkyLC0xNC4zMTEwMzUgLTEuMjc5MDgsLTE3LjQ4NzAyNCAtMC40MDkxMjQsLTEuMjM3MzEyIC0xLjUyNTI2LC00LjU0Njk2MyAtMi44ODUxNjQsLTQuOTE3NjE4IHoiIC8+CiAgICA8cGF0aAogICAgICAgaWQ9InBhdGg1NyIKICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjMuNzY1NjU7c3Ryb2tlLW1pdGVybGltaXQ6OS4xO3BhaW50LW9yZGVyOmZpbGwgbWFya2VycyBzdHJva2UiCiAgICAgICBkPSJtIDIwLjk5MjAxMywxNi4wODcwMDQgYyAwLjYwODk0NCwxLjg2NTU0NSAxLjgzNTMzNCwzLjcwNDMxNCAzLjQ4MDA4Niw0LjQwMTc0NSAtMC40NTg3ODEsMS4zODI4MDQgLTAuNDYwODMxLDMuMDI0OTQ5IC0wLjQ2MDgzMSw0Ljc4MzEyNiAwLDQuOTI3ODk1IDQuNTMzNjk4LDguOTE5NDEzIDEwLjEzMDM1OSw4LjkzODU1OSA1LjU5NjY2NCwtMC4wMTkxMiAxMC4xMzAzNjcsLTQuMDEwNjY3IDEwLjEzMDM2NywtOC45Mzg1NTkgMCwtMS43NTgxNzcgLTAuMDAyMSwtMy40MDAzMjIgLTAuNDYwODMzLC00Ljc4MzEyNiAxLjY0NDc1MywtMC42OTc0MzEgMi44NzExNDIsLTIuNTM2MiAzLjQ4MDA4NCwtNC40MDE3NDUgLTEuOTg3Nzc2LC0wLjAzMDUgLTUuMTUwOTA4LDAuNzAwNzU3IC03Ljg1MDA0NywwLjc4NjU5NSAtMS4zNTE1MzksLTAuMzUxODQ1IC0zLjA4NjEzNywtMC41NDU4NjggLTUuMjk5NTcxLC0wLjU0ODIzMyAtMi4yMTM0MzEsMC4wMDI0IC0zLjk0ODAyNywwLjE5NjM2NyAtNS4yOTk1NjgsMC41NDgyMzMgLTIuNjk5MTM1LC0wLjA4NTg0IC01Ljg2MjI2NiwtMC44MTcxODcgLTcuODUwMDQ2LC0wLjc4NjU5NSB6IG0gNi43Nzc0MTksNC42NDgwNTMgYyAwLjU1NTQ3LC0wLjAxMzgzIDEuMjk5Nzc5LDAuMDYyMDQgMi4zMDQxNjEsMC4yNDYzMTkgMC42NzIxOTgsMC4xMjMzMDIgMS41MjM1MzYsMC40NTI0MDIgMi4wMzQwMTksMC43NTQ4MTMgMC45NTA4MDcsMC41NjMyNjQgMS4wNzM1OTUsMS4yMDc2OTcgMi4wMzQwMTUsMS4yMDc2OTcgMC45NjA0MiwwIDEuMDgzMjA3LC0wLjY0NDQzMyAyLjAzNDAxOCwtMS4yMDc2OTcgMC41MTA0ODMsLTAuMzAyNDE4IDEuMzYxODIyLC0wLjYzMTUxMSAyLjAzNDAyMSwtMC43NTQ4MTMgNC41OTE0NTksLTAuODQyMzI4IDMuODIxNzMyLDAuNTIzOTYyIDMuODIxNzMyLDIuODM2NTA1IDAsMi4zODcxMzIgLTEuOTM1MTU1LDQuMzIyMjkgLTQuMzIyMjkxLDQuMzIyMjkgLTAuNzYyOTUsLTAuMDAzNyAtMS41MTEzMzIsLTAuMjA5MzQgLTIuMTY5MDkxLC0wLjU5NTkwNSAtMC4wMTU0NiwwLjAzMzc1IC0wLjAyODg3LDAuMDY0ODQgLTAuMDQ3NjgsMC4wOTUzNSBsIC0wLjk2OTMzOCwxLjU3MzE4OSBjIC0wLjEwNTIzOSwwLjE3MTIyMiAtMC4yNDM3OTcsMC4yNTc0NjcgLTAuMzgxMzc4LDAuMjU0MjUxIC0wLjEzNzU4LDAuMDAzMSAtMC4yNzYxMzksLTAuMDgzMDMgLTAuMzgxMzc4LC0wLjI1NDI1MSBsIC0wLjk2OTMzOCwtMS41NzMxODkgYyAtMC4wMTg3MSwtMC4wMzA1IC0wLjAzMjEyLC0wLjA2MTU5IC0wLjA0NzY4LC0wLjA5NTM1IC0wLjY1Nzc2MywwLjM4NjU4NSAtMS40MDYxNDIsMC41OTIxODggLTIuMTY5MDkxLDAuNTk1OTA1IC0yLjM4NzEzNywwIC00LjMyMjI5LC0xLjkzNTE1OCAtNC4zMjIyOSwtNC4zMjIyOSAwLC0xLjgwNjY3MyAtMC40NjYyNzEsLTMuMDMzMTczIDEuNTE3NTY5LC0zLjA4MjgxNCB6IiAvPgogICAgPHBhdGgKICAgICAgIGlkPSJwYXRoNTgiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjIyMDUyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjkuMTtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjpmaWxsIG1hcmtlcnMgc3Ryb2tlIgogICAgICAgZD0iTSAzMi4zMDQyLDI1LjMwMDU5NiBBIDEuOTkxNDQzOCwxLjk5MTQ0MzggMCAwIDEgMzAuNTc5NTU5LDI2LjI5NjMyIDEuOTkxNDQzOCwxLjk5MTQ0MzggMCAwIDEgMjguODU0OTE4LDI1LjMwMDU5NiIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDU5IgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MS4yMjA1MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo5LjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6ZmlsbCBtYXJrZXJzIHN0cm9rZSIKICAgICAgIGQ9Ik0gMzkuNDI4MzM0LDI1LjMwMDU5NiBBIDEuOTkxNDQzOCwxLjk5MTQ0MzggMCAwIDEgMzcuNzAzNjk2LDI2LjI5NjMyIDEuOTkxNDQzOCwxLjk5MTQ0MzggMCAwIDEgMzUuOTc5MDUzLDI1LjMwMDU5NiIgLz4KICA8L2c+Cjwvc3ZnPg=='); /* icon svg url. MUST BE A SVG. */ --dms-icon-svg-size: 90%; /* size of the svg (css mask-size property) */ --dms-icon-color-before: var(--icon-secondary); /* normal icon color */ --dms-icon-color-after: var(--white); /* icon color when button is hovered/selected */ diff --git a/Assets/noctalia-shape.svg b/Assets/noctalia-shape.svg deleted file mode 100644 index 631dabf5..00000000 --- a/Assets/noctalia-shape.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - From 3ef5e169e4e0688c54cbfd2f829285aaef30939d Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 26 Nov 2025 12:40:18 +0100 Subject: [PATCH 17/27] Brightness/VolumeWidget: fix visual issues (#875) --- Modules/Bar/Extras/BarPillHorizontal.qml | 7 +++++-- Modules/Bar/Extras/BarPillVertical.qml | 7 +++++-- Modules/Bar/Widgets/Brightness.qml | 2 ++ Services/Media/AudioService.qml | 9 +++++++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Modules/Bar/Extras/BarPillHorizontal.qml b/Modules/Bar/Extras/BarPillHorizontal.qml index cd9358b9..a91945f6 100644 --- a/Modules/Bar/Extras/BarPillHorizontal.qml +++ b/Modules/Bar/Extras/BarPillHorizontal.qml @@ -23,6 +23,8 @@ Item { property color customBackgroundColor: Color.transparent property color customTextIconColor: Color.transparent + readonly property bool hiddenByForceClose: forceClose && !forceOpen + // Effective shown state (true if hovered/animated open or forced) readonly property bool revealed: !forceClose && (forceOpen || showPill) @@ -66,8 +68,9 @@ Item { } } - width: pillHeight + Math.max(0, pill.width - pillOverlap) - height: pillHeight + width: hiddenByForceClose ? 0 : pillHeight + Math.max(0, pill.width - pillOverlap) + height: hiddenByForceClose ? 0 : pillHeight + visible: !hiddenByForceClose Connections { target: root diff --git a/Modules/Bar/Extras/BarPillVertical.qml b/Modules/Bar/Extras/BarPillVertical.qml index 494d47d7..e16083cf 100644 --- a/Modules/Bar/Extras/BarPillVertical.qml +++ b/Modules/Bar/Extras/BarPillVertical.qml @@ -24,6 +24,8 @@ Item { property color customBackgroundColor: Color.transparent property color customTextIconColor: Color.transparent + readonly property bool hiddenByForceClose: forceClose && !forceOpen + signal shown signal hidden signal entered @@ -75,8 +77,9 @@ Item { } // For vertical bars: width is just icon size, height includes pill space - width: buttonSize - height: revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize + width: hiddenByForceClose ? 0 : buttonSize + height: hiddenByForceClose ? 0 : (revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize) + visible: !hiddenByForceClose Connections { target: root diff --git a/Modules/Bar/Widgets/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml index bd0f5d08..160d02c6 100644 --- a/Modules/Bar/Widgets/Brightness.qml +++ b/Modules/Bar/Widgets/Brightness.qml @@ -47,6 +47,8 @@ Item { function getIcon() { var monitor = getMonitor(); var brightness = monitor ? monitor.brightness : 0; + if (brightness <= 0.001) + return "sun-off"; return brightness <= 0.5 ? "brightness-low" : "brightness-high"; } diff --git a/Services/Media/AudioService.qml b/Services/Media/AudioService.qml index 22b2f7ca..4420031a 100644 --- a/Services/Media/AudioService.qml +++ b/Services/Media/AudioService.qml @@ -202,9 +202,14 @@ Singleton { function getOutputIcon() { if (muted) return "volume-mute"; - if (volume <= Number.EPSILON) + + const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; + const clampedVolume = Math.max(0, Math.min(volume, maxVolume)); + const displayPercent = Math.round(clampedVolume * 100); + + if (displayPercent === 0) return "volume-zero"; - if (volume <= 0.5) + if (clampedVolume <= 0.5) return "volume-low"; return "volume-high"; } From 42211c6eda5888763b3b40b0db52f934b5fe1997 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 26 Nov 2025 13:49:54 +0100 Subject: [PATCH 18/27] Bluetooth/Wifi: fix on hover mode --- Modules/Bar/Widgets/Bluetooth.qml | 2 +- Modules/Bar/Widgets/WiFi.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml index 1fa1e28d..e57f01b7 100644 --- a/Modules/Bar/Widgets/Bluetooth.qml +++ b/Modules/Bar/Widgets/Bluetooth.qml @@ -87,7 +87,7 @@ Item { } autoHide: false forceOpen: !isBarVertical && root.displayMode === "alwaysShow" - forceClose: isBarVertical || root.displayMode === "alwaysHide" || BluetoothService.connectedDevices.length === 0 + forceClose: isBarVertical || root.displayMode === "alwaysHide" onClicked: PanelService.getPanel("bluetoothPanel", screen)?.toggle(this) onRightClicked: { var popupMenuWindow = PanelService.getPopupMenuWindow(screen); diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml index 26f699b7..f2832a1d 100644 --- a/Modules/Bar/Widgets/WiFi.qml +++ b/Modules/Bar/Widgets/WiFi.qml @@ -109,7 +109,7 @@ Item { } autoHide: false forceOpen: !isBarVertical && root.displayMode === "alwaysShow" - forceClose: isBarVertical || root.displayMode === "alwaysHide" || !pill.text + forceClose: isBarVertical || root.displayMode === "alwaysHide" onClicked: PanelService.getPanel("wifiPanel", screen)?.toggle(this) onRightClicked: { var popupMenuWindow = PanelService.getPopupMenuWindow(screen); From 60eb9c6e78676d0bd145f1a52a779918870892c3 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 26 Nov 2025 13:57:58 +0100 Subject: [PATCH 19/27] Bluetooth/Wifi: fix always hide logic --- Modules/Bar/Extras/BarPillHorizontal.qml | 15 ++++++++++----- Modules/Bar/Extras/BarPillVertical.qml | 15 ++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Modules/Bar/Extras/BarPillHorizontal.qml b/Modules/Bar/Extras/BarPillHorizontal.qml index a91945f6..107dc96c 100644 --- a/Modules/Bar/Extras/BarPillHorizontal.qml +++ b/Modules/Bar/Extras/BarPillHorizontal.qml @@ -23,7 +23,7 @@ Item { property color customBackgroundColor: Color.transparent property color customTextIconColor: Color.transparent - readonly property bool hiddenByForceClose: forceClose && !forceOpen + readonly property bool collapseToIcon: forceClose && !forceOpen // Effective shown state (true if hovered/animated open or forced) readonly property bool revealed: !forceClose && (forceOpen || showPill) @@ -68,9 +68,8 @@ Item { } } - width: hiddenByForceClose ? 0 : pillHeight + Math.max(0, pill.width - pillOverlap) - height: hiddenByForceClose ? 0 : pillHeight - visible: !hiddenByForceClose + width: collapseToIcon ? pillHeight : pillHeight + Math.max(0, pill.width - pillOverlap) + height: pillHeight Connections { target: root @@ -84,7 +83,7 @@ Item { // Unified background for the entire pill area to avoid overlapping opacity Rectangle { id: pillBackground - width: root.width + width: collapseToIcon ? pillHeight : root.width height: pillHeight radius: halfPillHeight color: root.bgColor @@ -293,6 +292,8 @@ Item { } function show() { + if (collapseToIcon) + return; if (!showPill) { shouldAnimateHide = autoHide; showAnim.start(); @@ -303,6 +304,8 @@ Item { } function hide() { + if (collapseToIcon) + return; if (forceOpen) { return; } @@ -313,6 +316,8 @@ Item { } function showDelayed() { + if (collapseToIcon) + return; if (!showPill) { shouldAnimateHide = autoHide; showTimer.start(); diff --git a/Modules/Bar/Extras/BarPillVertical.qml b/Modules/Bar/Extras/BarPillVertical.qml index e16083cf..b8ab6859 100644 --- a/Modules/Bar/Extras/BarPillVertical.qml +++ b/Modules/Bar/Extras/BarPillVertical.qml @@ -24,7 +24,7 @@ Item { property color customBackgroundColor: Color.transparent property color customTextIconColor: Color.transparent - readonly property bool hiddenByForceClose: forceClose && !forceOpen + readonly property bool collapseToIcon: forceClose && !forceOpen signal shown signal hidden @@ -77,9 +77,8 @@ Item { } // For vertical bars: width is just icon size, height includes pill space - width: hiddenByForceClose ? 0 : buttonSize - height: hiddenByForceClose ? 0 : (revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize) - visible: !hiddenByForceClose + width: buttonSize + height: collapseToIcon ? buttonSize : (revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize) Connections { target: root @@ -94,7 +93,7 @@ Item { Rectangle { id: pillBackground width: buttonSize - height: revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize + height: collapseToIcon ? buttonSize : (revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize) radius: halfButtonSize color: root.bgColor @@ -324,6 +323,8 @@ Item { } function show() { + if (collapseToIcon) + return; if (!showPill) { shouldAnimateHide = autoHide; showAnim.start(); @@ -334,6 +335,8 @@ Item { } function hide() { + if (collapseToIcon) + return; if (forceOpen) { return; } @@ -344,6 +347,8 @@ Item { } function showDelayed() { + if (collapseToIcon) + return; if (!showPill) { shouldAnimateHide = autoHide; showTimer.start(); From a44137f81fc89fdde0ed371d32cc624feb52c6dc Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 26 Nov 2025 14:53:31 +0100 Subject: [PATCH 20/27] OSD: fix 0% volume icon --- Modules/OSD/OSD.qml | 5 +++-- Services/Media/AudioService.qml | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Modules/OSD/OSD.qml b/Modules/OSD/OSD.qml index f5ea0a1a..a5579df5 100644 --- a/Modules/OSD/OSD.qml +++ b/Modules/OSD/OSD.qml @@ -49,8 +49,9 @@ Variants { case OSD.Type.Volume: if (isMuted) return "volume-mute"; - if (currentVolume <= Number.EPSILON) - return "volume-zero"; + // Show muted icon when volume is effectively 0% (within rounding threshold) + if (currentVolume < 0.005) + return "volume-mute"; return currentVolume <= 0.5 ? "volume-low" : "volume-high"; case OSD.Type.InputVolume: return isInputMuted ? "microphone-off" : "microphone"; diff --git a/Services/Media/AudioService.qml b/Services/Media/AudioService.qml index 4420031a..8ef66c22 100644 --- a/Services/Media/AudioService.qml +++ b/Services/Media/AudioService.qml @@ -205,10 +205,10 @@ Singleton { const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; const clampedVolume = Math.max(0, Math.min(volume, maxVolume)); - const displayPercent = Math.round(clampedVolume * 100); - if (displayPercent === 0) - return "volume-zero"; + // Show muted icon when volume is effectively 0% (within rounding threshold) + if (clampedVolume < 0.005) + return "volume-mute"; if (clampedVolume <= 0.5) return "volume-low"; return "volume-high"; From c0b836af26592d229e605b7672005da3dd29e787 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 26 Nov 2025 14:54:38 +0100 Subject: [PATCH 21/27] OSD: fix 0% brightness icon --- Modules/OSD/OSD.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Modules/OSD/OSD.qml b/Modules/OSD/OSD.qml index a5579df5..bbbff7fe 100644 --- a/Modules/OSD/OSD.qml +++ b/Modules/OSD/OSD.qml @@ -56,6 +56,9 @@ Variants { case OSD.Type.InputVolume: return isInputMuted ? "microphone-off" : "microphone"; case OSD.Type.Brightness: + // Show sun-off icon when brightness is effectively 0% (within rounding threshold) + if (currentBrightness < 0.005) + return "sun-off"; return currentBrightness <= 0.5 ? "brightness-low" : "brightness-high"; case OSD.Type.LockKey: return "keyboard"; From 94d1d9dc9cd8026cd65c825180b36c5e319bb08e Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 26 Nov 2025 15:00:27 +0100 Subject: [PATCH 22/27] Tray: fix blacklist wildcardc --- Modules/Bar/Widgets/Tray.qml | 12 ++++++++---- Modules/Panels/Tray/TrayDrawerPanel.qml | 10 ++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Modules/Bar/Widgets/Tray.qml b/Modules/Bar/Widgets/Tray.qml index dfd98fee..c3fd3307 100644 --- a/Modules/Bar/Widgets/Tray.qml +++ b/Modules/Bar/Widgets/Tray.qml @@ -161,10 +161,14 @@ Rectangle { } //Logger.d("Tray", "wildCardMatch - Input str:", str, "rule:", rule) - // Escape all special regex characters in the rule - let escapedRule = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - // Convert '*' to '.*' for wildcard matching - let pattern = escapedRule.replace(/\\\*/g, '.*'); + // First, convert '*' to a placeholder to preserve it, then escape other special regex characters + // Use a unique placeholder that won't appear in normal strings + const placeholder = '\uE000'; // Private use character + let processedRule = rule.replace(/\*/g, placeholder); + // Escape all special regex characters (but placeholder won't match this) + let escapedRule = processedRule.replace(/[.+?^${}()|[\]\\]/g, '\\$&'); + // Convert placeholder back to '.*' for wildcard matching + let pattern = escapedRule.replace(new RegExp(placeholder, 'g'), '.*'); // Add ^ and $ to match the entire string pattern = '^' + pattern + '$'; diff --git a/Modules/Panels/Tray/TrayDrawerPanel.qml b/Modules/Panels/Tray/TrayDrawerPanel.qml index 2573f439..c114c74c 100644 --- a/Modules/Panels/Tray/TrayDrawerPanel.qml +++ b/Modules/Panels/Tray/TrayDrawerPanel.qml @@ -43,8 +43,14 @@ SmartPanel { function wildCardMatch(str, rule) { if (!str || !rule) return false; - let escaped = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - let pattern = '^' + escaped.replace(/\\\*/g, '.*') + '$'; + // First, convert '*' to a placeholder to preserve it, then escape other special regex characters + // Use a unique placeholder that won't appear in normal strings + const placeholder = '\uE000'; // Private use character + let processedRule = rule.replace(/\*/g, placeholder); + // Escape all special regex characters (but placeholder won't match this) + let escaped = processedRule.replace(/[.+?^${}()|[\]\\]/g, '\\$&'); + // Convert placeholder back to '.*' for wildcard matching + let pattern = '^' + escaped.replace(new RegExp(placeholder, 'g'), '.*') + '$'; try { return new RegExp(pattern, 'i').test(str); } catch (e) { From f611e3a2c0ed4338457e4acddc7024f3779c3074 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 26 Nov 2025 15:07:19 +0100 Subject: [PATCH 23/27] OSD: use volume-x(volume-3) for 0% volume --- Commons/IconsTabler.qml | 1 + Modules/OSD/OSD.qml | 4 ++-- Services/Media/AudioService.qml | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Commons/IconsTabler.qml b/Commons/IconsTabler.qml index 7a0b5e80..21c7aa67 100644 --- a/Commons/IconsTabler.qml +++ b/Commons/IconsTabler.qml @@ -92,6 +92,7 @@ Singleton { "microphone": "microphone", "microphone-mute": "microphone-off", "volume-mute": "volume-off", + "volume-x": "volume-3", "volume-zero": "volume-3", "volume-low": "volume-2", "volume-high": "volume", diff --git a/Modules/OSD/OSD.qml b/Modules/OSD/OSD.qml index bbbff7fe..bde8b597 100644 --- a/Modules/OSD/OSD.qml +++ b/Modules/OSD/OSD.qml @@ -49,9 +49,9 @@ Variants { case OSD.Type.Volume: if (isMuted) return "volume-mute"; - // Show muted icon when volume is effectively 0% (within rounding threshold) + // Show volume-x icon when volume is effectively 0% (within rounding threshold) if (currentVolume < 0.005) - return "volume-mute"; + return "volume-x"; return currentVolume <= 0.5 ? "volume-low" : "volume-high"; case OSD.Type.InputVolume: return isInputMuted ? "microphone-off" : "microphone"; diff --git a/Services/Media/AudioService.qml b/Services/Media/AudioService.qml index 8ef66c22..efd7a287 100644 --- a/Services/Media/AudioService.qml +++ b/Services/Media/AudioService.qml @@ -206,9 +206,9 @@ Singleton { const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; const clampedVolume = Math.max(0, Math.min(volume, maxVolume)); - // Show muted icon when volume is effectively 0% (within rounding threshold) + // Show volume-x icon when volume is effectively 0% (within rounding threshold) if (clampedVolume < 0.005) - return "volume-mute"; + return "volume-x"; if (clampedVolume <= 0.5) return "volume-low"; return "volume-high"; From f10207a159c6e988cc9bf1201033324bfef2dfa7 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Wed, 26 Nov 2025 09:52:15 -0500 Subject: [PATCH 24/27] Settings / SetupWizard & OSD - Settings cleanup and avoid segfault by not using var. - SetupWizard simplified opening condition logic. Will only open when no settings available - OSD: simplified settings logic, updated translations to explain that no type selected = all types enabled. similar to bar and monitors logic. - Do not open changelog on a fresh install as we already open the SetupWizard --- Assets/Translations/de.json | 4 +- Assets/Translations/en.json | 10 +- Assets/Translations/es.json | 4 +- Assets/Translations/fr.json | 4 +- Assets/Translations/nl.json | 4 +- Assets/Translations/pt.json | 4 +- Assets/Translations/ru.json | 4 +- Assets/Translations/tr.json | 4 +- Assets/Translations/uk-UA.json | 4 +- Assets/Translations/zh-CN.json | 4 +- Assets/settings-default.json | 22 +- Commons/Settings.qml | 312 +++++++-------------- Modules/Panels/SetupWizard/SetupWizard.qml | 1 - Services/Noctalia/UpdateService.qml | 8 +- Services/UI/WallpaperService.qml | 2 +- shell.qml | 22 +- 16 files changed, 153 insertions(+), 260 deletions(-) diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index 321bf3e0..22e3bcd7 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -1690,8 +1690,8 @@ "label": "Feststelltasten" }, "section": { - "description": "Wähle, welche Ereignisse das On-Screen Display auslösen.", - "label": "OSD-Typen" + "description": "Wählen Sie die Ereignisse aus, die das OSD auslösen. Wenn keine Ereignisse ausgewählt werden, lösen alle verfügbaren Ereignisse das OSD aus.", + "label": "OSD-Auslöseereignisse" }, "volume": { "description": "OSD anzeigen, wenn sich die Ausgabelautstärke ändert.", diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index f9df474c..f80785e4 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -1683,19 +1683,19 @@ }, "input-volume": { "description": "Show OSD when microphone volume changes.", - "label": "Input Volume" + "label": "Input volume" }, "lockkey": { "description": "Show OSD when Caps Lock, Num Lock, or Scroll Lock are toggled.", - "label": "Lock Keys" + "label": "Lock keys" }, "section": { - "description": "Choose which events trigger the on-screen display.", - "label": "OSD Types" + "description": "Select the events that trigger the OSD. If no events are selected, all available events will trigger the OSD.", + "label": "OSD trigger events" }, "volume": { "description": "Show OSD when audio output volume changes.", - "label": "Output Volume" + "label": "Output volume" } } }, diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index c9b06176..b16b9401 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -1690,8 +1690,8 @@ "label": "Teclas de bloqueo" }, "section": { - "description": "Elige qué eventos activan la visualización en pantalla.", - "label": "Tipos de OSD" + "description": "Seleccione los eventos que activan el OSD. Si no se selecciona ningún evento, todos los eventos disponibles activarán el OSD.", + "label": "Eventos de activación OSD" }, "volume": { "description": "Mostrar el OSD cuando cambie el volumen de salida de audio.", diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 8a366f98..e132f1bb 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -1690,8 +1690,8 @@ "label": "Touches de verrouillage" }, "section": { - "description": "Choisissez quels événements déclenchent l'affichage à l'écran.", - "label": "Types d'OSD" + "description": "Sélectionnez les événements qui déclenchent l'OSD. Si aucun événement n'est sélectionné, tous les événements disponibles déclencheront l'OSD.", + "label": "Événements de déclenchement OSD" }, "volume": { "description": "Afficher l'OSD lorsque le volume de sortie audio change.", diff --git a/Assets/Translations/nl.json b/Assets/Translations/nl.json index c73c4978..4f76b493 100644 --- a/Assets/Translations/nl.json +++ b/Assets/Translations/nl.json @@ -1690,8 +1690,8 @@ "label": "Vergrendeltoetsen" }, "section": { - "description": "Kies welke gebeurtenissen de on-screenweergave activeren.", - "label": "OSD-typen" + "description": "Selecteer de gebeurtenissen die de OSD activeren. Als er geen gebeurtenissen zijn geselecteerd, activeren alle beschikbare gebeurtenissen de OSD.", + "label": "OSD triggergebeurtenissen" }, "volume": { "description": "Toon het OSD wanneer het uitvoervolume verandert.", diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index 540a9534..a3465840 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -1690,8 +1690,8 @@ "label": "Teclas de bloqueio" }, "section": { - "description": "Escolha quais eventos disparam a exibição na tela.", - "label": "Tipos de OSD" + "description": "Selecione os eventos que acionam o OSD. Se nenhum evento for selecionado, todos os eventos disponíveis acionarão o OSD.", + "label": "Eventos de disparo OSD" }, "volume": { "description": "Mostrar o OSD quando o volume de saída de áudio mudar.", diff --git a/Assets/Translations/ru.json b/Assets/Translations/ru.json index f361e5a5..1683694d 100644 --- a/Assets/Translations/ru.json +++ b/Assets/Translations/ru.json @@ -1690,8 +1690,8 @@ "label": "Клавиши блокировки" }, "section": { - "description": "Выберите события, которые запускают экранное отображение.", - "label": "Типы OSD" + "description": "Выберите события, которые должны запускать экранное меню (OSD). Если события не выбраны, экранное меню будет запускаться при любом доступном событии.", + "label": "События, запускающие экранное меню" }, "volume": { "description": "Показывать OSD при изменении громкости аудиовыхода.", diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json index 53e9b477..690ca4b2 100644 --- a/Assets/Translations/tr.json +++ b/Assets/Translations/tr.json @@ -1690,8 +1690,8 @@ "label": "Kilit tuşları" }, "section": { - "description": "Ekran göstergesini tetikleyen olayları seçin.", - "label": "OSD türleri" + "description": "OSD'yi tetikleyecek olayları seçin. Hiçbir olay seçilmezse, mevcut tüm olaylar OSD'yi tetikleyecektir.", + "label": "OSD tetikleme olayları" }, "volume": { "description": "Ses çıkış düzeyi değiştiğinde OSD'yi göster.", diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index ad73408d..26ca8d8f 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -1690,8 +1690,8 @@ "label": "Клавіші блокування" }, "section": { - "description": "Виберіть події, які запускають екранну індикацію.", - "label": "Типи OSD" + "description": "Виберіть події, які запускають екранне меню. Якщо жодну подію не вибрано, екранне меню запускатиметься всіма доступними подіями.", + "label": "Події, що запускають OSD" }, "volume": { "description": "Показувати OSD, коли змінюється гучність аудіовиходу.", diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 0f3b9926..454c54d6 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -1690,8 +1690,8 @@ "label": "锁定键" }, "section": { - "description": "选择哪些事件会触发屏显菜单。", - "label": "OSD 类型" + "description": "选择触发OSD的事件。如果未选择任何事件,则所有可用事件都将触发OSD。", + "label": "OSD触发事件" }, "volume": { "description": "当音频输出音量发生变化时显示 OSD。", diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 0cc60a46..2f8907a2 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -1,6 +1,5 @@ { - "settingsVersion": 24, - "setupCompleted": false, + "settingsVersion": 25, "bar": { "position": "top", "backgroundOpacity": 1, @@ -118,7 +117,6 @@ "enableMultiMonitorDirectories": false, "recursiveSearch": false, "setWallpaperOnAllMonitors": true, - "defaultWallpaper": "", "fillMode": "crop", "fillColor": "#000000", "randomEnabled": false, @@ -126,7 +124,6 @@ "transitionDuration": 1500, "transitionType": "random", "transitionEdgeSmoothness": 0.05, - "monitors": [], "panelPosition": "follow_bar", "hideWallpaperFilenames": false, "useWallhaven": false, @@ -137,7 +134,9 @@ "wallhavenPurity": "100", "wallhavenResolutionMode": "atleast", "wallhavenResolutionWidth": "", - "wallhavenResolutionHeight": "" + "wallhavenResolutionHeight": "", + "defaultWallpaper": "", + "monitors": [] }, "appLauncher": { "enableClipboardHistory": false, @@ -221,7 +220,7 @@ }, "dock": { "enabled": true, - "displayMode": "always_visible", + "displayMode": "auto_hide", "backgroundOpacity": 1, "radiusRatio": 0.1, "floatingRatio": 1, @@ -280,17 +279,12 @@ }, "osd": { "enabled": true, - "enabledTypes": [ - 0, - 1, - 2, - 3 - ], "location": "top_right", - "monitors": [], "autoHideMs": 2000, "overlayLayer": true, - "backgroundOpacity": 1 + "backgroundOpacity": 1, + "enabledTypes": [], + "monitors": [] }, "audio": { "volumeStep": 5, diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 2bbb1bae..69eb2c97 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -12,28 +12,30 @@ import qs.Services.UI Singleton { id: root - // Used to access via Settings.data.xxx.yyy - readonly property alias data: adapter property bool isLoaded: false property bool directoriesCreated: false - property int settingsVersion: 24 - property bool isDebug: Quickshell.env("NOCTALIA_DEBUG") === "1" + property bool shouldOpenSetupWizard: false - // Define our app directories - // Default config directory: ~/.config/noctalia - // Default cache directory: ~/.cache/noctalia - property string shellName: "noctalia" - property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/" - property string cacheDir: Quickshell.env("NOCTALIA_CACHE_DIR") || (Quickshell.env("XDG_CACHE_HOME") || Quickshell.env("HOME") + "/.cache") + "/" + shellName + "/" - property string cacheDirImages: cacheDir + "images/" - property string cacheDirImagesWallpapers: cacheDir + "images/wallpapers/" - property string cacheDirImagesNotifications: cacheDir + "images/notifications/" - property string settingsFile: Quickshell.env("NOCTALIA_SETTINGS_FILE") || (configDir + "settings.json") - - property string defaultLocation: "Tokyo" - property string defaultAvatar: Quickshell.env("HOME") + "/.face" - property string defaultVideosDirectory: Quickshell.env("HOME") + "/Videos" - property string defaultWallpapersDirectory: Quickshell.env("HOME") + "/Pictures/Wallpapers" + /* + Shell directories. + - Default config directory: ~/.config/noctalia + - Default cache directory: ~/.cache/noctalia + */ + readonly property alias data: adapter // Used to access via Settings.data.xxx.yyy + readonly property int settingsVersion: 25 + readonly property bool isDebug: Quickshell.env("NOCTALIA_DEBUG") === "1" + readonly property string shellName: "noctalia" + readonly property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/" + readonly property string cacheDir: Quickshell.env("NOCTALIA_CACHE_DIR") || (Quickshell.env("XDG_CACHE_HOME") || Quickshell.env("HOME") + "/.cache") + "/" + shellName + "/" + readonly property string cacheDirImages: cacheDir + "images/" + readonly property string cacheDirImagesWallpapers: cacheDir + "images/wallpapers/" + readonly property string cacheDirImagesNotifications: cacheDir + "images/notifications/" + readonly property string settingsFile: Quickshell.env("NOCTALIA_SETTINGS_FILE") || (configDir + "settings.json") + readonly property string defaultLocation: "Tokyo" + readonly property string defaultAvatar: Quickshell.env("HOME") + "/.face" + readonly property string defaultVideosDirectory: Quickshell.env("HOME") + "/Videos" + readonly property string defaultWallpapersDirectory: Quickshell.env("HOME") + "/Pictures/Wallpapers" + readonly property string defaultWallpaper: Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png" // Signal emitted when settings are loaded after startupcale changes signal settingsLoaded @@ -64,7 +66,6 @@ Singleton { adapter.general.avatarImage = defaultAvatar; adapter.screenRecorder.directory = defaultVideosDirectory; adapter.wallpaper.directory = defaultWallpapersDirectory; - adapter.wallpaper.defaultWallpaper = Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png"; // Set the adapter to the settingsFileView to trigger the real settings load settingsFileView.adapter = adapter; @@ -100,8 +101,8 @@ Singleton { Logger.i("Settings", "Settings loaded"); upgradeSettingsData(); - validateMonitorConfigurations(); - isLoaded = true; + + root.isLoaded = true; // Emit the signal root.settingsLoaded(); @@ -114,10 +115,14 @@ Singleton { if (error.toString().includes("No such file") || error === 2) { // File doesn't exist, create it with default values writeAdapter(); + // Also write to fallback if set if (Quickshell.env("NOCTALIA_SETTINGS_FALLBACK")) { settingsFallbackFileView.writeAdapter(); } + + // We started without settings, we should open the setupWizard + root.shouldOpenSetupWizard = true; } } } @@ -130,11 +135,11 @@ Singleton { printErrors: false watchChanges: false } + JsonAdapter { id: adapter property int settingsVersion: root.settingsVersion - property bool setupCompleted: false // bar property JsonObject bar: JsonObject { @@ -273,7 +278,6 @@ Singleton { property bool enableMultiMonitorDirectories: false property bool recursiveSearch: false property bool setWallpaperOnAllMonitors: true - property string defaultWallpaper: "" property string fillMode: "crop" property color fillColor: "#000000" property bool randomEnabled: false @@ -281,7 +285,6 @@ Singleton { property int transitionDuration: 1500 // 1500 ms property string transitionType: "random" property real transitionEdgeSmoothness: 0.05 - property list monitors: [] property string panelPosition: "follow_bar" property bool hideWallpaperFilenames: false // Wallhaven settings @@ -294,6 +297,9 @@ Singleton { property string wallhavenResolutionMode: "atleast" // "atleast" or "exact" property string wallhavenResolutionWidth: "" property string wallhavenResolutionHeight: "" + + property string defaultWallpaper: "" // TODO REMOVE + property list monitors: [] // TODO REMOVE } // applauncher @@ -389,7 +395,7 @@ Singleton { // dock property JsonObject dock: JsonObject { property bool enabled: true - property string displayMode: "always_visible" // "always_visible", "auto_hide", "exclusive" + property string displayMode: "auto_hide" // "always_visible", "auto_hide", "exclusive" property real backgroundOpacity: 1.0 property real radiusRatio: 0.1 property real floatingRatio: 1.0 @@ -457,12 +463,12 @@ Singleton { // on-screen display property JsonObject osd: JsonObject { property bool enabled: true - property var enabledTypes: [0, 1, 2, 3] property string location: "top_right" - property list monitors: [] property int autoHideMs: 2000 property bool overlayLayer: true property real backgroundOpacity: 1.0 + property list enabledTypes: [] + property list monitors: [] } // audio @@ -589,36 +595,39 @@ Singleton { } // ----------------------------------------------------- - // Function to validate monitor configurations - function validateMonitorConfigurations() { - var availableScreenNames = []; - for (var i = 0; i < Quickshell.screens.length; i++) { - availableScreenNames.push(Quickshell.screens[i].name); + // Function to clean up deprecated user/custom bar widgets settings + function upgradeWidget(widget) { + // Backup the widget definition before altering + const widgetBefore = JSON.stringify(widget); + + // Get all existing custom settings keys + const keys = Object.keys(BarWidgetRegistry.widgetMetadata[widget.id]); + + // Delete deprecated user settings from the wiget + for (const k of Object.keys(widget)) { + if (k === "id" || k === "allowUserSettings") { + continue; + } + if (!keys.includes(k)) { + delete widget[k]; + } } - Logger.d("Settings", "Available monitors: [" + availableScreenNames.join(", ") + "]"); - Logger.d("Settings", "Configured bar monitors: [" + adapter.bar.monitors.join(", ") + "]"); - - // Check bar monitors - if (adapter.bar.monitors.length > 0) { - var hasValidBarMonitor = false; - for (var j = 0; j < adapter.bar.monitors.length; j++) { - if (availableScreenNames.includes(adapter.bar.monitors[j])) { - hasValidBarMonitor = true; - break; - } + // Inject missing default setting (metaData) from BarWidgetRegistry + for (var i = 0; i < keys.length; i++) { + const k = keys[i]; + if (k === "id" || k === "allowUserSettings") { + continue; } - if (!hasValidBarMonitor) { - Logger.w("Settings", "No configured bar monitors found on system, clearing bar monitor list to show on all screens"); - adapter.bar.monitors = []; - } else - //Logger.i("Settings", "Found valid bar monitors, keeping configuration") - {} - } else + if (widget[k] === undefined) { + widget[k] = BarWidgetRegistry.widgetMetadata[widget.id][k]; + } + } - //Logger.i("Settings", "Bar monitor list is empty, will show on all available screens") - {} + // Compare settings, to detect if something has been upgraded + const widgetAfter = JSON.stringify(widget); + return (widgetAfter !== widgetBefore); } // ----------------------------------------------------- @@ -720,91 +729,7 @@ Singleton { } // ----------------- - // 5th. Migrate Discord templates (version 20 → 21) - // Consolidate individual discord_* properties into unified discord property - if (adapter.settingsVersion < 21) { - // Read raw JSON file to access properties not in adapter schema - try { - var rawJson = settingsFileView.text(); - - if (rawJson) { - var parsed = JSON.parse(rawJson); - var anyDiscordEnabled = false; - - // Check if any Discord client was enabled - const discordClients = ["discord_vesktop", "discord_webcord", "discord_armcord", "discord_equibop", "discord_lightcord", "discord_dorion", "discord_vencord"]; - - if (parsed.templates) { - for (var i = 0; i < discordClients.length; i++) { - if (parsed.templates[discordClients[i]]) { - anyDiscordEnabled = true; - break; - } - } - } - - // Set unified discord property - adapter.templates.discord = anyDiscordEnabled; - - Logger.i("Settings", "Migrated Discord templates to unified 'discord' property (enabled:", anyDiscordEnabled + ")"); - } - } catch (error) { - Logger.w("Settings", "Failed to read raw JSON for Discord migration:", error); - } - } - - // ----------------- - // 6th. Migrate panel background opacity (version 21 → 22) - // Move appLauncher.backgroundOpacity to ui.panelBackgroundOpacity - if (adapter.settingsVersion < 22) { - // Read raw JSON file to access properties not in adapter schema - try { - var rawJson = settingsFileView.text(); - - if (rawJson) { - var parsed = JSON.parse(rawJson); - if (parsed.appLauncher && parsed.appLauncher.backgroundOpacity !== undefined) { - var oldOpacity = parsed.appLauncher.backgroundOpacity; - if (adapter.ui) { - adapter.ui.panelBackgroundOpacity = oldOpacity; - Logger.i("Settings", "Migrated appLauncher.backgroundOpacity to ui.panelBackgroundOpacity (value:", oldOpacity + ")"); - } - } - } - } catch (error) { - Logger.w("Settings", "Failed to read raw JSON for migration:", error); - } - } - - // ----------------- - // 7th. Migrate dim desktop settings (version 22 → 23) - // If dimDesktop is enabled, set dimmerOpacity to 0.8 if it's not already set or is 0 - // Then remove dimDesktop property as it's no longer needed - if (adapter.settingsVersion < 23) { - // Read raw JSON file to access dimDesktop property - try { - var rawJson = settingsFileView.text(); - - if (rawJson) { - var parsed = JSON.parse(rawJson); - if (parsed.general && parsed.general.dimDesktop === true) { - // Check if dimmerOpacity exists in raw JSON (not adapter default) - var dimmerOpacityInJson = parsed.general.dimmerOpacity; - - // If dimmerOpacity wasn't explicitly set in JSON or was 0, set it to 0.8 (80% dimming) - if (dimmerOpacityInJson === undefined || dimmerOpacityInJson === 0) { - adapter.general.dimmerOpacity = 0.8; - Logger.i("Settings", "Migrated dimDesktop=true: set dimmerOpacity to 0.8 (80% dimming)"); - } - } - } - } catch (error) { - Logger.w("Settings", "Failed to read raw JSON for dimDesktop migration:", error); - } - } - - // ----------------- - // 9th. Normalize OSD enabled types and migrate legacy show* toggles + // TEMP Normalize OSD enabled types and migrate legacy show* toggles try { var osdRawJson = settingsFileView.text(); if (osdRawJson) { @@ -898,19 +823,49 @@ Singleton { // ----------------- // Migrate ShellState-related files from old cache files to ShellState - // This consolidates migrations that were previously in individual service files - if (typeof ShellState !== 'undefined' && ShellState.isLoaded) { - migrateShellStateFiles(); - } else { - // Wait for ShellState to be ready - Qt.callLater(() => { - if (typeof ShellState !== 'undefined' && ShellState.isLoaded) { - migrateShellStateFiles(); - } - }); + // This consolidates migrations that were previously in individual files + if (adapter.settingsVersion < 25) { + // Only migrate the settings once! + if (ShellState?.isLoaded) { + migrateShellStateFiles(); + } else { + // Wait for ShellState to be ready + Qt.callLater(() => { + if (ShellState?.isLoaded) { + migrateShellStateFiles(); + } + }); + } } } + // ----------------------------------------------------- + function buildStateSnapshot() { + try { + const settingsData = QtObj2JS.qtObjectToPlainObject(adapter); + const shellStateData = ShellState?.data ? QtObj2JS.qtObjectToPlainObject(ShellState.data) || {} : {}; + + return { + settings: settingsData, + state: { + doNotDisturb: NotificationService.doNotDisturb, + noctaliaPerformanceMode: PowerProfileService.noctaliaPerformanceMode, + barVisible: BarService.isVisible, + display: shellStateData.display || {}, + wallpapers: shellStateData.wallpapers || {}, + notificationsState: shellStateData.notificationsState || {}, + changelogState: shellStateData.changelogState || {}, + colorSchemesList: shellStateData.colorSchemesList || {} + } + }; + } catch (error) { + Logger.e("Settings", "Failed to build state snapshot:", error); + return null; + } + } + + // ----------------------------------------------------- + // --- TO BE REMOVED // ----------------------------------------------------- // Migrate old cache files to ShellState function migrateShellStateFiles() { @@ -930,6 +885,7 @@ Singleton { migrateWallpaperPaths(); } + // ----------------------------------------------------- function migrateDisplayFile() { // Check if ShellState already has display data const cached = ShellState.getDisplay(); @@ -963,6 +919,7 @@ Singleton { `, root, "displayMigrationView"); } + // ----------------------------------------------------- function migrateNotificationsStateFile() { // Check if ShellState already has notifications state const cached = ShellState.getNotificationsState(); @@ -1110,63 +1067,4 @@ Singleton { } } } - - // ----------------------------------------------------- - function upgradeWidget(widget) { - // Backup the widget definition before altering - const widgetBefore = JSON.stringify(widget); - - // Get all existing custom settings keys - const keys = Object.keys(BarWidgetRegistry.widgetMetadata[widget.id]); - - // Delete deprecated user settings from the wiget - for (const k of Object.keys(widget)) { - if (k === "id" || k === "allowUserSettings") { - continue; - } - if (!keys.includes(k)) { - delete widget[k]; - } - } - - // Inject missing default setting (metaData) from BarWidgetRegistry - for (var i = 0; i < keys.length; i++) { - const k = keys[i]; - if (k === "id" || k === "allowUserSettings") { - continue; - } - - if (widget[k] === undefined) { - widget[k] = BarWidgetRegistry.widgetMetadata[widget.id][k]; - } - } - - // Compare settings, to detect if something has been upgraded - const widgetAfter = JSON.stringify(widget); - return (widgetAfter !== widgetBefore); - } - - function buildStateSnapshot() { - try { - const settingsData = QtObj2JS.qtObjectToPlainObject(adapter); - const shellStateData = (typeof ShellState !== "undefined" && ShellState.data) ? QtObj2JS.qtObjectToPlainObject(ShellState.data) || {} : {}; - - return { - settings: settingsData, - state: { - doNotDisturb: NotificationService.doNotDisturb, - noctaliaPerformanceMode: PowerProfileService.noctaliaPerformanceMode, - barVisible: BarService.isVisible, - display: shellStateData.display || {}, - wallpapers: shellStateData.wallpapers || {}, - notificationsState: shellStateData.notificationsState || {}, - changelogState: shellStateData.changelogState || {}, - colorSchemesList: shellStateData.colorSchemesList || {} - } - }; - } catch (error) { - Logger.e("Settings", "Failed to build state snapshot:", error); - return null; - } - } } diff --git a/Modules/Panels/SetupWizard/SetupWizard.qml b/Modules/Panels/SetupWizard/SetupWizard.qml index fc64cc86..7addb49f 100644 --- a/Modules/Panels/SetupWizard/SetupWizard.qml +++ b/Modules/Panels/SetupWizard/SetupWizard.qml @@ -401,7 +401,6 @@ SmartPanel { Settings.data.general.scaleRatio = selectedScaleRatio; Settings.data.bar.position = selectedBarPosition; - Settings.data.setupCompleted = true; // Save settings immediately and wait for settingsSaved signal before closing Settings.saveImmediate(); diff --git a/Services/Noctalia/UpdateService.qml b/Services/Noctalia/UpdateService.qml index ce8fc292..bfee6f67 100644 --- a/Services/Noctalia/UpdateService.qml +++ b/Services/Noctalia/UpdateService.qml @@ -79,6 +79,12 @@ Singleton { const fromVersion = changelogFromVersion || ""; const toVersion = changelogToVersion || ""; + if (Settings.shouldOpenSetupWizard) { + // If you'll see the setup wizard then you don't need to see the changelog + markChangelogSeen(toVersion); + return; + } + if (!toVersion) return; @@ -116,7 +122,7 @@ Singleton { // 'from' always need to be before 'to' // handle edge case that will show up as we changed -dev to -git - if (from === to) { + if (from >= to) { from = "v3.0.0"; } diff --git a/Services/UI/WallpaperService.qml b/Services/UI/WallpaperService.qml index a5487596..f6c5cc4a 100644 --- a/Services/UI/WallpaperService.qml +++ b/Services/UI/WallpaperService.qml @@ -250,7 +250,7 @@ Singleton { // ------------------------------------------------------------------- // Get specific monitor wallpaper - now from cache function getWallpaper(screenName) { - return currentWallpapers[screenName] || Settings.data.wallpaper.defaultWallpaper; + return currentWallpapers[screenName] || Settings.defaultWallpaper; } // ------------------------------------------------------------------- diff --git a/shell.qml b/shell.qml index b542c95a..8f750704 100644 --- a/shell.qml +++ b/shell.qml @@ -71,7 +71,7 @@ ShellRoot { } Connections { - target: typeof ShellState !== 'undefined' ? ShellState : null + target: ShellState ? ShellState : null function onIsLoadedChanged() { if (ShellState.isLoaded) { shellStateLoaded = true; @@ -100,10 +100,7 @@ ShellRoot { UpdateService.init(); UpdateService.showLatestChangelog(); - // Only open the setup wizard for new users - if (!Settings.data.setupCompleted) { - checkSetupWizard(); - } + checkSetupWizard(); } Overview {} @@ -134,7 +131,12 @@ ShellRoot { } function checkSetupWizard() { - // Wait for distro service + // Only open the setup wizard for new users + if (!Settings.shouldOpenSetupWizard) { + return; + } + + // Wait for HostService to be fully ready if (!HostService.isReady) { Qt.callLater(checkSetupWizard); return; @@ -142,16 +144,10 @@ ShellRoot { // No setup wizard on NixOS if (HostService.isNixOS) { - Settings.data.setupCompleted = true; return; } - if (Settings.data.settingsVersion >= Settings.settingsVersion) { - setupWizardTimer.start(); - } else { - Settings.data.setupCompleted = true; - Settings.saveImmediate(); - } + setupWizardTimer.start(); } function showSetupWizard() { From f79aad5f0ed23589c50da293215e256310c51c96 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Wed, 26 Nov 2025 11:46:29 -0500 Subject: [PATCH 25/27] CREDITS.md --- CREDITS.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 CREDITS.md diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 00000000..790e4c7e --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,54 @@ +# Credits + +Noctalia Shell is made possible by the incredible work of many open-source projects and contributors. + +## Design & Branding + +- **MrDowntempo** - Creator of the Noctalia Owl and moon logo +- **SaberJ2X** - Creator of Talia, the Noctalia mascot + +## Core Framework + +- **[Quickshell](https://github.com/outfoxxed/quickshell)** - The Qt/QML-based Wayland shell framework that powers Noctalia + +## Runtime Dependencies + +### System Integration +- **[brightnessctl](https://github.com/Hummer12007/brightnessctl)** - Screen brightness control +- **[wlsunset](https://sr.ht/~kennylevinsen/wlsunset/)** - Night light and blue light filter support +- **[wl-clipboard](https://github.com/bugaevc/wl-clipboard)** - Wayland clipboard utilities +- **[ddcutil](https://www.ddcutil.com/)** - External display brightness control (optional) +- **[power-profiles-daemon](https://gitlab.freedesktop.org/upower/power-profiles-daemon)** - Power profile management (optional) + +### Media & Audio +- **[gpu-screen-recorder](https://git.dec05eba.com/gpu-screen-recorder/about/)** - Hardware-accelerated screen recording +- **[Cava](https://github.com/karlstav/cava)** - Audio visualizer component (optional) + +### Theming & Appearance +- **[Matugen](https://github.com/InioX/matugen)** - Material You color scheme generation from wallpapers +- **[Inter Font](https://rsms.me/inter/)** - UI font family +- **[Roboto](https://fonts.google.com/specimen/Roboto)** - Additional UI font family + +### Utilities +- **[cliphist](https://github.com/sentriz/cliphist)** - Clipboard history support (optional) + +## Audio Assets + +- **[DrNI on Freesound](https://freesound.org/people/DrNI/sounds/34562/)** - Notification sound effect + +## Build Dependencies + +- **[Qt 6](https://www.qt.io/)** - Cross-platform application framework +- **Git** - Version control and development + +## Special Thanks + +- The **Wayland** community for building the future of Linux desktop graphics +- The **Niri**, **Hyprland**, **Sway**, and **MangoWC** teams for their excellent Wayland compositors +- All the contributors and users who have helped make Noctalia better + +## License + +Noctalia Shell is licensed under the MIT License. See [LICENSE](LICENSE) for details. + +Each dependency listed above is governed by its own respective license. Please refer to their individual projects for licensing information. From 4d72a0bd0cc666a8d0c9d2e3588880151c0ffbce Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Wed, 26 Nov 2025 11:51:45 -0500 Subject: [PATCH 26/27] Credits: minor cleanup --- CREDITS.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 790e4c7e..7c37cb0e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -17,12 +17,12 @@ Noctalia Shell is made possible by the incredible work of many open-source proje - **[brightnessctl](https://github.com/Hummer12007/brightnessctl)** - Screen brightness control - **[wlsunset](https://sr.ht/~kennylevinsen/wlsunset/)** - Night light and blue light filter support - **[wl-clipboard](https://github.com/bugaevc/wl-clipboard)** - Wayland clipboard utilities -- **[ddcutil](https://www.ddcutil.com/)** - External display brightness control (optional) -- **[power-profiles-daemon](https://gitlab.freedesktop.org/upower/power-profiles-daemon)** - Power profile management (optional) +- **[ddcutil](https://www.ddcutil.com/)** - External display brightness control +- **[power-profiles-daemon](https://gitlab.freedesktop.org/upower/power-profiles-daemon)** - Power profile management ### Media & Audio - **[gpu-screen-recorder](https://git.dec05eba.com/gpu-screen-recorder/about/)** - Hardware-accelerated screen recording -- **[Cava](https://github.com/karlstav/cava)** - Audio visualizer component (optional) +- **[Cava](https://github.com/karlstav/cava)** - Audio visualizer component ### Theming & Appearance - **[Matugen](https://github.com/InioX/matugen)** - Material You color scheme generation from wallpapers @@ -30,16 +30,12 @@ Noctalia Shell is made possible by the incredible work of many open-source proje - **[Roboto](https://fonts.google.com/specimen/Roboto)** - Additional UI font family ### Utilities -- **[cliphist](https://github.com/sentriz/cliphist)** - Clipboard history support (optional) +- **[cliphist](https://github.com/sentriz/cliphist)** - Clipboard history support ## Audio Assets - **[DrNI on Freesound](https://freesound.org/people/DrNI/sounds/34562/)** - Notification sound effect -## Build Dependencies - -- **[Qt 6](https://www.qt.io/)** - Cross-platform application framework -- **Git** - Version control and development ## Special Thanks From 7f9bb6f0a58fb8284ca66c9be2787fed270fb2ec Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Wed, 26 Nov 2025 12:29:13 -0500 Subject: [PATCH 27/27] Credits: saber --- CREDITS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CREDITS.md b/CREDITS.md index 7c37cb0e..a71a8368 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -5,7 +5,7 @@ Noctalia Shell is made possible by the incredible work of many open-source proje ## Design & Branding - **MrDowntempo** - Creator of the Noctalia Owl and moon logo -- **SaberJ2X** - Creator of Talia, the Noctalia mascot +- **[SaberJ2X](https://www.reddit.com/user/SaberJ64/)** - Creator of Talia, the Noctalia mascot ## Core Framework