diff --git a/.github/workflows/update-aur-package.yml b/.github/workflows/update-aur-package.yml
new file mode 100644
index 00000000..7978e188
--- /dev/null
+++ b/.github/workflows/update-aur-package.yml
@@ -0,0 +1,110 @@
+name: Update AUR Package
+
+on:
+ push:
+ tags:
+ - 'v*'
+ workflow_dispatch:
+
+jobs:
+ aur-sync:
+ name: Sync PKGBUILD with release
+ runs-on: ubuntu-latest
+ container:
+ image: archlinux:latest
+ defaults:
+ run:
+ shell: bash
+ env:
+ AUR_REPO: ssh://aur@aur.archlinux.org/noctalia-shell.git
+ GIT_SSH_COMMAND: ssh -i /root/.ssh/id_aur -o StrictHostKeyChecking=yes -o IdentitiesOnly=yes
+ PKGNAME: noctalia-shell
+ AUR_LINK: https://aur.archlinux.org/packages/noctalia-shell
+
+ steps:
+ - name: Install dependencies
+ run: |
+ set -euo pipefail
+ pacman -Syu --noconfirm git base-devel pacman-contrib openssh
+
+ - name: Create build user
+ run: |
+ set -euo pipefail
+ useradd -m builduser
+ echo 'builduser ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
+
+ - name: Configure SSH
+ env:
+ AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
+ run: |
+ set -euo pipefail
+ mkdir -p /root/.ssh
+ chmod 700 /root/.ssh
+ printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > /root/.ssh/id_aur
+ chmod 600 /root/.ssh/id_aur
+ ssh-keyscan aur.archlinux.org >> /root/.ssh/known_hosts
+ chmod 600 /root/.ssh/known_hosts
+
+ - name: Determine version
+ id: vars
+ env:
+ TAG_NAME: ${{ github.ref_name }}
+ run: |
+ set -euo pipefail
+ PKGVER="${TAG_NAME#v}"
+ echo "pkgver=$PKGVER" >> "$GITHUB_OUTPUT"
+
+ - name: Clone AUR repository
+ run: |
+ set -euo pipefail
+ git clone "$AUR_REPO" "$GITHUB_WORKSPACE/aur"
+
+ - name: Update PKGBUILD
+ env:
+ PKGVER: ${{ steps.vars.outputs.pkgver }}
+ working-directory: ${{ github.workspace }}/aur
+ run: |
+ set -euo pipefail
+ sed -i "s/^pkgver=.*/pkgver=${PKGVER}/" PKGBUILD
+ sed -i "s/^pkgrel=.*/pkgrel=1/" PKGBUILD
+
+ - name: Refresh checksums and metadata
+ env:
+ AUR_DIR: ${{ github.workspace }}/aur
+ run: |
+ set -euo pipefail
+ chown -R builduser:builduser "$AUR_DIR"
+ su - builduser -c "cd $AUR_DIR && updpkgsums"
+ su - builduser -c "cd $AUR_DIR && makepkg --printsrcinfo > .SRCINFO"
+
+ - name: Commit and push changes
+ env:
+ PKGVER: ${{ steps.vars.outputs.pkgver }}
+ working-directory: ${{ github.workspace }}/aur
+ run: |
+ set -euo pipefail
+ git config --global --add safe.directory "$PWD"
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ if [[ -n "$(git status --porcelain)" ]]; then
+ git add PKGBUILD .SRCINFO
+ git commit -m "chore(package): release ${PKGVER}"
+ git push origin HEAD
+ else
+ echo "No updates necessary."
+ fi
+
+ - name: Summarize update
+ env:
+ PKGNAME: noctalia-shell
+ PKGVER: ${{ steps.vars.outputs.pkgver }}
+ AUR_LINK: https://aur.archlinux.org/packages/noctalia-shell
+ run: |
+ set -euo pipefail
+ {
+ echo "## AUR Update"
+ echo ""
+ echo "- Package: ${PKGNAME}"
+ echo "- Updated version: ${PKGVER}"
+ echo "- AUR page: ${AUR_LINK}"
+ } >> "$GITHUB_STEP_SUMMARY"
\ No newline at end of file
diff --git a/Assets/ColorScheme/Aya.json b/Assets/ColorScheme/Ayu.json
similarity index 100%
rename from Assets/ColorScheme/Aya.json
rename to Assets/ColorScheme/Ayu.json
diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json
index d3678692..9137fef8 100644
--- a/Assets/Translations/de.json
+++ b/Assets/Translations/de.json
@@ -31,6 +31,10 @@
"animation-speed": {
"label": "Animationsgeschwindigkeit",
"description": "Globale Animationsgeschwindigkeit anpassen."
+ },
+ "animation-disable": {
+ "label": "UI-Animationen deaktivieren",
+ "description": "Alle Animationen für eine schnellere, reaktionsschnellere Erfahrung deaktivieren."
}
},
"screen-corners": {
@@ -478,12 +482,16 @@
"enable-matugen": {
"label": "Matugen aktivieren",
"description": "Automatisch Farben basierend auf Ihrem aktiven Hintergrundbild generieren."
+ },
+ "matugen-scheme-type": {
+ "label": "Matugen-Schema-Typ",
+ "description": "Wähle einen Farbstil für Matugen aus."
}
},
"predefined": {
"section": {
"label": "Vordefinierte Farbschemata",
- "description": "Um diese Farbschemata zu verwenden, müssen Sie Matugen ausschalten. Mit aktiviertem Matugen werden Farben automatisch aus Ihrem Hintergrundbild generiert."
+ "description": "Wählen Sie aus einer Sammlung vordefinierter Farbschemata."
}
},
"matugen": {
@@ -825,21 +833,54 @@
"search-placeholder": "Widgets suchen..."
},
"active-window": {
- "auto-hide": "Automatisch ausblenden",
- "scrolling-mode": "Scrollmodus",
- "show-app-icon": "App-Symbol anzeigen"
+ "auto-hide": {
+ "label": "Automatisch ausblenden",
+ "description": "Widget automatisch ausblenden, wenn kein Fenster aktiv ist."
+ },
+ "show-app-icon": {
+ "label": "App-Symbol anzeigen",
+ "description": "Anwendungssymbol neben dem Fenstertitel anzeigen."
+ },
+ "scrolling-mode": {
+ "label": "Scrollmodus",
+ "description": "Steuern, wann Textscrolling für lange Fenstertitel aktiviert ist."
+ }
},
"system-monitor": {
- "cpu-usage": "CPU-Auslastung",
- "cpu-temperature": "CPU-Temperatur",
- "memory-usage": "Speicherverbrauch",
- "memory-percentage": "Speicher als Prozentsatz",
- "network-traffic": "Netzwerkverkehr",
- "storage-usage": "Speichernutzung"
+ "cpu-usage": {
+ "label": "CPU-Auslastung",
+ "description": "Aktuelle CPU-Auslastung in Prozent anzeigen."
+ },
+ "cpu-temperature": {
+ "label": "CPU-Temperatur",
+ "description": "CPU-Temperaturwerte anzeigen, falls verfügbar."
+ },
+ "memory-usage": {
+ "label": "Speicherverbrauch",
+ "description": "Aktuelle RAM-Nutzungsinformationen anzeigen."
+ },
+ "memory-percentage": {
+ "label": "Speicher als Prozentsatz",
+ "description": "Speicherverbrauch als Prozentsatz statt absolute Werte anzeigen."
+ },
+ "network-traffic": {
+ "label": "Netzwerkverkehr",
+ "description": "Upload- und Download-Geschwindigkeiten anzeigen."
+ },
+ "storage-usage": {
+ "label": "Speichernutzung",
+ "description": "Festplattenspeicher-Nutzungsinformationen anzeigen."
+ }
},
"notification-history": {
- "show-unread-badge": "Badge für ungelesene Nachrichten anzeigen",
- "hide-badge-when-zero": "Badge ausblenden, wenn null"
+ "show-unread-badge": {
+ "label": "Badge für ungelesene Nachrichten anzeigen",
+ "description": "Badge mit der Anzahl ungelesener Benachrichtigungen anzeigen."
+ },
+ "hide-badge-when-zero": {
+ "label": "Badge ausblenden, wenn null",
+ "description": "Benachrichtigungs-Badge ausblenden, wenn keine ungelesenen Benachrichtigungen vorhanden sind."
+ }
},
"battery": {
"display-mode": {
@@ -852,7 +893,10 @@
}
},
"control-center": {
- "use-distro-logo": "Distro-Logo anstelle von Symbol verwenden",
+ "use-distro-logo": {
+ "label": "Distro-Logo anstelle von Symbol verwenden",
+ "description": "Logo Ihrer Distribution anstelle eines benutzerdefinierten Symbols verwenden."
+ },
"icon": {
"label": "Symbol",
"description": "Symbol aus der Bibliothek oder eine benutzerdefinierte Datei auswählen."
@@ -874,7 +918,10 @@
}
},
"workspace": {
- "label-mode": "Beschriftungsmodus",
+ "label-mode": {
+ "label": "Beschriftungsmodus",
+ "description": "Wählen Sie, wie Arbeitsbereichs-Beschriftungen angezeigt werden."
+ },
"hide-unoccupied": {
"label": "Unbesetzte ausblenden",
"description": "Arbeitsbereiche ohne Fenster nicht anzeigen."
@@ -904,9 +951,18 @@
"description": "Symbol aus der Bibliothek auswählen."
},
"browse": "Durchsuchen",
- "left-click": "Linksklick",
- "right-click": "Rechtsklick",
- "middle-click": "Mittelklick",
+ "left-click": {
+ "label": "Linksklick",
+ "description": "Befehl, der ausgeführt wird, wenn die Schaltfläche links angeklickt wird."
+ },
+ "right-click": {
+ "label": "Rechtsklick",
+ "description": "Befehl, der ausgeführt wird, wenn die Schaltfläche rechts angeklickt wird."
+ },
+ "middle-click": {
+ "label": "Mittelklick",
+ "description": "Befehl, der ausgeführt wird, wenn die Schaltfläche mit der mittleren Maustaste angeklickt wird."
+ },
"dynamic-text": "Dynamischer Text",
"display-command-output": {
"label": "Befehlsausgabe anzeigen",
@@ -918,11 +974,26 @@
}
},
"media-mini": {
- "auto-hide": "Automatisch ausblenden",
- "show-album-art": "Albumcover anzeigen",
- "show-visualizer": "Visualizer anzeigen",
- "visualizer-type": "Visualizer-Typ",
- "scrolling-mode": "Scrollmodus"
+ "auto-hide": {
+ "label": "Automatisch ausblenden",
+ "description": "Widget automatisch ausblenden, wenn keine Medien abgespielt werden."
+ },
+ "show-album-art": {
+ "label": "Albumcover anzeigen",
+ "description": "Albumcover des aktuell abgespielten Tracks anzeigen."
+ },
+ "show-visualizer": {
+ "label": "Visualizer anzeigen",
+ "description": "Audio-Visualizer anzeigen, wenn Musik abgespielt wird."
+ },
+ "visualizer-type": {
+ "label": "Visualizer-Typ",
+ "description": "Stil des Audio-Visualizers auswählen."
+ },
+ "scrolling-mode": {
+ "label": "Scrollmodus",
+ "description": "Steuern, wann Textscrolling für lange Track-Titel aktiviert ist."
+ }
},
"clock": {
"use-primary-color": {
diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json
index 18bb5ce1..5f2e156e 100644
--- a/Assets/Translations/en.json
+++ b/Assets/Translations/en.json
@@ -31,6 +31,10 @@
"animation-speed": {
"label": "Animation speed",
"description": "Adjust global animation speed."
+ },
+ "animation-disable": {
+ "label": "Disable UI Animations",
+ "description": "Disable all animations for a faster, more responsive experience."
}
},
"screen-corners": {
@@ -478,12 +482,16 @@
"enable-matugen": {
"label": "Enable Matugen",
"description": "Automatically generate colors based on your active wallpaper."
+ },
+ "matugen-scheme-type": {
+ "label": "Matugen scheme type",
+ "description": "Choose the color scheme generation algorithm for Matugen."
}
},
"predefined": {
"section": {
"label": "Predefined color schemes",
- "description": "To use these color schemes, you must turn off Matugen. With Matugen enabled, colors are automatically generated from your wallpaper."
+ "description": "Choose from a collection of predefined color schemes."
}
},
"matugen": {
@@ -808,21 +816,54 @@
"search-placeholder": "Search widget..."
},
"active-window": {
- "auto-hide": "Hide automatically",
- "show-app-icon": "Show app icon",
- "scrolling-mode": "Scrolling mode"
+ "auto-hide": {
+ "label": "Hide automatically",
+ "description": "Automatically hide the widget when no window is active."
+ },
+ "show-app-icon": {
+ "label": "Show app icon",
+ "description": "Display the application icon next to the window title."
+ },
+ "scrolling-mode": {
+ "label": "Scrolling mode",
+ "description": "Control when text scrolling is enabled for long window titles."
+ }
},
"system-monitor": {
- "cpu-usage": "CPU usage",
- "cpu-temperature": "CPU temperature",
- "memory-usage": "Memory usage",
- "memory-percentage": "Memory as percentage",
- "network-traffic": "Network traffic",
- "storage-usage": "Storage usage"
+ "cpu-usage": {
+ "label": "CPU usage",
+ "description": "Display current CPU usage percentage."
+ },
+ "cpu-temperature": {
+ "label": "CPU temperature",
+ "description": "Show CPU temperature readings if available."
+ },
+ "memory-usage": {
+ "label": "Memory usage",
+ "description": "Display current RAM usage information."
+ },
+ "memory-percentage": {
+ "label": "Memory as percentage",
+ "description": "Show memory usage as a percentage instead of absolute values."
+ },
+ "network-traffic": {
+ "label": "Network traffic",
+ "description": "Display network upload and download speeds."
+ },
+ "storage-usage": {
+ "label": "Storage usage",
+ "description": "Show disk space usage information."
+ }
},
"notification-history": {
- "show-unread-badge": "Show unread badge",
- "hide-badge-when-zero": "Hide badge when zero"
+ "show-unread-badge": {
+ "label": "Show unread badge",
+ "description": "Display a badge showing the number of unread notifications."
+ },
+ "hide-badge-when-zero": {
+ "label": "Hide badge when zero",
+ "description": "Hide the notification badge when there are no unread notifications."
+ }
},
"battery": {
"display-mode": {
@@ -835,7 +876,10 @@
}
},
"control-center": {
- "use-distro-logo": "Use distro logo instead of icon",
+ "use-distro-logo": {
+ "label": "Use distro logo instead of icon",
+ "description": "Use your distribution's logo instead of a custom icon."
+ },
"icon": {
"label": "Icon",
"description": "Select an icon from the library or a custom file."
@@ -857,7 +901,10 @@
}
},
"workspace": {
- "label-mode": "Label Mode",
+ "label-mode": {
+ "label": "Label Mode",
+ "description": "Choose how workspace labels are displayed."
+ },
"hide-unoccupied": {
"label": "Hide unoccupied",
"description": "Don't display workspaces without windows."
@@ -887,9 +934,18 @@
"description": "Select an icon from the library."
},
"browse": "Browse",
- "left-click": "Left click",
- "right-click": "Right click",
- "middle-click": "Middle click",
+ "left-click": {
+ "label": "Left click",
+ "description": "Command to execute when the button is left-clicked."
+ },
+ "right-click": {
+ "label": "Right click",
+ "description": "Command to execute when the button is right-clicked."
+ },
+ "middle-click": {
+ "label": "Middle click",
+ "description": "Command to execute when the button is middle-clicked."
+ },
"dynamic-text": "Dynamic text",
"display-command-output": {
"label": "Display Command Output",
@@ -901,11 +957,26 @@
}
},
"media-mini": {
- "auto-hide": "Hide automatically",
- "show-album-art": "Show album art",
- "show-visualizer": "Show visualizer",
- "visualizer-type": "Visualizer type",
- "scrolling-mode": "Scrolling mode"
+ "auto-hide": {
+ "label": "Hide automatically",
+ "description": "Automatically hide the widget when no media is playing."
+ },
+ "show-album-art": {
+ "label": "Show album art",
+ "description": "Display the album artwork for the currently playing track."
+ },
+ "show-visualizer": {
+ "label": "Show visualizer",
+ "description": "Display an audio visualizer when music is playing."
+ },
+ "visualizer-type": {
+ "label": "Visualizer type",
+ "description": "Choose the style of audio visualizer to display."
+ },
+ "scrolling-mode": {
+ "label": "Scrolling mode",
+ "description": "Control when text scrolling is enabled for long track titles."
+ }
},
"clock": {
"use-primary-color": {
diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json
index 574484ba..e5afc18c 100644
--- a/Assets/Translations/es.json
+++ b/Assets/Translations/es.json
@@ -29,6 +29,10 @@
"animation-speed": {
"label": "Velocidad de la animación",
"description": "Ajusta la velocidad de la animación global."
+ },
+ "animation-disable": {
+ "label": "Desactivar animaciones de UI",
+ "description": "Desactivar todas las animaciones para una experiencia más rápida y responsiva."
}
},
"screen-corners": {
@@ -476,12 +480,16 @@
"enable-matugen": {
"label": "Activar Matugen",
"description": "Genera colores automáticamente basados en tu fondo de pantalla activo."
+ },
+ "matugen-scheme-type": {
+ "label": "Tipo de esquema Matugen",
+ "description": "Elige el algoritmo de generación de esquema de colores para Matugen."
}
},
"predefined": {
"section": {
"label": "Esquemas de colores predefinidos",
- "description": "Para usar estos esquemas de colores, debes desactivar Matugen. Con Matugen activado, los colores se generan automáticamente a partir de tu fondo de pantalla."
+ "description": "Elige entre una colección de esquemas de colores predefinidos."
}
},
"matugen": {
@@ -806,21 +814,54 @@
"search-placeholder": "Buscar widgets..."
},
"active-window": {
- "auto-hide": "Ocultar automáticamente",
- "show-app-icon": "Mostrar icono de la aplicación",
- "scrolling-mode": "Modo de desplazamiento"
+ "auto-hide": {
+ "label": "Ocultar automáticamente",
+ "description": "Ocultar automáticamente el widget cuando no hay ventana activa."
+ },
+ "show-app-icon": {
+ "label": "Mostrar icono de la aplicación",
+ "description": "Mostrar el icono de la aplicación junto al título de la ventana."
+ },
+ "scrolling-mode": {
+ "label": "Modo de desplazamiento",
+ "description": "Controlar cuándo está habilitado el desplazamiento de texto para títulos de ventana largos."
+ }
},
"system-monitor": {
- "cpu-usage": "Uso de CPU",
- "cpu-temperature": "Temperatura de la CPU",
- "memory-usage": "Uso de memoria",
- "memory-percentage": "Memoria como porcentaje",
- "network-traffic": "Tráfico de red",
- "storage-usage": "Uso de almacenamiento"
+ "cpu-usage": {
+ "label": "Uso de CPU",
+ "description": "Mostrar el porcentaje actual de uso de CPU."
+ },
+ "cpu-temperature": {
+ "label": "Temperatura de la CPU",
+ "description": "Mostrar lecturas de temperatura de CPU si están disponibles."
+ },
+ "memory-usage": {
+ "label": "Uso de memoria",
+ "description": "Mostrar información actual del uso de RAM."
+ },
+ "memory-percentage": {
+ "label": "Memoria como porcentaje",
+ "description": "Mostrar el uso de memoria como porcentaje en lugar de valores absolutos."
+ },
+ "network-traffic": {
+ "label": "Tráfico de red",
+ "description": "Mostrar velocidades de carga y descarga de la red."
+ },
+ "storage-usage": {
+ "label": "Uso de almacenamiento",
+ "description": "Mostrar información del uso del espacio en disco."
+ }
},
"notification-history": {
- "show-unread-badge": "Mostrar insignia de no leídos",
- "hide-badge-when-zero": "Ocultar insignia cuando es cero"
+ "show-unread-badge": {
+ "label": "Mostrar insignia de no leídos",
+ "description": "Mostrar una insignia con el número de notificaciones no leídas."
+ },
+ "hide-badge-when-zero": {
+ "label": "Ocultar insignia cuando es cero",
+ "description": "Ocultar la insignia de notificaciones cuando no hay notificaciones no leídas."
+ }
},
"battery": {
"display-mode": {
@@ -833,7 +874,10 @@
}
},
"control-center": {
- "use-distro-logo": "Usar logo de la distro en lugar del icono",
+ "use-distro-logo": {
+ "label": "Usar logo de la distribución en lugar de icono",
+ "description": "Usar el logo de tu distribución en lugar de un icono personalizado."
+ },
"icon": {
"label": "Icono",
"description": "Selecciona un icono de la biblioteca o un archivo personalizado."
@@ -855,7 +899,10 @@
}
},
"workspace": {
- "label-mode": "Modo de etiqueta",
+ "label-mode": {
+ "label": "Modo de etiqueta",
+ "description": "Elegir cómo se muestran las etiquetas de los espacios de trabajo."
+ },
"hide-unoccupied": {
"label": "Ocultar desocupados",
"description": "No mostrar espacios de trabajo sin ventanas."
@@ -885,9 +932,18 @@
"description": "Selecciona un icono de la biblioteca."
},
"browse": "Explorar",
- "left-click": "Clic izquierdo",
- "right-click": "Clic derecho",
- "middle-click": "Clic central",
+ "left-click": {
+ "label": "Clic izquierdo",
+ "description": "Comando a ejecutar cuando se hace clic izquierdo en el botón."
+ },
+ "right-click": {
+ "label": "Clic derecho",
+ "description": "Comando a ejecutar cuando se hace clic derecho en el botón."
+ },
+ "middle-click": {
+ "label": "Clic medio",
+ "description": "Comando a ejecutar cuando se hace clic medio en el botón."
+ },
"dynamic-text": "Texto dinámico",
"display-command-output": {
"label": "Mostrar salida de comando",
@@ -899,11 +955,26 @@
}
},
"media-mini": {
- "auto-hide": "Ocultar automáticamente",
- "show-album-art": "Mostrar carátula del álbum",
- "show-visualizer": "Mostrar visualizador",
- "visualizer-type": "Tipo de visualizador",
- "scrolling-mode": "Modo de desplazamiento"
+ "auto-hide": {
+ "label": "Ocultar automáticamente",
+ "description": "Ocultar automáticamente el widget cuando no se está reproduciendo ningún medio."
+ },
+ "show-album-art": {
+ "label": "Mostrar arte del álbum",
+ "description": "Mostrar la portada del álbum de la pista que se está reproduciendo actualmente."
+ },
+ "show-visualizer": {
+ "label": "Mostrar visualizador",
+ "description": "Mostrar un visualizador de audio cuando se reproduce música."
+ },
+ "visualizer-type": {
+ "label": "Tipo de visualizador",
+ "description": "Elegir el estilo de visualizador de audio a mostrar."
+ },
+ "scrolling-mode": {
+ "label": "Modo de desplazamiento",
+ "description": "Controlar cuándo está habilitado el desplazamiento de texto para títulos de pista largos."
+ }
},
"clock": {
"use-primary-color": {
diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json
index 5c302a1d..7e5d1ae5 100644
--- a/Assets/Translations/fr.json
+++ b/Assets/Translations/fr.json
@@ -29,6 +29,10 @@
"animation-speed": {
"label": "Vitesse d'animation",
"description": "Ajustez la vitesse globale des animations."
+ },
+ "animation-disable": {
+ "label": "Désactiver les animations de l'interface",
+ "description": "Désactiver toutes les animations pour une expérience plus rapide et réactive."
}
},
"screen-corners": {
@@ -476,12 +480,16 @@
"enable-matugen": {
"label": "Activer Matugen",
"description": "Générez automatiquement des couleurs en fonction de votre fond d'écran actif."
+ },
+ "matugen-scheme-type": {
+ "label": "Type de schéma Matugen",
+ "description": "Choisissez l'algorithme de génération de schéma de couleurs pour Matugen."
}
},
"predefined": {
"section": {
"label": "Jeux de couleurs prédéfinis",
- "description": "Pour utiliser ces jeux de couleurs, vous devez désactiver Matugen. Avec Matugen activé, les couleurs sont générées automatiquement à partir de votre fond d'écran."
+ "description": "Choisissez parmi une collection de jeux de couleurs prédéfinis."
}
},
"matugen": {
@@ -806,21 +814,54 @@
"search-placeholder": "Rechercher des widgets..."
},
"active-window": {
- "show-app-icon": "Afficher l'icône de l'application",
- "scrolling-mode": "Mode de défilement",
- "auto-hide": "Masquer automatiquement"
+ "show-app-icon": {
+ "label": "Afficher l'icône de l'application",
+ "description": "Afficher l'icône de l'application à côté du titre de la fenêtre."
+ },
+ "scrolling-mode": {
+ "label": "Mode de défilement",
+ "description": "Contrôler quand le défilement de texte est activé pour les titres de fenêtre longs."
+ },
+ "auto-hide": {
+ "label": "Masquer automatiquement",
+ "description": "Masquer automatiquement le widget quand aucune fenêtre n'est active."
+ }
},
"system-monitor": {
- "cpu-usage": "Utilisation du CPU",
- "cpu-temperature": "Température du CPU",
- "memory-usage": "Utilisation de la mémoire",
- "memory-percentage": "Mémoire en pourcentage",
- "network-traffic": "Trafic réseau",
- "storage-usage": "Utilisation du stockage"
+ "cpu-usage": {
+ "label": "Utilisation du CPU",
+ "description": "Afficher le pourcentage d'utilisation actuel du CPU."
+ },
+ "cpu-temperature": {
+ "label": "Température du CPU",
+ "description": "Afficher les lectures de température du CPU si disponibles."
+ },
+ "memory-usage": {
+ "label": "Utilisation de la mémoire",
+ "description": "Afficher les informations actuelles d'utilisation de la RAM."
+ },
+ "memory-percentage": {
+ "label": "Mémoire en pourcentage",
+ "description": "Afficher l'utilisation de la mémoire en pourcentage au lieu de valeurs absolues."
+ },
+ "network-traffic": {
+ "label": "Trafic réseau",
+ "description": "Afficher les vitesses de téléchargement et de téléversement du réseau."
+ },
+ "storage-usage": {
+ "label": "Utilisation du stockage",
+ "description": "Afficher les informations d'utilisation de l'espace disque."
+ }
},
"notification-history": {
- "show-unread-badge": "Afficher le badge non lu",
- "hide-badge-when-zero": "Masquer le badge si zéro"
+ "show-unread-badge": {
+ "label": "Afficher le badge non lu",
+ "description": "Afficher un badge montrant le nombre de notifications non lues."
+ },
+ "hide-badge-when-zero": {
+ "label": "Masquer le badge quand zéro",
+ "description": "Masquer le badge de notification quand il n'y a pas de notifications non lues."
+ }
},
"battery": {
"display-mode": {
@@ -833,7 +874,10 @@
}
},
"control-center": {
- "use-distro-logo": "Utiliser le logo de la distribution au lieu de l'icône",
+ "use-distro-logo": {
+ "label": "Utiliser le logo de la distribution au lieu de l'icône",
+ "description": "Utiliser le logo de votre distribution au lieu d'une icône personnalisée."
+ },
"icon": {
"label": "Icône",
"description": "Sélectionnez une icône de la bibliothèque ou un fichier personnalisé."
@@ -855,7 +899,10 @@
}
},
"workspace": {
- "label-mode": "Mode d'étiquette",
+ "label-mode": {
+ "label": "Mode d'étiquette",
+ "description": "Choisir comment les étiquettes d'espace de travail sont affichées."
+ },
"hide-unoccupied": {
"label": "Masquer les inoccupés",
"description": "Ne pas afficher les espaces de travail sans fenêtres."
@@ -885,9 +932,18 @@
"description": "Sélectionnez une icône dans la bibliothèque."
},
"browse": "Parcourir",
- "left-click": "Clic gauche",
- "right-click": "Clic droit",
- "middle-click": "Clic du milieu",
+ "left-click": {
+ "label": "Clic gauche",
+ "description": "Commande à exécuter quand le bouton est cliqué à gauche."
+ },
+ "right-click": {
+ "label": "Clic droit",
+ "description": "Commande à exécuter quand le bouton est cliqué à droite."
+ },
+ "middle-click": {
+ "label": "Clic milieu",
+ "description": "Commande à exécuter quand le bouton est cliqué au milieu."
+ },
"dynamic-text": "Texte dynamique",
"display-command-output": {
"label": "Afficher la sortie de la commande",
@@ -899,11 +955,26 @@
}
},
"media-mini": {
- "show-album-art": "Afficher la pochette de l'album",
- "show-visualizer": "Afficher le visualiseur",
- "visualizer-type": "Type de visualiseur",
- "scrolling-mode": "Mode de défilement",
- "auto-hide": "Masquer automatiquement"
+ "show-album-art": {
+ "label": "Afficher la pochette d'album",
+ "description": "Afficher la pochette d'album de la piste en cours de lecture."
+ },
+ "show-visualizer": {
+ "label": "Afficher le visualiseur",
+ "description": "Afficher un visualiseur audio quand la musique est en cours de lecture."
+ },
+ "visualizer-type": {
+ "label": "Type de visualiseur",
+ "description": "Choisir le style de visualiseur audio à afficher."
+ },
+ "scrolling-mode": {
+ "label": "Mode de défilement",
+ "description": "Contrôler quand le défilement de texte est activé pour les titres de piste longs."
+ },
+ "auto-hide": {
+ "label": "Masquer automatiquement",
+ "description": "Masquer automatiquement le widget quand aucun média n'est en cours de lecture."
+ }
},
"clock": {
"use-primary-color": {
diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json
index 93e83768..ce3e2ec1 100644
--- a/Assets/Translations/pt.json
+++ b/Assets/Translations/pt.json
@@ -29,6 +29,10 @@
"animation-speed": {
"label": "Velocidade da animação",
"description": "Ajuste a velocidade global da animação."
+ },
+ "animation-disable": {
+ "label": "Desativar animações da interface",
+ "description": "Desativar todas as animações para uma experiência mais rápida e responsiva."
}
},
"screen-corners": {
@@ -442,12 +446,16 @@
"enable-matugen": {
"label": "Ativar Matugen",
"description": "Gera cores automaticamente com base no seu papel de parede ativo."
+ },
+ "matugen-scheme-type": {
+ "label": "Tipo de esquema Matugen",
+ "description": "Escolha o algoritmo de geração de esquema de cores para Matugen."
}
},
"predefined": {
"section": {
"label": "Esquemas de cores predefinidos",
- "description": "Para usar esses esquemas de cores, você deve desativar o Matugen. Com o Matugen ativado, as cores são geradas automaticamente a partir do seu papel de parede."
+ "description": "Escolha entre uma coleção de esquemas de cores predefinidos."
}
},
"matugen": {
@@ -709,7 +717,6 @@
}
}
},
-
"widgets": {
"tooltip": {
"placeholder": "Espaço reservado"
@@ -807,21 +814,54 @@
"search-placeholder": "Pesquisar widgets..."
},
"active-window": {
- "auto-hide": "Ocultar automaticamente",
- "show-app-icon": "Mostrar ícone do aplicativo",
- "scrolling-mode": "Modo de Rolagem"
+ "auto-hide": {
+ "label": "Ocultar automaticamente",
+ "description": "Ocultar automaticamente o widget quando nenhuma janela está ativa."
+ },
+ "show-app-icon": {
+ "label": "Mostrar ícone do aplicativo",
+ "description": "Exibir o ícone do aplicativo ao lado do título da janela."
+ },
+ "scrolling-mode": {
+ "label": "Modo de rolagem",
+ "description": "Controlar quando a rolagem de texto está habilitada para títulos de janela longos."
+ }
},
"system-monitor": {
- "cpu-usage": "Uso de CPU",
- "cpu-temperature": "Temperatura da CPU",
- "memory-usage": "Uso de memória",
- "memory-percentage": "Memória em porcentagem",
- "network-traffic": "Tráfego de rede",
- "storage-usage": "Uso de armazenamento"
+ "cpu-usage": {
+ "label": "Uso da CPU",
+ "description": "Exibir o percentual atual de uso da CPU."
+ },
+ "cpu-temperature": {
+ "label": "Temperatura da CPU",
+ "description": "Mostrar leituras de temperatura da CPU se disponíveis."
+ },
+ "memory-usage": {
+ "label": "Uso de memória",
+ "description": "Exibir informações atuais de uso da RAM."
+ },
+ "memory-percentage": {
+ "label": "Memória como percentual",
+ "description": "Mostrar o uso de memória como percentual em vez de valores absolutos."
+ },
+ "network-traffic": {
+ "label": "Tráfego de rede",
+ "description": "Exibir velocidades de upload e download da rede."
+ },
+ "storage-usage": {
+ "label": "Uso de armazenamento",
+ "description": "Mostrar informações de uso do espaço em disco."
+ }
},
"notification-history": {
- "show-unread-badge": "Mostrar selo de não lidas",
- "hide-badge-when-zero": "Ocultar selo quando for zero"
+ "show-unread-badge": {
+ "label": "Mostrar distintivo de não lidos",
+ "description": "Exibir um distintivo mostrando o número de notificações não lidas."
+ },
+ "hide-badge-when-zero": {
+ "label": "Ocultar distintivo quando zero",
+ "description": "Ocultar o distintivo de notificação quando não há notificações não lidas."
+ }
},
"battery": {
"display-mode": {
@@ -834,7 +874,10 @@
}
},
"control-center": {
- "use-distro-logo": "Usar logo da distro em vez do ícone",
+ "use-distro-logo": {
+ "label": "Usar logo da distribuição em vez de ícone",
+ "description": "Usar o logo da sua distribuição em vez de um ícone personalizado."
+ },
"icon": {
"label": "Ícone",
"description": "Selecione um ícone da biblioteca ou um arquivo personalizado."
@@ -856,7 +899,10 @@
}
},
"workspace": {
- "label-mode": "Modo de Rótulo",
+ "label-mode": {
+ "label": "Modo de rótulo",
+ "description": "Escolher como os rótulos de espaço de trabalho são exibidos."
+ },
"hide-unoccupied": {
"label": "Ocultar desocupados",
"description": "Não exibir áreas de trabalho sem janelas."
@@ -886,9 +932,18 @@
"description": "Selecione um ícone da biblioteca."
},
"browse": "Navegar",
- "left-click": "Clique esquerdo",
- "right-click": "Clique direito",
- "middle-click": "Clique do meio",
+ "left-click": {
+ "label": "Clique esquerdo",
+ "description": "Comando a executar quando o botão é clicado com o botão esquerdo."
+ },
+ "right-click": {
+ "label": "Clique direito",
+ "description": "Comando a executar quando o botão é clicado com o botão direito."
+ },
+ "middle-click": {
+ "label": "Clique do meio",
+ "description": "Comando a executar quando o botão é clicado com o botão do meio."
+ },
"dynamic-text": "Texto dinâmico",
"display-command-output": {
"label": "Exibir Saída de Comando",
@@ -900,11 +955,26 @@
}
},
"media-mini": {
- "auto-hide": "Ocultar automaticamente",
- "show-album-art": "Mostrar arte do álbum",
- "show-visualizer": "Mostrar visualizador",
- "visualizer-type": "Tipo de visualizador",
- "scrolling-mode": "Modo de rolagem"
+ "auto-hide": {
+ "label": "Ocultar automaticamente",
+ "description": "Ocultar automaticamente o widget quando nenhuma mídia está sendo reproduzida."
+ },
+ "show-album-art": {
+ "label": "Mostrar arte do álbum",
+ "description": "Exibir a arte do álbum da faixa atualmente sendo reproduzida."
+ },
+ "show-visualizer": {
+ "label": "Mostrar visualizador",
+ "description": "Exibir um visualizador de áudio quando música está sendo reproduzida."
+ },
+ "visualizer-type": {
+ "label": "Tipo de visualizador",
+ "description": "Escolher o estilo de visualizador de áudio a exibir."
+ },
+ "scrolling-mode": {
+ "label": "Modo de rolagem",
+ "description": "Controlar quando a rolagem de texto está habilitada para títulos de faixa longos."
+ }
},
"clock": {
"use-primary-color": {
@@ -1101,8 +1171,8 @@
"bottom_right": "Inferior direito",
"bottom_center": "Centro inferior",
"top_center": "Centro superior",
- "center_left": "Esquerda central",
- "center_right": "Direita central"
+ "center_left": "Centro à esquerda",
+ "center_right": "Centro à direita"
}
},
"bar": {
@@ -1118,19 +1188,6 @@
"comfortable": "Confortável"
}
},
- "launcher": {
- "position": {
- "center": "Centro (padrão)",
- "top_left": "Superior esquerdo",
- "top_right": "Superior direito",
- "bottom_left": "Inferior esquerdo",
- "bottom_right": "Inferior direito",
- "bottom_center": "Centro inferior",
- "top_center": "Centro superior",
- "center_left": "Centro à esquerda",
- "center_right": "Centro à direita"
- }
- },
"display-mode": {
"on-hover": "Ao passar o mouse",
"always-show": "Sempre mostrar",
diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json
index 8bb1eac5..a478c547 100644
--- a/Assets/Translations/zh-CN.json
+++ b/Assets/Translations/zh-CN.json
@@ -1,1317 +1,1388 @@
{
- "settings": {
- "general": {
- "title": "通用",
- "profile": {
- "section": {
- "label": "个人资料",
- "description": "编辑您的用户详细信息和头像。"
- },
- "picture": {
- "label": "{user} 的个人资料图片",
- "description": "在整个界面中显示您的个人资料图片。"
- },
- "select-avatar": "选择头像图片"
- },
- "ui": {
- "section": {
- "label": "用户界面",
- "description": "自定义界面的外观、风格和行为。"
- },
- "dim-desktop": {
- "label": "调暗桌面",
- "description": "当面板或菜单打开时调暗桌面。"
- },
- "border-radius": {
- "label": "边框圆角",
- "description": "控制窗口、按钮及其他元素的边角圆度。"
- },
- "animation-speed": {
- "label": "动画速度",
- "description": "调整全局动画速度。"
- }
- },
- "screen-corners": {
- "section": {
- "label": "屏幕边角",
- "description": "自定义屏幕边角的圆度和视觉效果。"
- },
- "show-corners": {
- "label": "显示屏幕圆角",
- "description": "在屏幕边缘显示圆角。"
- },
- "solid-black": {
- "label": "实心黑色边角",
- "description": "使用实心黑色而非状态栏背景色。"
- },
- "radius": {
- "label": "屏幕边角半径",
- "description": "调整屏幕圆角的弧度。"
- }
- },
- "fonts": {
- "section": {
- "label": "字体",
- "description": "选择整个界面中使用的字体。"
- },
- "default": {
- "label": "默认字体",
- "description": "整个界面使用的主要字体。",
- "placeholder": "选择默认字体...",
- "search-placeholder": "搜索字体..."
- },
- "monospace": {
- "label": "等宽字体",
- "description": "用于数字和统计信息显示的等宽字体。",
- "placeholder": "选择等宽字体...",
- "search-placeholder": "搜索等宽字体..."
- },
- "accent": {
- "label": "强调字体",
- "description": "用于突出显示内容的大字体。",
- "placeholder": "选择标题字体...",
- "search-placeholder": "搜索标题字体..."
- }
- }
- },
- "audio": {
- "title": "音频",
- "volumes": {
- "section": {
- "label": "音量",
- "description": "调整音量控制和音频级别。"
- },
- "output-volume": {
- "label": "输出音量",
- "description": "系统全局音量级别。"
- },
- "mute-output": {
- "label": "静音输出",
- "description": "静音系统主音频输出。"
- },
- "input-volume": {
- "label": "输入音量",
- "description": "麦克风输入音量级别。"
- },
- "mute-input": {
- "label": "静音输入",
- "description": "静音默认音频输入(麦克风)。"
- },
- "step-size": {
- "label": "音量步长",
- "description": "调整音量变化的步长(滚轮、键盘快捷键)。"
- },
- "volume-overdrive": {
- "label": "允许音量过载",
- "description": "允许将音量提高到100%以上。可能不被所有硬件支持。"
- }
- },
- "devices": {
- "section": {
- "label": "音频设备",
- "description": "配置可用的音频输入和输出设备。"
- },
- "output-device": {
- "label": "输出设备",
- "description": "选择所需的音频输出设备。"
- },
- "input-device": {
- "label": "输入设备",
- "description": "选择所需的音频输入设备。"
- }
- },
- "media": {
- "section": {
- "label": "媒体播放器",
- "description": "设置您首选和要忽略的媒体应用程序。"
- },
- "primary-player": {
- "label": "主要播放器",
- "description": "输入关键词以识别您的主要播放器。",
- "placeholder": "例如:spotify, vlc, mpv"
- },
- "excluded-player": {
- "label": "排除的播放器",
- "description": "添加您希望系统忽略的播放器关键词。每个关键词应单独占一行。",
- "placeholder": "输入关键词并按 + 添加"
- },
- "visualizer-type": {
- "label": "可视化类型",
- "description": "选择媒体播放的可视化类型"
- },
- "frame-rate": {
- "label": "帧率",
- "description": "帧率越高越流畅,但会占用更多资源。"
- },
- "scrolling-title": {
- "label": "标题滚动",
- "description": "为长媒体标题启用连续滚动"
- },
- "scrolling-speed": {
- "label": "滚动速度",
- "description": "标题从头到尾滚动所需的时间(秒)"
- }
- }
- },
- "display": {
- "title": "显示",
- "monitors": {
- "section": {
- "label": "每显示器设置",
- "description": "调整每个显示器的缩放比例和亮度。"
- },
- "scale": "缩放比例",
- "brightness": "亮度",
- "reset-scaling": "重置缩放",
- "brightness-step": {
- "label": "亮度步长",
- "description": "调整亮度变化的步长(滚轮和键盘快捷键)。"
- }
- },
- "night-light": {
- "section": {
- "label": "夜灯",
- "description": "减少蓝光发射,帮助您更好地睡眠并减轻眼睛疲劳。"
- },
- "enable": {
- "label": "启用夜灯",
- "description": "应用暖色滤镜以减少蓝光发射。"
- },
- "temperature": {
- "label": "色温",
- "description": "设置夜间和白天的颜色温暖度。",
- "night": "夜间",
- "day": "白天"
- },
- "auto-schedule": {
- "label": "自动调度",
- "description": "基于 {location} 的日落和日出时间 - 推荐。"
- },
- "manual-schedule": {
- "label": "手动调度",
- "description": "为日出和日落设置自定义时间。",
- "sunrise": "日出时间",
- "sunset": "日落时间",
- "select-start": "选择开始时间",
- "select-stop": "选择停止时间"
- },
- "force-activation": {
- "label": "强制激活",
- "description": "忽略调度并立即应用夜间滤镜。"
- }
- }
- },
- "bar": {
- "title": "状态栏",
- "appearance": {
- "section": {
- "label": "外观",
- "description": "自定义状态栏的外观和位置。"
- },
- "position": {
- "label": "状态栏位置",
- "description": "选择在屏幕上的位置。"
- },
- "density": {
- "label": "状态栏密度",
- "description": "调整状态栏的内边距以获得紧凑或宽松的外观。"
- },
- "background-opacity": {
- "label": "背景不透明度",
- "description": "调整状态栏的背景不透明度。"
- },
- "show-capsule": {
- "label": "显示胶囊",
- "description": "显示小部件背景。"
- },
- "floating": {
- "label": "浮动状态栏",
- "description": "将状态栏显示为浮动'药丸'。注意:这会将屏幕边角移动到边缘。"
- },
- "margins": {
- "label": "边距",
- "description": "调整浮动状态栏周围的边距。",
- "vertical": "垂直",
- "horizontal": "水平"
- }
- },
- "widgets": {
- "section": {
- "label": "小部件定位",
- "description": "拖放小部件以在每个部分内重新排序,或使用添加/删除按钮管理小部件。"
- }
- },
- "monitors": {
- "section": {
- "label": "显示器显示",
- "description": "在特定显示器上显示状态栏。如果未选择,则默认为全部。"
- }
- }
- },
- "dock": {
- "title": "Dock",
- "appearance": {
- "section": {
- "label": "外观",
- "description": "自定义 Dock 的行为和外观。"
- },
- "auto-hide": {
- "label": "自动隐藏",
- "description": "不使用时自动隐藏。"
- },
- "exclusive-zone": {
- "label": "独占区域",
- "description": "防止窗口重叠。"
- },
- "background-opacity": {
- "label": "背景不透明度",
- "description": "调整 Dock 的背景不透明度。"
- },
- "floating-distance": {
- "label": "Dock 浮动距离",
- "description": "调整距离屏幕边缘的浮动距离。"
- }
- },
- "monitors": {
- "section": {
- "label": "显示器显示",
- "description": "选择在哪个显示器上显示 Dock。"
- }
- }
- },
- "launcher": {
- "title": "启动器",
- "settings": {
- "section": {
- "label": "外观",
- "description": "自定义启动器的行为和外观。"
- },
- "position": {
- "label": "位置",
- "description": "选择启动器面板出现的位置。"
- },
- "background-opacity": {
- "label": "背景不透明度",
- "description": "调整启动器的背景不透明度。"
- },
- "clipboard-history": {
- "label": "启用剪贴板历史记录",
- "description": "从启动器访问之前复制的项目。"
- },
- "sort-by-usage": {
- "label": "按使用频率排序",
- "description": "启用后,经常启动的应用程序将显示在列表首位。"
- },
- "use-app2unit": {
- "label": "使用 App2Unit 启动应用程序",
- "description": "使用替代启动方法以更好地管理应用程序进程并防止问题。"
- }
- }
- },
- "notifications": {
- "title": "通知",
- "settings": {
- "section": {
- "label": "外观",
- "description": "配置通知的外观和行为。"
- },
- "do-not-disturb": {
- "label": "勿扰模式",
- "description": "启用后禁用所有通知弹出窗口。"
- },
- "enable-osd": {
- "label": "启用屏幕显示",
- "description": "实时显示音量和亮度变化。"
- },
- "location": {
- "label": "位置",
- "description": "通知在屏幕上出现的位置。"
- },
- "always-on-top": {
- "label": "始终置顶",
- "description": "在全屏窗口和其他图层上方显示通知。"
- }
- },
- "duration": {
- "section": {
- "label": "通知持续时间",
- "description": "根据紧急级别配置通知保持可见的时间。"
- },
- "respect-expire": {
- "label": "尊重过期超时",
- "description": "使用通知中设置的过期超时。"
- },
- "low-urgency": {
- "label": "低紧急度",
- "description": "低优先级通知保持可见的时间。"
- },
- "normal-urgency": {
- "label": "正常紧急度",
- "description": "正常优先级通知保持可见的时间。"
- },
- "critical-urgency": {
- "label": "高紧急度",
- "description": "高优先级通知保持可见的时间。"
- }
- },
- "monitors": {
- "section": {
- "label": "显示器显示",
- "description": "在特定显示器上显示通知。如果未选择,则默认为全部。"
- }
- }
- },
- "osd": {
- "title": "屏幕显示",
- "description": "配置屏幕叠加指示器,例如音量和亮度。",
+ "settings": {
+ "general": {
+ "title": "通用",
+ "profile": {
"section": {
- "general": {
- "label": "常规",
- "description": "配置屏幕显示(OSD)的可见性与行为。"
- }
+ "label": "个人资料",
+ "description": "编辑您的用户详细信息和头像。"
},
- "enabled": {
- "label": "启用屏幕显示",
- "description": "实时显示音量与亮度变化。"
+ "picture": {
+ "label": "{user} 的个人资料图片",
+ "description": "在整个界面中显示您的个人资料图片。"
},
- "location": {
- "label": "位置",
- "description": "屏幕显示出现的位置。"
- },
- "duration": {
- "section": {
- "label": "自动隐藏超时",
- "description": "屏幕显示自动隐藏前保持可见的时长。"
- },
- "auto-hide": {
- "label": "在此之后隐藏",
- "description": "调整屏幕显示消失前的时间。"
- }
- },
- "monitors": {
- "section": {
- "label": "显示器显示",
- "description": "在特定显示器上显示屏幕显示。若未选择,则默认全部。"
- }
- }
+ "select-avatar": "选择头像图片"
},
- "wallpaper": {
- "title": "壁纸",
- "settings": {
- "section": {
- "label": "壁纸设置",
- "description": "控制壁纸的管理和显示方式。"
- },
- "enable-management": {
- "label": "启用壁纸管理",
- "description": "使用 Noctalia 管理壁纸。如果您更喜欢使用其他应用程序,请取消选中。"
- },
- "folder": {
- "label": "壁纸文件夹",
- "description": "您的主壁纸文件夹路径。",
- "tooltip": "浏览壁纸文件夹"
- },
- "monitor-specific": {
- "label": "显示器特定目录",
- "description": "为每个显示器设置不同的壁纸文件夹。",
- "tooltip": "浏览壁纸文件夹"
- },
- "select-folder": "选择壁纸文件夹",
- "select-monitor-folder": "选择显示器壁纸文件夹"
- },
- "look-feel": {
- "section": {
- "label": "外观和感觉"
- },
- "fill-mode": {
- "label": "填充模式",
- "description": "选择图像应如何缩放以匹配显示器的分辨率。"
- },
- "fill-color": {
- "label": "填充颜色",
- "description": "选择可能出现在壁纸后面的填充颜色。"
- },
- "transition-type": {
- "label": "过渡类型",
- "description": "切换壁纸时的动画类型。"
- },
- "transition-duration": {
- "label": "过渡持续时间",
- "description": "过渡动画的持续时间(秒)。"
- },
- "edge-smoothness": {
- "label": "软化过渡边缘",
- "description": "对过渡边缘应用柔和、羽化的效果。"
- }
- },
- "automation": {
- "section": {
- "label": "自动化"
- },
- "random-wallpaper": {
- "label": "随机壁纸",
- "description": "按固定间隔调度随机壁纸更改。"
- },
- "interval": {
- "label": "壁纸间隔",
- "description": "自动更改壁纸的频率。"
- },
- "custom-interval": {
- "label": "自定义间隔",
- "description": "以 HH:MM 格式输入时间(例如:01:30)。"
- }
- }
- },
- "color-scheme": {
- "title": "配色方案",
- "color-source": {
- "section": {
- "label": "颜色来源",
- "description": "Noctalia 颜色的主要设置。"
- },
- "dark-mode": {
- "label": "深色模式",
- "description": "切换到更暗的主题,便于夜间观看。"
- },
- "enable-matugen": {
- "label": "启用 Matugen",
- "description": "根据您的活动壁纸自动生成颜色。"
- }
- },
- "predefined": {
- "section": {
- "label": "预定义配色方案",
- "description": "要使用这些配色方案,您必须关闭 Matugen。启用 Matugen 后,颜色会根据您的壁纸自动生成。"
- }
- },
- "matugen": {
- "section": {
- "label": "Matugen 模板",
- "description": "将颜色应用于外部应用程序。"
- },
- "ui": {
- "label": "用户界面",
- "description": "桌面环境和 UI 工具包主题。",
- "gtk4": {
- "description": "写入 {filepath}"
- },
- "gtk3": {
- "description": "写入 {filepath}"
- },
- "qt6": {
- "description": "写入 {filepath}"
- },
- "qt5": {
- "description": "写入 {filepath}"
- }
- },
- "terminal": {
- "label": "终端",
- "description": "终端模拟器主题。",
- "kitty": {
- "description": "写入 {filepath} 并重新加载",
- "description-missing": "需要安装 {app}"
- },
- "ghostty": {
- "description": "写入 {filepath} 并重新加载",
- "description-missing": "需要安装 {app}"
- },
- "foot": {
- "description": "写入 {filepath} 并重新加载",
- "description-missing": "需要安装 {app}"
- }
- },
- "programs": {
- "label": "程序",
- "description": "应用程序特定主题。",
- "fuzzel": {
- "description": "写入 {filepath} 并重新加载",
- "description-missing": "需要安装 {app}"
- },
- "vesktop": {
- "description": "写入 {filepath}",
- "description-missing": "需要安装 {app}"
- },
- "pywalfox": {
- "description": "写入 {filepath} 并运行 pywalfox update",
- "description-missing": "需要安装 {app}"
- }
- },
- "misc": {
- "label": "杂项",
- "description": "其他配置选项。",
- "user-templates": {
- "label": "用户模板",
- "description": "启用来自 ~/.config/matugen/config.toml 的用户定义 Matugen 配置"
- }
- }
- }
- },
- "location": {
- "title": "位置",
- "location": {
- "section": {
- "label": "您的位置",
- "description": "通过设置您的位置获取准确的天气和夜灯调度。"
- },
- "search": {
- "label": "搜索位置",
- "description": "例如:多伦多, 安大略省",
- "placeholder": "输入位置名称"
- }
- },
- "weather": {
- "section": {
- "label": "天气",
- "description": "选择您喜欢的温度单位。"
- },
- "fahrenheit": {
- "label": "以华氏度显示温度 (°F)",
- "description": "以华氏度而非摄氏度显示温度。"
- }
- },
- "date-time": {
- "section": {
- "label": "日期和时间",
- "description": "自定义日期和时间的显示方式。"
- },
- "12hour-format": {
- "label": "在锁屏上使用 12 小时制",
- "description": "开启为 AM/PM 格式(例如:8:00 PM),关闭为 24 小时制(例如:20:00)。"
- },
- "week-numbers": {
- "label": "显示周数",
- "description": "在日历中显示一年中的第几周(例如:第 38 周)。"
- }
- }
- },
- "network": {
- "title": "网络",
+ "ui": {
"section": {
- "description": "管理 Wi-Fi 和蓝牙连接。"
+ "label": "用户界面",
+ "description": "自定义界面的外观、风格和行为。"
},
- "wifi": {
- "label": "启用 Wi-Fi"
+ "dim-desktop": {
+ "label": "调暗桌面",
+ "description": "当面板或菜单打开时调暗桌面。"
},
- "bluetooth": {
- "label": "启用蓝牙"
+ "border-radius": {
+ "label": "边框圆角",
+ "description": "控制窗口、按钮及其他元素的边角圆度。"
+ },
+ "animation-speed": {
+ "label": "动画速度",
+ "description": "调整全局动画速度。"
+ },
+ "animation-disable": {
+ "label": "关闭动画",
+ "description": "禁用所有动画效果,以获得更快速、更灵敏的体验。"
}
},
- "screen-recorder": {
- "title": "屏幕录制",
- "general": {
- "section": {
- "label": "常规设置",
- "description": "管理屏幕录制输出和内容。"
- },
- "output-folder": {
- "label": "输出文件夹",
- "description": "屏幕录制将保存的文件夹。",
- "tooltip": "浏览输出文件夹"
- },
- "show-cursor": {
- "label": "显示光标",
- "description": "在视频中录制鼠标光标。"
- },
- "select-output-folder": "选择输出文件夹"
+ "screen-corners": {
+ "section": {
+ "label": "屏幕边角",
+ "description": "自定义屏幕边角的圆度和视觉效果。"
},
- "video": {
- "section": {
- "label": "视频设置",
- "description": "配置视频录制选项。"
- },
- "video-source": {
- "label": "视频源",
- "description": "推荐使用 Portal,如果出现伪影请尝试 Screen。"
- },
- "frame-rate": {
- "label": "帧率",
- "description": "屏幕录制的目标帧率。"
- },
- "video-quality": {
- "label": "视频质量",
- "description": "更高的质量会导致更大的文件大小。"
- },
- "video-codec": {
- "label": "视频编解码器",
- "description": "h264 是最常见的编解码器。"
- },
- "color-range": {
- "label": "颜色范围",
- "description": "推荐使用 Limited 以获得更好的兼容性。"
- }
+ "show-corners": {
+ "label": "显示屏幕圆角",
+ "description": "在屏幕边缘显示圆角。"
},
- "audio": {
- "section": {
- "label": "音频设置",
- "description": "配置音频录制选项。"
- },
- "audio-source": {
- "label": "音频源",
- "description": "录制期间要捕获的音频源。"
- },
- "audio-codec": {
- "label": "音频编解码器",
- "description": "推荐使用 Opus 以获得最佳性能和最小的音频大小。"
- }
+ "solid-black": {
+ "label": "实心黑色边角",
+ "description": "使用实心黑色而非状态栏背景色。"
+ },
+ "radius": {
+ "label": "屏幕边角半径",
+ "description": "调整屏幕圆角的弧度。"
}
},
- "about": {
- "title": "关于",
- "noctalia": {
- "section": {
- "label": "Noctalia shell",
- "description": "一款为 Wayland 精心打造的时尚简约桌面 shell,基于 Quickshell 构建。"
- },
- "latest-version": "最新版本:",
- "installed-version": "已安装版本:",
- "download-latest": "下载最新版本"
+ "fonts": {
+ "section": {
+ "label": "字体",
+ "description": "选择整个界面中使用的字体。"
},
- "contributors": {
- "section": {
- "label": "贡献者",
- "description": "向我们 {count} 位超棒的贡献者致敬!",
- "description_plural": "向我们 {count} 位超棒的贡献者致敬!"
- }
- }
- },
- "hooks": {
- "title": "钩子",
- "system-hooks": {
- "section": {
- "label": "系统钩子",
- "description": "配置在系统事件发生时执行的命令。"
- },
- "enable": {
- "label": "启用钩子",
- "description": "启用或禁用所有钩子命令。"
- }
+ "default": {
+ "label": "默认字体",
+ "description": "整个界面使用的主要字体。",
+ "placeholder": "选择默认字体...",
+ "search-placeholder": "搜索字体..."
},
- "wallpaper-changed": {
- "label": "壁纸已更改",
- "description": "壁纸更改时执行的命令。",
- "placeholder": "例如:notify-send \"壁纸\" \"已更改\""
+ "monospace": {
+ "label": "等宽字体",
+ "description": "用于数字和统计信息显示的等宽字体。",
+ "placeholder": "选择等宽字体...",
+ "search-placeholder": "搜索等宽字体..."
},
- "theme-changed": {
- "label": "主题已更改",
- "description": "主题在深色和浅色模式之间切换时执行的命令。",
- "placeholder": "例如:notify-send \"主题\" \"已切换\""
- },
- "info": {
- "command-info": {
- "label": "钩子命令信息",
- "description": "• 命令通过 shell 执行 (sh -c)\n• 命令在后台运行(分离)\n• 测试按钮使用当前值执行"
- },
- "parameters": {
- "label": "可用参数",
- "description": "• 壁纸钩子: $1 = 壁纸路径, $2 = 屏幕名称\n• 主题切换钩子: $1 = true/false (深色模式状态)"
- }
+ "accent": {
+ "label": "强调字体",
+ "description": "用于突出显示内容的大字体。",
+ "placeholder": "选择标题字体...",
+ "search-placeholder": "搜索标题字体..."
}
}
},
- "widgets": {
- "tooltip": {
- "placeholder": "占位符"
- },
- "file-picker": {
- "select-folder": "选择文件夹",
- "select-file": "选择文件"
- },
- "datetime-tokens": {
- "common": {
- "12hour-time-minutes": "12小时制带分钟",
- "24hour-time-minutes": "24小时制带分钟",
- "24hour-time-seconds": "24小时制带秒",
- "weekday-month-day": "星期、月份和日期",
- "iso-date": "ISO 日期格式",
- "us-date": "美国日期格式",
- "european-date": "欧洲日期格式",
- "weekday-date": "星期和日期"
+ "audio": {
+ "title": "音频",
+ "volumes": {
+ "section": {
+ "label": "音量",
+ "description": "调整音量控制和音频级别。"
},
- "hour": {
- "no-leading-zero": "小时无前导零 (0-23) - 24小时制",
- "leading-zero": "小时有前导零 (00-23) - 24小时制"
+ "output-volume": {
+ "label": "输出音量",
+ "description": "系统全局音量级别。"
},
- "minute": {
- "no-leading-zero": "分钟无前导零 (0-59)",
- "leading-zero": "分钟有前导零 (00-59)"
+ "mute-output": {
+ "label": "静音输出",
+ "description": "静音系统主音频输出。"
},
- "second": {
- "no-leading-zero": "秒无前导零 (0-59)",
- "leading-zero": "秒有前导零 (00-59)"
+ "input-volume": {
+ "label": "输入音量",
+ "description": "麦克风输入音量级别。"
},
- "ampm": {
- "uppercase": "AM/PM 大写",
- "lowercase": "am/pm 小写"
+ "mute-input": {
+ "label": "静音输入",
+ "description": "静音默认音频输入(麦克风)。"
},
- "timezone": {
- "abbreviation": "时区缩写"
+ "step-size": {
+ "label": "音量步长",
+ "description": "调整音量变化的步长(滚轮、键盘快捷键)。"
},
- "year": {
- "two-digit": "年份为两位数 (00-99)",
- "four-digit": "年份为四位数"
- },
- "month": {
- "number-no-zero": "月份数字无前导零 (1-12)",
- "number-leading-zero": "月份数字有前导零 (01-12)",
- "abbreviated": "月份名称缩写",
- "full": "月份名称全称"
- },
- "day": {
- "no-leading-zero": "日期无前导零 (1-31)",
- "leading-zero": "日期有前导零 (01-31)",
- "abbreviated": "星期名称缩写",
- "full": "星期名称全称"
+ "volume-overdrive": {
+ "label": "允许音量过载",
+ "description": "允许将音量提高到100%以上。可能不被所有硬件支持。"
}
},
- "icon-picker": {
- "title": "图标选择器",
- "search": {
- "label": "搜索"
+ "devices": {
+ "section": {
+ "label": "音频设备",
+ "description": "配置可用的音频输入和输出设备。"
},
- "cancel": "取消",
- "apply": "应用"
+ "output-device": {
+ "label": "输出设备",
+ "description": "选择所需的音频输出设备。"
+ },
+ "input-device": {
+ "label": "输入设备",
+ "description": "选择所需的音频输入设备。"
+ }
},
- "color-picker": {
- "title": "颜色选择器",
- "hex": {
- "label": "十六进制颜色",
- "description": "输入十六进制颜色代码。"
+ "media": {
+ "section": {
+ "label": "媒体播放器",
+ "description": "设置您首选和要忽略的媒体应用程序。"
},
- "rgb": {
- "label": "RGB 值",
- "description": "调整红、绿、蓝和亮度值。"
+ "primary-player": {
+ "label": "主要播放器",
+ "description": "输入关键词以识别您的主要播放器。",
+ "placeholder": "例如:spotify, vlc, mpv"
},
+ "excluded-player": {
+ "label": "排除的播放器",
+ "description": "添加您希望系统忽略的播放器关键词。每个关键词应单独占一行。",
+ "placeholder": "输入关键词并按 + 添加"
+ },
+ "visualizer-type": {
+ "label": "可视化类型",
+ "description": "选择媒体播放的可视化类型"
+ },
+ "frame-rate": {
+ "label": "帧率",
+ "description": "帧率越高越流畅,但会占用更多资源。"
+ },
+ "scrolling-title": {
+ "label": "标题滚动",
+ "description": "为长媒体标题启用连续滚动"
+ },
+ "scrolling-speed": {
+ "label": "滚动速度",
+ "description": "标题从头到尾滚动所需的时间(秒)"
+ }
+ }
+ },
+ "display": {
+ "title": "显示",
+ "monitors": {
+ "section": {
+ "label": "每显示器设置",
+ "description": "调整每个显示器的缩放比例和亮度。"
+ },
+ "scale": "缩放比例",
"brightness": "亮度",
- "theme-colors": {
- "label": "主题颜色",
- "description": "快速访问您的主题调色板。"
+ "reset-scaling": "重置缩放",
+ "brightness-step": {
+ "label": "亮度步长",
+ "description": "调整亮度变化的步长(滚轮和键盘快捷键)。"
+ }
+ },
+ "night-light": {
+ "section": {
+ "label": "夜间模式",
+ "description": "减少蓝光发射,帮助您更好地睡眠并减轻眼睛疲劳。"
},
- "palette": {
- "label": "调色板",
- "description": "从各种预定义颜色中选择。"
+ "enable": {
+ "label": "启用夜间模式",
+ "description": "应用暖色滤镜以减少蓝光发射。"
},
- "cancel": "取消",
- "apply": "应用"
+ "temperature": {
+ "label": "色温",
+ "description": "设置夜间和白天的颜色温暖度。",
+ "night": "夜间",
+ "day": "白天"
+ },
+ "auto-schedule": {
+ "label": "自动调度",
+ "description": "基于 {location} 的日落和日出时间 - 推荐。"
+ },
+ "manual-schedule": {
+ "label": "手动调度",
+ "description": "为日出和日落设置自定义时间。",
+ "sunrise": "日出时间",
+ "sunset": "日落时间",
+ "select-start": "选择开始时间",
+ "select-stop": "选择停止时间"
+ },
+ "force-activation": {
+ "label": "强制激活",
+ "description": "忽略调度并立即应用夜间滤镜。"
+ }
}
},
"bar": {
- "widget-settings": {
- "dialog": {
- "cancel": "取消",
- "apply": "应用"
+ "title": "状态栏",
+ "appearance": {
+ "section": {
+ "label": "外观",
+ "description": "自定义状态栏的外观和位置。"
},
- "section-editor": {
- "placeholder": "选择要添加的小部件...",
- "search-placeholder": "搜索小部件..."
+ "position": {
+ "label": "状态栏位置",
+ "description": "选择在屏幕上的位置。"
},
- "active-window": {
- "auto-hide": "自动隐藏",
- "show-app-icon": "显示应用图标",
- "scrolling-mode": "滚动模式"
+ "density": {
+ "label": "状态栏密度",
+ "description": "调整状态栏的内边距以获得紧凑或宽松的外观。"
},
- "system-monitor": {
- "cpu-usage": "CPU 使用率",
- "cpu-temperature": "CPU 温度",
- "memory-usage": "内存使用率",
- "memory-percentage": "内存百分比",
- "network-traffic": "网络流量",
- "storage-usage": "存储使用率"
+ "background-opacity": {
+ "label": "背景不透明度",
+ "description": "调整状态栏的背景不透明度。"
},
- "notification-history": {
- "show-unread-badge": "显示未读标记",
- "hide-badge-when-zero": "为零时隐藏标记"
+ "show-capsule": {
+ "label": "显示胶囊",
+ "description": "显示小部件背景。"
},
- "battery": {
- "display-mode": {
- "label": "显示模式",
- "description": "选择您希望此值显示的方式。"
- },
- "low-battery-threshold": {
- "label": "低电量警告阈值",
- "description": "当电量低于此百分比时显示警告。"
- }
+ "floating": {
+ "label": "浮动状态栏",
+ "description": "将状态栏显示为浮动样式(类似于一个药丸)。注意:这会将屏幕边角移动到边缘。"
},
- "control-center": {
- "use-distro-logo": "使用发行版徽标代替图标",
- "icon": {
- "label": "图标",
- "description": "从库中选择图标或自定义文件。"
- },
- "browse-library": "浏览库",
- "browse-file": "浏览文件",
- "select-custom-icon": "选择自定义图标"
+ "margins": {
+ "label": "边距",
+ "description": "调整浮动状态栏周围的边距。",
+ "vertical": "垂直",
+ "horizontal": "水平"
+ }
+ },
+ "widgets": {
+ "section": {
+ "label": "小部件定位",
+ "description": "拖放小部件以在每个部分内重新排序,或使用添加/删除按钮管理小部件。"
+ }
+ },
+ "monitors": {
+ "section": {
+ "label": "显示器显示",
+ "description": "在特定显示器上显示状态栏。如果未选择,则默认为全部。"
+ }
+ }
+ },
+ "dock": {
+ "title": "Dock",
+ "appearance": {
+ "section": {
+ "label": "外观",
+ "description": "自定义 Dock 的行为和外观。"
},
- "keyboard-layout": {
- "display-mode": {
- "label": "显示模式",
- "description": "选择您希望此值显示的方式。"
- }
+ "auto-hide": {
+ "label": "自动隐藏",
+ "description": "不使用时自动隐藏。"
},
- "volume": {
- "display-mode": {
- "label": "显示模式",
- "description": "选择您希望此值显示的方式。"
- }
+ "exclusive-zone": {
+ "label": "独占区域",
+ "description": "可以防止窗口重叠。"
},
- "workspace": {
- "label-mode": "标签模式",
- "hide-unoccupied": {
- "label": "隐藏未占用",
- "description": "不显示没有窗口的工作区。"
- }
+ "background-opacity": {
+ "label": "背景不透明度",
+ "description": "调整 Dock 的背景不透明度。"
},
- "microphone": {
- "display-mode": {
- "label": "显示模式",
- "description": "选择您希望此值显示的方式。"
- }
+ "floating-distance": {
+ "label": "Dock 浮动距离",
+ "description": "调整距离屏幕边缘的浮动距离。"
+ }
+ },
+ "monitors": {
+ "section": {
+ "label": "显示器显示",
+ "description": "选择在哪个显示器上显示 Dock。"
+ }
+ }
+ },
+ "launcher": {
+ "title": "启动器",
+ "settings": {
+ "section": {
+ "label": "外观",
+ "description": "自定义启动器的行为和外观。"
},
- "brightness": {
- "display-mode": {
- "label": "显示模式",
- "description": "选择您希望此值显示的方式。"
- }
+ "position": {
+ "label": "位置",
+ "description": "选择启动器面板出现的位置。"
},
- "spacer": {
- "width": {
- "label": "宽度",
- "description": "间距宽度(像素)"
- }
+ "background-opacity": {
+ "label": "背景不透明度",
+ "description": "调整启动器的背景不透明度。"
},
- "custom-button": {
- "icon": {
- "label": "图标",
- "description": "从库中选择图标。"
- },
- "browse": "浏览",
- "left-click": "左键点击",
- "right-click": "右键点击",
- "middle-click": "中键点击",
- "dynamic-text": "动态文本",
- "display-command-output": {
- "label": "显示命令输出",
- "description": "输入一个定期运行的命令。其输出的第一行将显示为文本。"
- },
- "refresh-interval": {
- "label": "刷新间隔",
- "description": "间隔时间(毫秒)。"
- }
+ "clipboard-history": {
+ "label": "启用剪贴板历史记录",
+ "description": "从启动器访问之前复制的项目。"
},
- "media-mini": {
- "auto-hide": "自动隐藏",
- "show-album-art": "显示专辑封面",
- "show-visualizer": "显示可视化器",
- "visualizer-type": "可视化器类型",
- "scrolling-mode": "滚动模式"
+ "sort-by-usage": {
+ "label": "按使用频率排序",
+ "description": "启用后,经常启动的应用程序将显示在列表首位。"
},
- "clock": {
- "use-primary-color": {
- "label": "使用主颜色",
- "description": "启用后,将应用主颜色进行强调。"
- },
- "use-monospaced-font": {
- "label": "使用等宽字体",
- "description": "启用后,时钟将使用等宽字体。"
- },
- "clock-display": {
- "label": "时钟显示",
- "description": "通过从下面的列表添加标记来自定义时钟显示。要使用 12 小时制,必须包含 'AP' 标记。"
- },
- "horizontal-bar": {
- "label": "水平栏",
- "description": "提示:使用 \\n 创建换行。"
- },
- "vertical-bar": {
- "label": "垂直栏",
- "description": "使用空格将每个部分分隔到新行。"
- },
- "preview": "预览"
+ "use-app2unit": {
+ "label": "使用 App2Unit 启动应用程序",
+ "description": "使用替代启动方法以更好地管理应用程序进程并防止问题。"
}
}
},
"notifications": {
- "panel": {
- "title": "通知",
- "no-notifications": "无通知",
- "description": "您的通知将在到达时显示在此处。"
+ "title": "通知",
+ "settings": {
+ "section": {
+ "label": "外观",
+ "description": "配置通知的外观和行为。"
+ },
+ "do-not-disturb": {
+ "label": "勿扰模式",
+ "description": "启用后禁用所有通知弹出窗口。"
+ },
+ "enable-osd": {
+ "label": "启用屏幕显示",
+ "description": "实时显示音量和亮度变化。"
+ },
+ "location": {
+ "label": "位置",
+ "description": "通知在屏幕上出现的位置。"
+ },
+ "always-on-top": {
+ "label": "始终置顶",
+ "description": "在全屏窗口和其他图层上方显示通知。"
+ }
+ },
+ "duration": {
+ "section": {
+ "label": "通知持续时间",
+ "description": "根据紧急级别配置通知保持可见的时间。"
+ },
+ "respect-expire": {
+ "label": "尊重过期超时",
+ "description": "使用通知中设置的过期超时。"
+ },
+ "low-urgency": {
+ "label": "低紧急度",
+ "description": "低优先级通知保持可见的时间。"
+ },
+ "normal-urgency": {
+ "label": "正常紧急度",
+ "description": "正常优先级通知保持可见的时间。"
+ },
+ "critical-urgency": {
+ "label": "高紧急度",
+ "description": "高优先级通知保持可见的时间。"
+ }
+ },
+ "monitors": {
+ "section": {
+ "label": "显示器显示",
+ "description": "在特定显示器上显示通知。如果未选择,则默认为全部。"
+ }
+ }
+ },
+ "osd": {
+ "title": "屏幕显示",
+ "description": "配置屏幕叠加指示器,例如音量和亮度。",
+ "section": {
+ "general": {
+ "label": "常规",
+ "description": "配置屏幕显示(OSD)的可见性与行为。"
+ }
+ },
+ "enabled": {
+ "label": "启用屏幕显示",
+ "description": "实时显示音量与亮度变化。"
+ },
+ "location": {
+ "label": "位置",
+ "description": "屏幕显示出现的位置。"
+ },
+ "duration": {
+ "section": {
+ "label": "自动隐藏超时",
+ "description": "屏幕显示自动隐藏前保持可见的时长。"
+ },
+ "auto-hide": {
+ "label": "在此之后隐藏",
+ "description": "调整屏幕显示消失前的时间。"
+ }
+ },
+ "monitors": {
+ "section": {
+ "label": "显示器显示",
+ "description": "在特定显示器上显示屏幕显示。若未选择,则默认全部。"
+ }
}
},
"wallpaper": {
- "panel": {
- "title": "壁纸选择器",
- "apply-all-monitors": {
- "label": "应用到所有显示器",
- "description": "一次性将选定的壁纸应用到所有显示器。"
+ "title": "壁纸",
+ "settings": {
+ "section": {
+ "label": "壁纸设置",
+ "description": "控制壁纸的管理和显示方式。"
},
- "search": "搜索:"
- },
- "transitions": {
- "none": "无",
- "random": "随机",
- "fade": "淡入淡出",
- "disc": "圆盘",
- "stripes": "条纹",
- "wipe": "擦除"
- },
- "fill-modes": {
- "center": "居中",
- "crop": "裁剪(填充)",
- "fit": "适应(包含)",
- "stretch": "拉伸"
- },
- "no-match": "未找到匹配项。",
- "no-wallpaper": "未找到壁纸。",
- "try-different-search": "尝试不同的搜索查询。",
- "configure-directory": "使用图像配置您的壁纸目录。"
- },
- "bluetooth": {
- "panel": {
- "title": "蓝牙",
- "disabled": "蓝牙已禁用",
- "enable-message": "启用蓝牙以查看可用设备。",
- "connected-devices": "已连接设备",
- "known-devices": "已知设备",
- "available-devices": "可用设备",
- "scanning": "正在扫描设备...",
- "pairing-mode": "确保您的设备处于配对模式。"
- }
- },
- "wifi": {
- "panel": {
- "title": "Wi-Fi",
- "disabled": "Wi-Fi 已禁用",
- "enable-message": "启用 Wi-Fi 以查看可用网络。",
- "searching": "正在搜索附近网络...",
- "connected": "已连接",
- "disconnecting": "正在断开连接...",
- "forgetting": "正在忘记...",
- "saved": "已保存",
- "disconnect": "断开连接",
- "enter-password": "输入密码...",
- "connect": "连接",
- "password": "密码",
- "forget-network": "忘记此网络?",
- "forget": "忘记",
- "no-networks": "未找到网络",
- "scan-again": "重新扫描"
- }
- },
- "calendar": {
- "panel": {
- "week": "周"
- }
- },
- "tooltips": {
- "refresh": "刷新",
- "close": "关闭",
- "refresh-wallpaper-list": "刷新壁纸列表",
- "refresh-devices": "刷新设备",
- "forget-network": "忘记网络",
- "clear-history": "清除历史记录",
- "delete-notification": "删除通知",
- "previous-month": "上个月",
- "next-month": "下个月",
- "add-widget": "添加小部件",
- "widget-settings": "小部件设置",
- "remove-widget": "移除小部件",
- "move-to-left-section": "移动到左侧部分",
- "move-to-center-section": "移动到中央部分",
- "move-to-right-section": "移动到右侧部分",
- "open-settings": "打开设置",
- "session-menu": "会话菜单",
- "cancel-timer": "取消计时器",
- "start-screen-recording": "开始屏幕录制",
- "stop-screen-recording": "停止屏幕录制",
- "screen-recorder-not-installed": "屏幕录制器未安装",
- "keep-awake": "保持唤醒",
- "enable-keep-awake": "启用保持唤醒",
- "disable-keep-awake": "禁用保持唤醒",
- "wallpaper-selector": "左键点击:打开壁纸选择器。\n右键点击:设置随机壁纸。",
- "do-not-disturb-enabled": "'勿扰模式'已启用",
- "do-not-disturb-disabled": "'勿扰模式'已禁用",
- "connect-disconnect-devices": "左键点击连接。右键点击忘记。",
- "set-power-profile": "设置\"{profile}\"电源模式",
- "switch-to-light-mode": "切换到浅色模式",
- "switch-to-dark-mode": "切换到深色模式",
- "night-light-disabled": "夜灯已禁用。\n左键点击循环模式。\n右键点击访问设置。",
- "night-light-enabled": "夜灯已启用。\n左键点击循环模式。\n右键点击访问设置。",
- "night-light-forced": "夜灯已强制启用。\n左键点击循环模式。\n右键点击访问设置。",
- "click-to-start-recording": "点击开始录制",
- "click-to-stop-recording": "点击停止录制",
- "open-control-center": "打开控制中心",
- "volume-at": "音量 {volume}%\n左键点击切换静音。右键点击进入设置。\n滚动调整音量。",
- "microphone-volume-at": "麦克风音量 {volume}%\n左键点击切换静音。右键点击进入设置。\n滚动调整音量。",
- "manage-wifi": "管理 Wi-Fi",
- "bluetooth-devices": "蓝牙设备",
- "open-notification-history-enable-dnd": "打开通知历史记录\n右键点击启用\"勿扰模式\"。",
- "open-notification-history-disable-dnd": "打开通知历史记录\n右键点击禁用\"勿扰模式\"。",
- "open-wallpaper-selector": "打开壁纸选择器",
- "previous-media": "上一媒体",
- "pause": "暂停",
- "play": "播放",
- "next-media": "下一媒体",
- "power-profile": "'{profile}' 电源模式",
- "keyboard-layout": "{layout} 键盘布局"
- },
- "clock": {
- "tooltip": "打开日历"
- },
- "dock": {
- "menu": {
- "focus": "聚焦",
- "pin": "固定",
- "unpin": "取消固定",
- "close": "关闭"
- }
- },
- "placeholders": {
- "search-icons": "例如:noctalia, niri, battery, cloud",
- "profile-picture-path": "/home/user/.face",
- "enter-width-pixels": "输入宽度(像素)",
- "enter-command": "输入要执行的命令(应用程序或自定义脚本)",
- "command-example": "echo \"Hello World\"",
- "search-wallpapers": "输入以筛选壁纸...",
- "search-launcher": "搜索条目...或使用 > 执行命令",
- "search": "搜索...",
- "select": "选择",
- "cancel": "取消",
- "test": "测试"
- },
- "options": {
- "bar": {
- "position": {
- "top": "顶部",
- "bottom": "底部",
- "left": "左侧",
- "right": "右侧"
+ "enable-management": {
+ "label": "启用壁纸管理",
+ "description": "使用 Noctalia 管理壁纸。如果您更喜欢使用其他应用程序,请取消选中。"
},
- "density": {
- "compact": "紧凑",
- "default": "默认",
- "comfortable": "舒适"
+ "folder": {
+ "label": "壁纸文件夹",
+ "description": "您的主壁纸文件夹路径。",
+ "tooltip": "浏览壁纸文件夹"
+ },
+ "monitor-specific": {
+ "label": "显示器特定目录",
+ "description": "为每个显示器设置不同的壁纸文件夹。",
+ "tooltip": "浏览壁纸文件夹"
+ },
+ "select-folder": "选择壁纸文件夹",
+ "select-monitor-folder": "选择显示器壁纸文件夹"
+ },
+ "look-feel": {
+ "section": {
+ "label": "外观和感觉"
+ },
+ "fill-mode": {
+ "label": "填充模式",
+ "description": "选择图像应如何缩放以匹配显示器的分辨率。"
+ },
+ "fill-color": {
+ "label": "填充颜色",
+ "description": "选择可能出现在壁纸后面的填充颜色。"
+ },
+ "transition-type": {
+ "label": "过渡类型",
+ "description": "切换壁纸时的动画类型。"
+ },
+ "transition-duration": {
+ "label": "过渡持续时间",
+ "description": "过渡动画的持续时间(秒)。"
+ },
+ "edge-smoothness": {
+ "label": "软化过渡边缘",
+ "description": "对过渡边缘应用柔和、羽化的效果。"
}
},
- "launcher": {
- "position": {
- "center": "居中(默认)",
- "top_left": "左上角",
- "top_right": "右上角",
- "bottom_left": "左下角",
- "bottom_right": "右下角",
- "bottom_center": "底部居中",
- "top_center": "顶部居中",
- "center_left": "左侧居中",
- "center_right": "右侧居中"
- }
- },
- "osd": {
- "position": {
- "top_left": "左上角",
- "top_right": "右上角",
- "top_center": "顶部居中",
- "bottom_left": "左下角",
- "bottom_right": "右下角",
- "bottom_center": "底部居中",
- "center_left": "左侧居中",
- "center_right": "右侧居中"
- }
- },
- "display-mode": {
- "on-hover": "悬停时显示",
- "always-show": "始终显示",
- "always-hide": "始终隐藏",
- "force-open": "强制打开"
- },
- "workspace-labels": {
- "none": "无",
- "index": "索引",
- "name": "名称"
- },
- "visualizer-types": {
- "none": "无",
- "linear": "线性",
- "mirrored": "镜像",
- "wave": "波形"
- },
- "scrolling-modes": {
- "always": "始终滚动",
- "hover": "悬停时滚动",
- "never": "从不滚动"
- },
- "frame-rates": {
- "fps": "{fps} FPS"
- },
- "screen-recording": {
- "sources": {
- "portal": "Portal",
- "screen": "屏幕"
+ "automation": {
+ "section": {
+ "label": "自动化"
},
- "quality": {
- "medium": "中等",
- "high": "高",
- "very-high": "很高",
- "ultra": "超高"
+ "random-wallpaper": {
+ "label": "随机壁纸",
+ "description": "按固定间隔调度随机壁纸更改。"
},
- "color-range": {
- "limited": "有限",
- "full": "完全"
+ "interval": {
+ "label": "壁纸间隔",
+ "description": "自动更改壁纸的频率。"
},
- "audio-sources": {
- "system-output": "系统输出",
- "microphone-input": "麦克风输入",
- "both": "系统输出 + 麦克风输入"
+ "custom-interval": {
+ "label": "自定义间隔",
+ "description": "以 HH:MM 格式输入时间(例如:01:30)。"
}
}
},
- "session-menu": {
- "title": "会话菜单",
- "click-again": "再次点击立即执行",
- "action-in-seconds": "{seconds} 秒后{action}...",
- "lock-subtitle": "锁定您的会话",
- "end-subtitle": "结束您的会话",
- "lock": "锁定",
- "suspend": "挂起",
- "reboot": "重启",
- "logout": "注销",
- "shutdown": "关机"
- },
- "plugins": {
- "applications": "应用程序",
- "clipboard": "剪贴板历史记录",
- "calculator": "计算器",
- "clipboard-search-description": "搜索剪贴板历史记录",
- "clipboard-clear-description": "清除所有剪贴板历史记录",
- "clipboard-history-disabled": "剪贴板历史记录已禁用",
- "clipboard-history-disabled-description": "在设置中启用剪贴板历史记录或安装 cliphist",
- "clipboard-clear-history": "清除剪贴板历史记录",
- "clipboard-clear-description-full": "从剪贴板历史记录中移除所有项目",
- "clipboard-loading": "正在加载剪贴板历史记录...",
- "clipboard-loading-description": "请稍候",
- "calculator-description": "计算器 - 计算数学表达式",
- "calculator-name": "计算器",
- "calculator-enter-expression": "输入数学表达式",
- "calculator-error": "错误"
- },
- "system": {
- "uptime": "系统运行时间:{uptime}",
- "welcome-back": "欢迎回来,{user}!",
- "monitor-description": "{model} ({width}x{height})",
- "scaling-percentage": "{percentage}%",
- "location-display": "{name} ({coordinates})",
- "signal-strength": "{signal}%",
- "cpu-temperature": "{temp}°C",
- "disk-usage": "{percent}%",
- "widget-settings-title": "{widget} 设置",
- "unknown-app": "未知应用",
- "no-media-player-detected": "未检测到媒体播放器",
- "user-requested": "用户请求",
- "unknown": "未知",
- "unknown-version": "未知",
- "unknown-layout": "未知"
- },
- "lock-screen": {
- "secure-terminal": "安全终端",
- "unlock-command": "sudo unlock-session",
- "password": "密码:",
- "shut-down": "关机",
- "restart": "重启",
- "suspend": "挂起"
- },
- "toast": {
- "night-light": {
- "enabled": "已启用",
- "disabled": "已禁用",
- "not-installed": "未安装 wlsunset",
- "forced": "强制激活",
- "normal": "正常模式"
+ "color-scheme": {
+ "title": "配色方案",
+ "color-source": {
+ "section": {
+ "label": "颜色来源",
+ "description": "Noctalia 颜色的主要设置。"
+ },
+ "dark-mode": {
+ "label": "深色模式",
+ "description": "切换到更暗的主题,便于夜间观看。"
+ },
+ "enable-matugen": {
+ "label": "启用 Matugen",
+ "description": "根据您的活动壁纸自动生成颜色。"
+ },
+ "matugen-scheme-type": {
+ "label": "Matugen 配色方案类型",
+ "description": "为 Matugen 选择配色方案生成算法。"
+ }
},
- "keep-awake": {
- "enabled": "已启用",
- "disabled": "已禁用"
+ "predefined": {
+ "section": {
+ "label": "预定义配色方案",
+ "description": "从预定义配色方案集合中选择。"
+ }
},
"matugen": {
- "enabled": "已启用",
- "disabled": "已禁用",
- "not-installed": "未安装"
- },
- "recording": {
- "stopping": "正在停止录制…",
- "started": "录制已开始",
- "saved": "录制已保存",
- "failed-start": "开始录制失败",
- "failed-gpu": "gpu-screen-recorder 意外退出。",
- "failed-general": "录制器因错误退出。",
- "no-portals": "桌面门户未运行",
- "no-portals-desc": "请启动 xdg-desktop-portal 和一个合成器门户 (wlr/hyprland/gnome/kde)。"
- },
- "clipboard": {
- "unavailable": "剪贴板历史记录不可用",
- "unavailable-desc": "未安装 'cliphist' 应用程序。请安装它以使用剪贴板历史记录功能。"
- },
- "ipc": {
- "powerpanel-deprecated": "PowerPanel 已重命名为 SessionMenu,此 IPC 调用将很快弃用。请改用 \"ipc call sessionMenu toggle\"。",
- "sidepanel-deprecated": "SidePanel 已重命名为 ControlCenter,此 IPC 调用将很快弃用。请改用 \"ipc call controlCenter toggle\"。"
- },
- "wifi": {
- "enabled": "已启用",
- "disabled": "已禁用",
- "connected": "已连接到 '{ssid}'",
- "disconnected": "已断开与 '{ssid}' 的连接"
- },
- "bluetooth": {
- "enabled": "已启用",
- "disabled": "已禁用"
- },
- "do-not-disturb": {
- "enabled": "'勿扰模式'已启用",
- "disabled": "'勿扰模式'已禁用",
- "enabled-desc": "您可以在历史记录中找到这些通知。",
- "disabled-desc": "显示所有通知。"
- },
- "power-profile": {
- "changed": "电源模式已更改",
- "profile-name": "\"{profile}\""
- },
- "audio": {
- "muted": "已静音",
- "unmuted": "已取消静音"
- },
- "battery": {
- "low": "电量低",
- "low-desc": "电量为 {percent}%。请连接充电器。"
- },
- "missing-control-center": {
- "label": "最后一个控制中心小部件已移除",
- "description": "控制中心小部件已从状态栏中移除。要再次从状态栏访问它,您需要重新添加小部件。"
+ "section": {
+ "label": "Matugen 模板",
+ "description": "将颜色应用于外部应用程序。"
+ },
+ "ui": {
+ "label": "用户界面",
+ "description": "桌面环境和 UI 工具包主题。",
+ "gtk4": {
+ "description": "写入 {filepath}"
+ },
+ "gtk3": {
+ "description": "写入 {filepath}"
+ },
+ "qt6": {
+ "description": "写入 {filepath}"
+ },
+ "qt5": {
+ "description": "写入 {filepath}"
+ }
+ },
+ "terminal": {
+ "label": "终端",
+ "description": "终端模拟器主题。",
+ "kitty": {
+ "description": "写入 {filepath} 并重新加载",
+ "description-missing": "需要安装 {app}"
+ },
+ "ghostty": {
+ "description": "写入 {filepath} 并重新加载",
+ "description-missing": "需要安装 {app}"
+ },
+ "foot": {
+ "description": "写入 {filepath} 并重新加载",
+ "description-missing": "需要安装 {app}"
+ }
+ },
+ "programs": {
+ "label": "程序",
+ "description": "应用程序特定主题。",
+ "fuzzel": {
+ "description": "写入 {filepath} 并重新加载",
+ "description-missing": "需要安装 {app}"
+ },
+ "vesktop": {
+ "description": "写入 {filepath}",
+ "description-missing": "需要安装 {app}"
+ },
+ "pywalfox": {
+ "description": "写入 {filepath} 并运行 pywalfox update",
+ "description-missing": "需要安装 {app}"
+ }
+ },
+ "misc": {
+ "label": "杂项",
+ "description": "其他配置选项。",
+ "user-templates": {
+ "label": "用户模板",
+ "description": "启用来自 ~/.config/matugen/config.toml 的用户定义 Matugen 配置"
+ }
+ }
}
},
- "weather": {
- "clear-sky": "晴朗",
- "mainly-clear": "基本晴朗",
- "partly-cloudy": "局部多云",
- "overcast": "阴天",
- "fog": "雾",
- "drizzle": "毛毛雨",
- "snow": "雪",
- "rain-showers": "阵雨",
- "thunderstorm": "雷暴",
- "unknown": "未知"
+ "location": {
+ "title": "位置",
+ "location": {
+ "section": {
+ "label": "您的位置",
+ "description": "通过设置您的位置获取准确的天气和调度夜间模式。"
+ },
+ "search": {
+ "label": "搜索位置",
+ "description": "例如:多伦多, 安大略省",
+ "placeholder": "输入位置名称"
+ }
+ },
+ "weather": {
+ "section": {
+ "label": "天气",
+ "description": "选择您喜欢的温度单位。"
+ },
+ "fahrenheit": {
+ "label": "以华氏度显示温度 (°F)",
+ "description": "以华氏度而非摄氏度显示温度。"
+ }
+ },
+ "date-time": {
+ "section": {
+ "label": "日期和时间",
+ "description": "自定义日期和时间的显示方式。"
+ },
+ "12hour-format": {
+ "label": "在锁屏上使用 12 小时制",
+ "description": "开启为 AM/PM 格式(例如:8:00 PM),关闭为 24 小时制(例如:20:00)。"
+ },
+ "week-numbers": {
+ "label": "显示周数",
+ "description": "在日历中显示一年中的第几周(例如:第 38 周)。"
+ }
+ }
},
- "authentication": {
- "failed": "认证失败",
- "error": "认证错误"
+ "network": {
+ "title": "网络",
+ "section": {
+ "description": "管理 Wi-Fi 和蓝牙连接。"
+ },
+ "wifi": {
+ "label": "启用 Wi-Fi"
+ },
+ "bluetooth": {
+ "label": "启用蓝牙"
+ }
},
- "general": {
- "no-results": "无结果",
- "no-summary": "无摘要",
- "unknown": "未知"
+ "screen-recorder": {
+ "title": "屏幕录制",
+ "general": {
+ "section": {
+ "label": "常规设置",
+ "description": "管理屏幕录制输出和内容。"
+ },
+ "output-folder": {
+ "label": "输出文件夹",
+ "description": "屏幕录制将保存的文件夹。",
+ "tooltip": "浏览输出文件夹"
+ },
+ "show-cursor": {
+ "label": "显示光标",
+ "description": "在视频中录制鼠标光标。"
+ },
+ "select-output-folder": "选择输出文件夹"
+ },
+ "video": {
+ "section": {
+ "label": "视频设置",
+ "description": "配置视频录制选项。"
+ },
+ "video-source": {
+ "label": "视频源",
+ "description": "推荐使用 Portal,如果出现伪影请尝试 Screen。"
+ },
+ "frame-rate": {
+ "label": "帧率",
+ "description": "屏幕录制的目标帧率。"
+ },
+ "video-quality": {
+ "label": "视频质量",
+ "description": "更高的质量会导致更大的文件大小。"
+ },
+ "video-codec": {
+ "label": "视频编解码器",
+ "description": "h264 是最常见的编解码器。"
+ },
+ "color-range": {
+ "label": "颜色范围",
+ "description": "推荐使用 Limited 以获得更好的兼容性。"
+ }
+ },
+ "audio": {
+ "section": {
+ "label": "音频设置",
+ "description": "配置音频录制选项。"
+ },
+ "audio-source": {
+ "label": "音频源",
+ "description": "录制期间要捕获的音频源。"
+ },
+ "audio-codec": {
+ "label": "音频编解码器",
+ "description": "推荐使用 Opus 以获得最佳性能和最小的音频大小。"
+ }
+ }
+ },
+ "about": {
+ "title": "关于",
+ "noctalia": {
+ "section": {
+ "label": "Noctalia shell",
+ "description": "一款为 Wayland 精心打造的时尚简约桌面 shell,基于 Quickshell 构建。"
+ },
+ "latest-version": "最新版本:",
+ "installed-version": "已安装版本:",
+ "download-latest": "下载最新版本"
+ },
+ "contributors": {
+ "section": {
+ "label": "贡献者",
+ "description": "向我们 {count} 位超棒的贡献者致敬!",
+ "description_plural": "向我们 {count} 位超棒的贡献者致敬!"
+ }
+ }
+ },
+ "hooks": {
+ "title": "钩子",
+ "system-hooks": {
+ "section": {
+ "label": "系统钩子",
+ "description": "配置在系统事件发生时执行的命令。"
+ },
+ "enable": {
+ "label": "启用钩子",
+ "description": "启用或禁用所有钩子命令。"
+ }
+ },
+ "wallpaper-changed": {
+ "label": "壁纸已更改",
+ "description": "壁纸更改时执行的命令。",
+ "placeholder": "例如:notify-send \"壁纸\" \"已更改\""
+ },
+ "theme-changed": {
+ "label": "主题已更改",
+ "description": "主题在深色和浅色模式之间切换时执行的命令。",
+ "placeholder": "例如:notify-send \"主题\" \"已切换\""
+ },
+ "info": {
+ "command-info": {
+ "label": "钩子命令信息",
+ "description": "• 命令通过 shell 执行 (sh -c)\n• 命令在后台运行(分离)\n• 测试按钮使用当前值执行"
+ },
+ "parameters": {
+ "label": "可用参数",
+ "description": "• 壁纸钩子: $1 = 壁纸路径, $2 = 屏幕名称\n• 主题切换钩子: $1 = true/false (深色模式状态)"
+ }
+ }
+ }
+ },
+ "widgets": {
+ "tooltip": {
+ "placeholder": "占位符"
+ },
+ "file-picker": {
+ "select-folder": "选择文件夹",
+ "select-file": "选择文件"
+ },
+ "datetime-tokens": {
+ "common": {
+ "12hour-time-minutes": "12小时制带分钟",
+ "24hour-time-minutes": "24小时制带分钟",
+ "24hour-time-seconds": "24小时制带秒",
+ "weekday-month-day": "星期、月份和日期",
+ "iso-date": "ISO 日期格式",
+ "us-date": "美国日期格式",
+ "european-date": "欧洲日期格式",
+ "weekday-date": "星期和日期"
+ },
+ "hour": {
+ "no-leading-zero": "小时无前导零 (0-23) - 24小时制",
+ "leading-zero": "小时有前导零 (00-23) - 24小时制"
+ },
+ "minute": {
+ "no-leading-zero": "分钟无前导零 (0-59)",
+ "leading-zero": "分钟有前导零 (00-59)"
+ },
+ "second": {
+ "no-leading-zero": "秒无前导零 (0-59)",
+ "leading-zero": "秒有前导零 (00-59)"
+ },
+ "ampm": {
+ "uppercase": "AM/PM 大写",
+ "lowercase": "am/pm 小写"
+ },
+ "timezone": {
+ "abbreviation": "时区缩写"
+ },
+ "year": {
+ "two-digit": "年份为两位数 (00-99)",
+ "four-digit": "年份为四位数"
+ },
+ "month": {
+ "number-no-zero": "月份数字无前导零 (1-12)",
+ "number-leading-zero": "月份数字有前导零 (01-12)",
+ "abbreviated": "月份名称缩写",
+ "full": "月份名称全称"
+ },
+ "day": {
+ "no-leading-zero": "日期无前导零 (1-31)",
+ "leading-zero": "日期有前导零 (01-31)",
+ "abbreviated": "星期名称缩写",
+ "full": "星期名称全称"
+ }
+ },
+ "icon-picker": {
+ "title": "图标选择器",
+ "search": {
+ "label": "搜索"
+ },
+ "cancel": "取消",
+ "apply": "应用"
+ },
+ "color-picker": {
+ "title": "颜色选择器",
+ "hex": {
+ "label": "十六进制颜色",
+ "description": "输入十六进制颜色代码。"
+ },
+ "rgb": {
+ "label": "RGB 值",
+ "description": "调整红、绿、蓝和亮度值。"
+ },
+ "brightness": "亮度",
+ "theme-colors": {
+ "label": "主题颜色",
+ "description": "快速访问您的主题调色板。"
+ },
+ "palette": {
+ "label": "调色板",
+ "description": "从各种预定义颜色中选择。"
+ },
+ "cancel": "取消",
+ "apply": "应用"
+ }
+ },
+ "bar": {
+ "widget-settings": {
+ "dialog": {
+ "cancel": "取消",
+ "apply": "应用"
+ },
+ "section-editor": {
+ "placeholder": "选择要添加的小部件...",
+ "search-placeholder": "搜索小部件..."
+ },
+ "active-window": {
+ "auto-hide": {
+ "label": "自动隐藏",
+ "description": "当没有活动窗口时自动隐藏小部件。"
+ },
+ "show-app-icon": {
+ "label": "显示应用图标",
+ "description": "在窗口标题旁边显示应用程序图标。"
+ },
+ "scrolling-mode": {
+ "label": "滚动模式",
+ "description": "控制何时为长窗口标题启用文本滚动。"
+ }
+ },
+ "system-monitor": {
+ "cpu-usage": {
+ "label": "CPU使用率",
+ "description": "显示当前CPU使用百分比。"
+ },
+ "cpu-temperature": {
+ "label": "CPU温度",
+ "description": "如果可用,显示CPU温度读数。"
+ },
+ "memory-usage": {
+ "label": "内存使用率",
+ "description": "显示当前RAM使用信息。"
+ },
+ "memory-percentage": {
+ "label": "内存百分比",
+ "description": "以百分比而不是绝对值显示内存使用情况。"
+ },
+ "network-traffic": {
+ "label": "网络流量",
+ "description": "显示网络上传和下载速度。"
+ },
+ "storage-usage": {
+ "label": "存储使用率",
+ "description": "显示磁盘空间使用信息。"
+ }
+ },
+ "notification-history": {
+ "show-unread-badge": {
+ "label": "显示未读徽章",
+ "description": "显示显示未读通知数量的徽章。"
+ },
+ "hide-badge-when-zero": {
+ "label": "零时隐藏徽章",
+ "description": "当没有未读通知时隐藏通知徽章。"
+ }
+ },
+ "battery": {
+ "display-mode": {
+ "label": "显示模式",
+ "description": "选择您希望此值显示的方式。"
+ },
+ "low-battery-threshold": {
+ "label": "低电量警告阈值",
+ "description": "当电量低于此百分比时显示警告。"
+ }
+ },
+ "control-center": {
+ "use-distro-logo": {
+ "label": "使用发行版徽标而不是图标",
+ "description": "使用您的发行版徽标而不是自定义图标。"
+ },
+ "icon": {
+ "label": "图标",
+ "description": "从库中选择图标或自定义文件。"
+ },
+ "browse-library": "浏览库",
+ "browse-file": "浏览文件",
+ "select-custom-icon": "选择自定义图标"
+ },
+ "keyboard-layout": {
+ "display-mode": {
+ "label": "显示模式",
+ "description": "选择您希望此值显示的方式。"
+ }
+ },
+ "volume": {
+ "display-mode": {
+ "label": "显示模式",
+ "description": "选择您希望此值显示的方式。"
+ }
+ },
+ "workspace": {
+ "label-mode": {
+ "label": "标签模式",
+ "description": "选择工作区标签的显示方式。"
+ },
+ "hide-unoccupied": {
+ "label": "隐藏未占用",
+ "description": "不显示没有窗口的工作区。"
+ }
+ },
+ "microphone": {
+ "display-mode": {
+ "label": "显示模式",
+ "description": "选择您希望此值显示的方式。"
+ }
+ },
+ "brightness": {
+ "display-mode": {
+ "label": "显示模式",
+ "description": "选择您希望此值显示的方式。"
+ }
+ },
+ "spacer": {
+ "width": {
+ "label": "宽度",
+ "description": "间距宽度(像素)"
+ }
+ },
+ "custom-button": {
+ "icon": {
+ "label": "图标",
+ "description": "从库中选择图标。"
+ },
+ "browse": "浏览",
+ "left-click": {
+ "label": "左键点击",
+ "description": "左键点击按钮时执行的命令。"
+ },
+ "right-click": {
+ "label": "右键点击",
+ "description": "右键点击按钮时执行的命令。"
+ },
+ "middle-click": {
+ "label": "中键点击",
+ "description": "中键点击按钮时执行的命令。"
+ },
+ "dynamic-text": "动态文本",
+ "display-command-output": {
+ "label": "显示命令输出",
+ "description": "输入一个定期运行的命令。其输出的第一行将显示为文本。"
+ },
+ "refresh-interval": {
+ "label": "刷新间隔",
+ "description": "间隔时间(毫秒)。"
+ }
+ },
+ "media-mini": {
+ "auto-hide": {
+ "label": "自动隐藏",
+ "description": "当没有媒体播放时自动隐藏小部件。"
+ },
+ "show-album-art": {
+ "label": "显示专辑封面",
+ "description": "显示当前播放曲目的专辑封面。"
+ },
+ "show-visualizer": {
+ "label": "显示可视化器",
+ "description": "播放音乐时显示音频可视化器。"
+ },
+ "visualizer-type": {
+ "label": "可视化器类型",
+ "description": "选择要显示的音频可视化器样式。"
+ },
+ "scrolling-mode": {
+ "label": "滚动模式",
+ "description": "控制何时为长曲目标题启用文本滚动。"
+ }
+ },
+ "clock": {
+ "use-primary-color": {
+ "label": "使用主颜色",
+ "description": "启用后,将应用主颜色进行强调。"
+ },
+ "use-monospaced-font": {
+ "label": "使用等宽字体",
+ "description": "启用后,时钟将使用等宽字体。"
+ },
+ "clock-display": {
+ "label": "时钟显示",
+ "description": "通过从下面的列表添加标记来自定义时钟显示。要使用 12 小时制,必须包含 'AP' 标记。"
+ },
+ "horizontal-bar": {
+ "label": "水平栏",
+ "description": "提示:使用 \\n 创建换行。"
+ },
+ "vertical-bar": {
+ "label": "垂直栏",
+ "description": "使用空格将每个部分分隔到新行。"
+ },
+ "preview": "预览"
+ }
+ }
+ },
+ "notifications": {
+ "panel": {
+ "title": "通知",
+ "no-notifications": "无通知",
+ "description": "您的通知将在到达时显示在此处。"
+ }
+ },
+ "wallpaper": {
+ "panel": {
+ "title": "壁纸选择器",
+ "apply-all-monitors": {
+ "label": "应用到所有显示器",
+ "description": "一次性将选定的壁纸应用到所有显示器。"
+ },
+ "search": "搜索:"
+ },
+ "transitions": {
+ "none": "无",
+ "random": "随机",
+ "fade": "淡入淡出",
+ "disc": "圆盘",
+ "stripes": "条纹",
+ "wipe": "擦除"
+ },
+ "fill-modes": {
+ "center": "居中",
+ "crop": "裁剪(填充)",
+ "fit": "适应(包含)",
+ "stretch": "拉伸"
+ },
+ "no-match": "未找到匹配项。",
+ "no-wallpaper": "未找到壁纸。",
+ "try-different-search": "尝试不同的搜索查询。",
+ "configure-directory": "使用图像配置您的壁纸目录。"
+ },
+ "bluetooth": {
+ "panel": {
+ "title": "蓝牙",
+ "disabled": "蓝牙已禁用",
+ "enable-message": "启用蓝牙以查看可用设备。",
+ "connected-devices": "已连接设备",
+ "known-devices": "已知设备",
+ "available-devices": "可用设备",
+ "scanning": "正在扫描设备...",
+ "pairing-mode": "确保您的设备处于配对模式。"
+ }
+ },
+ "wifi": {
+ "panel": {
+ "title": "Wi-Fi",
+ "disabled": "Wi-Fi 已禁用",
+ "enable-message": "启用 Wi-Fi 以查看可用网络。",
+ "searching": "正在搜索附近网络...",
+ "connected": "已连接",
+ "disconnecting": "正在断开连接...",
+ "forgetting": "正在忘记...",
+ "saved": "已保存",
+ "disconnect": "断开连接",
+ "enter-password": "输入密码...",
+ "connect": "连接",
+ "password": "密码",
+ "forget-network": "忘记此网络?",
+ "forget": "忘记",
+ "no-networks": "未找到网络",
+ "scan-again": "重新扫描"
+ }
+ },
+ "calendar": {
+ "panel": {
+ "week": "周"
+ }
+ },
+ "tooltips": {
+ "refresh": "刷新",
+ "close": "关闭",
+ "refresh-wallpaper-list": "刷新壁纸列表",
+ "refresh-devices": "刷新设备",
+ "forget-network": "忘记网络",
+ "clear-history": "清除历史记录",
+ "delete-notification": "删除通知",
+ "previous-month": "上个月",
+ "next-month": "下个月",
+ "add-widget": "添加小部件",
+ "widget-settings": "小部件设置",
+ "remove-widget": "移除小部件",
+ "move-to-left-section": "移动到左侧部分",
+ "move-to-center-section": "移动到中央部分",
+ "move-to-right-section": "移动到右侧部分",
+ "open-settings": "打开设置",
+ "session-menu": "会话菜单",
+ "cancel-timer": "取消计时器",
+ "start-screen-recording": "开始屏幕录制",
+ "stop-screen-recording": "停止屏幕录制",
+ "screen-recorder-not-installed": "屏幕录制器未安装",
+ "keep-awake": "保持唤醒",
+ "enable-keep-awake": "启用保持唤醒",
+ "disable-keep-awake": "禁用保持唤醒",
+ "wallpaper-selector": "左键点击:打开壁纸选择器。\n右键点击:设置随机壁纸。",
+ "do-not-disturb-enabled": "'勿扰模式'已启用",
+ "do-not-disturb-disabled": "'勿扰模式'已禁用",
+ "connect-disconnect-devices": "左键点击连接。右键点击忘记。",
+ "set-power-profile": "设置\"{profile}\"电源模式",
+ "switch-to-light-mode": "切换到浅色模式",
+ "switch-to-dark-mode": "切换到深色模式",
+ "night-light-disabled": "夜间模式已禁用。\n左键点击循环模式。\n右键点击访问设置。",
+ "night-light-enabled": "夜间模式已启用。\n左键点击循环模式。\n右键点击访问设置。",
+ "night-light-forced": "夜间模式已强制启用。\n左键点击循环模式。\n右键点击访问设置。",
+ "click-to-start-recording": "点击开始录制",
+ "click-to-stop-recording": "点击停止录制",
+ "open-control-center": "打开控制中心",
+ "volume-at": "音量 {volume}%\n左键点击切换静音。右键点击进入设置。\n滚动调整音量。",
+ "microphone-volume-at": "麦克风音量 {volume}%\n左键点击切换静音。右键点击进入设置。\n滚动调整音量。",
+ "manage-wifi": "管理 Wi-Fi",
+ "bluetooth-devices": "蓝牙设备",
+ "open-notification-history-enable-dnd": "打开通知历史记录\n右键点击启用\"勿扰模式\"。",
+ "open-notification-history-disable-dnd": "打开通知历史记录\n右键点击禁用\"勿扰模式\"。",
+ "open-wallpaper-selector": "打开壁纸选择器",
+ "previous-media": "上一媒体",
+ "pause": "暂停",
+ "play": "播放",
+ "next-media": "下一媒体",
+ "power-profile": "'{profile}' 电源模式",
+ "keyboard-layout": "{layout} 键盘布局"
+ },
+ "clock": {
+ "tooltip": "打开日历"
+ },
+ "dock": {
+ "menu": {
+ "focus": "聚焦",
+ "pin": "固定",
+ "unpin": "取消固定",
+ "close": "关闭"
+ }
+ },
+ "placeholders": {
+ "search-icons": "例如:noctalia, niri, battery, cloud",
+ "profile-picture-path": "/home/user/.face",
+ "enter-width-pixels": "输入宽度(像素)",
+ "enter-command": "输入要执行的命令(应用程序或自定义脚本)",
+ "command-example": "echo \"Hello World\"",
+ "search-wallpapers": "输入以筛选壁纸...",
+ "search-launcher": "搜索条目...或使用 > 执行命令",
+ "search": "搜索...",
+ "select": "选择",
+ "cancel": "取消",
+ "test": "测试"
+ },
+ "options": {
+ "bar": {
+ "position": {
+ "top": "顶部",
+ "bottom": "底部",
+ "left": "左侧",
+ "right": "右侧"
+ },
+ "density": {
+ "compact": "紧凑",
+ "default": "默认",
+ "comfortable": "舒适"
+ }
+ },
+ "launcher": {
+ "position": {
+ "center": "居中(默认)",
+ "top_left": "左上角",
+ "top_right": "右上角",
+ "bottom_left": "左下角",
+ "bottom_right": "右下角",
+ "bottom_center": "底部居中",
+ "top_center": "顶部居中",
+ "center_left": "左侧居中",
+ "center_right": "右侧居中"
+ }
+ },
+ "osd": {
+ "position": {
+ "top_left": "左上角",
+ "top_right": "右上角",
+ "top_center": "顶部居中",
+ "bottom_left": "左下角",
+ "bottom_right": "右下角",
+ "bottom_center": "底部居中",
+ "center_left": "左侧居中",
+ "center_right": "右侧居中"
+ }
+ },
+ "display-mode": {
+ "on-hover": "悬停时显示",
+ "always-show": "始终显示",
+ "always-hide": "始终隐藏",
+ "force-open": "强制打开"
+ },
+ "workspace-labels": {
+ "none": "无",
+ "index": "索引",
+ "name": "名称"
+ },
+ "visualizer-types": {
+ "none": "无",
+ "linear": "线性",
+ "mirrored": "镜像",
+ "wave": "波形"
+ },
+ "scrolling-modes": {
+ "always": "始终滚动",
+ "hover": "悬停时滚动",
+ "never": "从不滚动"
+ },
+ "frame-rates": {
+ "fps": "{fps} FPS"
+ },
+ "screen-recording": {
+ "sources": {
+ "portal": "Portal",
+ "screen": "屏幕"
+ },
+ "quality": {
+ "medium": "中等",
+ "high": "高",
+ "very-high": "很高",
+ "ultra": "超高"
+ },
+ "color-range": {
+ "limited": "有限",
+ "full": "完全"
+ },
+ "audio-sources": {
+ "system-output": "系统输出",
+ "microphone-input": "麦克风输入",
+ "both": "系统输出 + 麦克风输入"
+ }
+ }
+ },
+ "session-menu": {
+ "title": "会话菜单",
+ "click-again": "再次点击立即执行",
+ "action-in-seconds": "{seconds} 秒后{action}...",
+ "lock-subtitle": "锁定您的会话",
+ "end-subtitle": "结束您的会话",
+ "lock": "锁定",
+ "suspend": "挂起",
+ "reboot": "重启",
+ "logout": "注销",
+ "shutdown": "关机"
+ },
+ "plugins": {
+ "applications": "应用程序",
+ "clipboard": "剪贴板历史记录",
+ "calculator": "计算器",
+ "clipboard-search-description": "搜索剪贴板历史记录",
+ "clipboard-clear-description": "清除所有剪贴板历史记录",
+ "clipboard-history-disabled": "剪贴板历史记录已禁用",
+ "clipboard-history-disabled-description": "在设置中启用剪贴板历史记录或安装 cliphist",
+ "clipboard-clear-history": "清除剪贴板历史记录",
+ "clipboard-clear-description-full": "从剪贴板历史记录中移除所有项目",
+ "clipboard-loading": "正在加载剪贴板历史记录...",
+ "clipboard-loading-description": "请稍候",
+ "calculator-description": "计算器 - 计算数学表达式",
+ "calculator-name": "计算器",
+ "calculator-enter-expression": "输入数学表达式",
+ "calculator-error": "错误"
+ },
+ "system": {
+ "uptime": "系统运行时间:{uptime}",
+ "welcome-back": "欢迎回来,{user}!",
+ "monitor-description": "{model} ({width}x{height})",
+ "scaling-percentage": "{percentage}%",
+ "location-display": "{name} ({coordinates})",
+ "signal-strength": "{signal}%",
+ "cpu-temperature": "{temp}°C",
+ "disk-usage": "{percent}%",
+ "widget-settings-title": "{widget} 设置",
+ "unknown-app": "未知应用",
+ "no-media-player-detected": "未检测到媒体播放器",
+ "user-requested": "用户请求",
+ "unknown": "未知",
+ "unknown-version": "未知",
+ "unknown-layout": "未知"
+ },
+ "lock-screen": {
+ "secure-terminal": "安全终端",
+ "unlock-command": "sudo unlock-session",
+ "password": "密码:",
+ "shut-down": "关机",
+ "restart": "重启",
+ "suspend": "挂起"
+ },
+ "toast": {
+ "night-light": {
+ "enabled": "已启用",
+ "disabled": "已禁用",
+ "not-installed": "未安装 wlsunset",
+ "forced": "强制激活",
+ "normal": "正常模式"
+ },
+ "keep-awake": {
+ "enabled": "已启用",
+ "disabled": "已禁用"
+ },
+ "matugen": {
+ "enabled": "已启用",
+ "disabled": "已禁用",
+ "not-installed": "未安装"
+ },
+ "recording": {
+ "stopping": "正在停止录制…",
+ "started": "录制已开始",
+ "saved": "录制已保存",
+ "failed-start": "开始录制失败",
+ "failed-gpu": "gpu-screen-recorder 意外退出。",
+ "failed-general": "录制器因错误退出。",
+ "no-portals": "桌面门户未运行",
+ "no-portals-desc": "请启动 xdg-desktop-portal 和一个合成器门户 (wlr/hyprland/gnome/kde)。"
+ },
+ "clipboard": {
+ "unavailable": "剪贴板历史记录不可用",
+ "unavailable-desc": "未安装 'cliphist' 应用程序。请安装它以使用剪贴板历史记录功能。"
+ },
+ "ipc": {
+ "powerpanel-deprecated": "PowerPanel 已重命名为 SessionMenu,此 IPC 调用将很快弃用。请改用 \"ipc call sessionMenu toggle\"。",
+ "sidepanel-deprecated": "SidePanel 已重命名为 ControlCenter,此 IPC 调用将很快弃用。请改用 \"ipc call controlCenter toggle\"。"
+ },
+ "wifi": {
+ "enabled": "已启用",
+ "disabled": "已禁用",
+ "connected": "已连接到 '{ssid}'",
+ "disconnected": "已断开与 '{ssid}' 的连接"
+ },
+ "bluetooth": {
+ "enabled": "已启用",
+ "disabled": "已禁用"
+ },
+ "do-not-disturb": {
+ "enabled": "'勿扰模式'已启用",
+ "disabled": "'勿扰模式'已禁用",
+ "enabled-desc": "您可以在历史记录中找到这些通知。",
+ "disabled-desc": "显示所有通知。"
+ },
+ "power-profile": {
+ "changed": "电源模式已更改",
+ "profile-name": "\"{profile}\""
+ },
+ "audio": {
+ "muted": "已静音",
+ "unmuted": "已取消静音"
},
"battery": {
- "no-battery-detected": "未检测到电池。",
- "charging-rate": "充电速率:{rate} W。",
- "discharging-rate": "放电速率:{rate} W。",
- "charging": "正在充电。",
- "discharging": "正在放电。"
+ "low": "电量低",
+ "low-desc": "电量为 {percent}%。请连接充电器。"
+ },
+ "missing-control-center": {
+ "label": "最后一个控制中心小部件已移除",
+ "description": "控制中心小部件已从状态栏中移除。要再次从状态栏访问它,您需要重新添加小部件。"
}
+ },
+ "weather": {
+ "clear-sky": "晴朗",
+ "mainly-clear": "基本晴朗",
+ "partly-cloudy": "局部多云",
+ "overcast": "阴天",
+ "fog": "雾",
+ "drizzle": "毛毛雨",
+ "snow": "雪",
+ "rain-showers": "阵雨",
+ "thunderstorm": "雷暴",
+ "unknown": "未知"
+ },
+ "authentication": {
+ "failed": "认证失败",
+ "error": "认证错误"
+ },
+ "general": {
+ "no-results": "无结果",
+ "no-summary": "无摘要",
+ "unknown": "未知"
+ },
+ "battery": {
+ "no-battery-detected": "未检测到电池。",
+ "charging-rate": "充电速率:{rate} W。",
+ "discharging-rate": "放电速率:{rate} W。",
+ "charging": "正在充电。",
+ "discharging": "正在放电。"
}
+}
diff --git a/Assets/settings-default.json b/Assets/settings-default.json
index 55a851c8..3fddf7cd 100644
--- a/Assets/settings-default.json
+++ b/Assets/settings-default.json
@@ -1,5 +1,5 @@
{
- "settingsVersion": 8,
+ "settingsVersion": 12,
"bar": {
"position": "top",
"backgroundOpacity": 1,
@@ -51,9 +51,6 @@
{
"id": "Brightness"
},
- {
- "id": "NightLight"
- },
{
"id": "Clock"
},
@@ -70,7 +67,8 @@
"forceBlackScreenCorners": false,
"radiusRatio": 1,
"screenRadiusRatio": 1,
- "animationSpeed": 1
+ "animationSpeed": 1,
+ "animationDisabled": false
},
"location": {
"name": "Tokyo",
@@ -120,8 +118,7 @@
"pinnedApps": []
},
"network": {
- "wifiEnabled": true,
- "bluetoothEnabled": true
+ "wifiEnabled": true
},
"notifications": {
"doNotDisturb": false,
@@ -161,7 +158,8 @@
"colorSchemes": {
"useWallpaperColors": false,
"predefinedScheme": "Noctalia (default)",
- "darkMode": true
+ "darkMode": true,
+ "matugenSchemeType": "scheme-fruit-salad"
},
"matugen": {
"gtk4": false,
diff --git a/Bin/notifications-test.sh b/Bin/notifications-test.sh
index 32ecd9d2..789b036b 100755
--- a/Bin/notifications-test.sh
+++ b/Bin/notifications-test.sh
@@ -41,6 +41,6 @@ gdbus call --session \
"dialog-question" \
"Confirmation Required" \
"Do you want to proceed with the action?" \
- "['default', 'OK', 'cancel', 'Cancel']" \
+ "['default', 'OK', 'cancel', 'Cancel', 'maybe', 'Maybe', 'undecided', 'Undecided']" \
"{}" \
- 5000
\ No newline at end of file
+ 5000
diff --git a/Commons/Settings.qml b/Commons/Settings.qml
index 819f11be..bed06a98 100644
--- a/Commons/Settings.qml
+++ b/Commons/Settings.qml
@@ -54,7 +54,7 @@ Singleton {
// Then it should be commented out again, regular users don't need to generate
// default settings on every start
// TODO: automate this someday!
- //generateDefaultSettings()
+ // generateDefaultSettings()
// Patch-in the local default, resolved to user's home
adapter.general.avatarImage = defaultAvatar
@@ -114,7 +114,7 @@ Singleton {
JsonAdapter {
id: adapter
- property int settingsVersion: 8
+ property int settingsVersion: 12
// bar
property JsonObject bar: JsonObject {
@@ -158,8 +158,6 @@ Singleton {
"id": "Volume"
}, {
"id": "Brightness"
- }, {
- "id": "NightLight"
}, {
"id": "Clock"
}, {
@@ -177,6 +175,7 @@ Singleton {
property real radiusRatio: 1.0
property real screenRadiusRatio: 1.0
property real animationSpeed: 1.0
+ property bool animationDisabled: false
}
// location
@@ -241,7 +240,6 @@ Singleton {
// network
property JsonObject network: JsonObject {
property bool wifiEnabled: true
- property bool bluetoothEnabled: true
}
// notifications
@@ -293,6 +291,7 @@ Singleton {
property bool useWallpaperColors: false
property string predefinedScheme: "Noctalia (default)"
property bool darkMode: true
+ property string matugenSchemeType: "scheme-fruit-salad"
}
// matugen templates toggles
diff --git a/Commons/Style.qml b/Commons/Style.qml
index c8607f79..ab09232f 100644
--- a/Commons/Style.qml
+++ b/Commons/Style.qml
@@ -60,10 +60,10 @@ Singleton {
property real opacityFull: 1.0
// Animation duration (ms)
- property int animationFast: Math.round(150 / Settings.data.general.animationSpeed)
- property int animationNormal: Math.round(300 / Settings.data.general.animationSpeed)
- property int animationSlow: Math.round(450 / Settings.data.general.animationSpeed)
- property int animationSlowest: Math.round(750 / Settings.data.general.animationSpeed)
+ property int animationFast: Settings.data.general.animationDisabled ? 0 : Math.round(150 / Settings.data.general.animationSpeed)
+ property int animationNormal: Settings.data.general.animationDisabled ? 0 : Math.round(300 / Settings.data.general.animationSpeed)
+ property int animationSlow: Settings.data.general.animationDisabled ? 0 : Math.round(450 / Settings.data.general.animationSpeed)
+ property int animationSlowest: Settings.data.general.animationDisabled ? 0 : Math.round(750 / Settings.data.general.animationSpeed)
// Delays
property int tooltipDelay: 300
diff --git a/Commons/TablerIcons.qml b/Commons/TablerIcons.qml
index 2044503a..13b60e33 100644
--- a/Commons/TablerIcons.qml
+++ b/Commons/TablerIcons.qml
@@ -148,7 +148,8 @@ Singleton {
"filepicker-file": "file",
"filepicker-text": "file-text",
"filepicker-eye": "eye",
- "filepicker-eye-off": "eye-off"
+ "filepicker-eye-off": "eye-off",
+ "filepicker-folder-current": "checks"
}
// Fonts Codepoints - do not change!
diff --git a/Modules/Bar/Bluetooth/BluetoothPanel.qml b/Modules/Bar/Bluetooth/BluetoothPanel.qml
index 3f4773ab..c625f1f1 100644
--- a/Modules/Bar/Bluetooth/BluetoothPanel.qml
+++ b/Modules/Bar/Bluetooth/BluetoothPanel.qml
@@ -44,13 +44,13 @@ NPanel {
NToggle {
id: bluetoothSwitch
- checked: Settings.data.network.bluetoothEnabled
+ checked: BluetoothService.enabled
onToggled: checked => BluetoothService.setBluetoothEnabled(checked)
baseSize: Style.baseWidgetSize * 0.65 * scaling
}
NIconButton {
- enabled: Settings.data.network.bluetoothEnabled
+ enabled: BluetoothService.enabled
icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop" : "refresh"
tooltipText: I18n.tr("tooltips.refresh-devices")
baseSize: Style.baseWidgetSize * 0.8
diff --git a/Modules/Bar/Extras/BarPillHorizontal.qml b/Modules/Bar/Extras/BarPillHorizontal.qml
index f32bfc48..4962153c 100644
--- a/Modules/Bar/Extras/BarPillHorizontal.qml
+++ b/Modules/Bar/Extras/BarPillHorizontal.qml
@@ -46,6 +46,15 @@ Item {
width: pillHeight + Math.max(0, pill.width - pillOverlap)
height: pillHeight
+ Connections {
+ target: root
+ function onTooltipTextChanged() {
+ if (PanelService.tooltip.visible) {
+ PanelService.tooltip.updateText(root.tooltipText)
+ }
+ }
+ }
+
Rectangle {
id: pill
width: revealed ? pillMaxWidth : 1
@@ -195,14 +204,6 @@ Item {
}
}
- NTooltip {
- id: tooltip
- positionAbove: Settings.data.bar.position === "bottom"
- target: pill
- delay: Style.tooltipDelayLong
- text: root.tooltipText
- }
-
Timer {
id: showTimer
interval: Style.pillDelay
@@ -220,7 +221,7 @@ Item {
onEntered: {
hovered = true
root.entered()
- tooltip.show()
+ PanelService.tooltip.show(pill, root.tooltipText, BarService.getTooltipDirection(), Style.tooltipDelayLong)
if (disableOpen || forceClose) {
return
}
@@ -234,7 +235,7 @@ Item {
if (!forceOpen && !forceClose) {
hide()
}
- tooltip.hide()
+ PanelService.tooltip.hide()
}
onClicked: function (mouse) {
if (mouse.button === Qt.LeftButton) {
diff --git a/Modules/Bar/Extras/BarPillVertical.qml b/Modules/Bar/Extras/BarPillVertical.qml
index 494083e4..f24ff086 100644
--- a/Modules/Bar/Extras/BarPillVertical.qml
+++ b/Modules/Bar/Extras/BarPillVertical.qml
@@ -58,6 +58,15 @@ Item {
width: buttonSize
height: revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize
+ Connections {
+ target: root
+ function onTooltipTextChanged() {
+ if (PanelService.tooltip.visible) {
+ PanelService.tooltip.updateText(root.tooltipText)
+ }
+ }
+ }
+
Rectangle {
id: pill
width: revealed ? maxPillWidth : 1
@@ -236,16 +245,6 @@ Item {
}
}
- NTooltip {
- id: tooltip
- target: pill
- text: root.tooltipText
- positionLeft: barPosition === "right"
- positionRight: barPosition === "left"
- positionAbove: Settings.data.bar.position === "bottom"
- delay: Style.tooltipDelayLong
- }
-
Timer {
id: showTimer
interval: Style.pillDelay
@@ -263,7 +262,7 @@ Item {
onEntered: {
hovered = true
root.entered()
- tooltip.show()
+ PanelService.tooltip.show(pill, root.tooltipText, BarService.getTooltipDirection(), Style.tooltipDelayLong)
if (disableOpen || forceClose) {
return
}
@@ -277,7 +276,7 @@ Item {
if (!forceOpen && !forceClose) {
hide()
}
- tooltip.hide()
+ PanelService.tooltip.hide()
}
onClicked: function (mouse) {
if (mouse.button === Qt.LeftButton) {
diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml
index 8a43014f..537c53bd 100644
--- a/Modules/Bar/Widgets/ActiveWindow.qml
+++ b/Modules/Bar/Widgets/ActiveWindow.qml
@@ -328,29 +328,17 @@ Item {
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onEntered: {
- if (barPosition === "left" || barPosition === "right") {
- tooltip.show()
- } else if ((tooltip.text !== "") && (scrollingMode === "never")) {
- tooltip.show()
+ if ((windowTitle !== "") && (barPosition === "left" || barPosition === "right") || (scrollingMode === "never")) {
+ PanelService.tooltip.show(root, windowTitle, BarService.getTooltipDirection())
}
}
onExited: {
- tooltip.hide()
+ PanelService.tooltip.hide()
}
}
}
}
- NTooltip {
- id: tooltip
- text: windowTitle
- target: (barPosition === "left" || barPosition === "right") ? verticalLayout : windowActiveRect
- positionLeft: barPosition === "right"
- positionRight: barPosition === "left"
- positionAbove: Settings.data.bar.position === "bottom"
- delay: Style.tooltipDelay
- }
-
Connections {
target: CompositorService
function onActiveWindowChanged() {
diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml
index 04f2757d..e76fa234 100644
--- a/Modules/Bar/Widgets/Bluetooth.qml
+++ b/Modules/Bar/Widgets/Bluetooth.qml
@@ -19,9 +19,9 @@ NIconButton {
colorFg: Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
-
- icon: Settings.data.network.bluetoothEnabled ? "bluetooth" : "bluetooth-off"
tooltipText: I18n.tr("tooltips.bluetooth-devices")
+ tooltipDirection: BarService.getTooltipDirection()
+ icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off"
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
onRightClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
}
diff --git a/Modules/Bar/Widgets/Clock.qml b/Modules/Bar/Widgets/Clock.qml
index 4a21bb10..29bce8c6 100644
--- a/Modules/Bar/Widgets/Clock.qml
+++ b/Modules/Bar/Widgets/Clock.qml
@@ -106,12 +106,6 @@ Rectangle {
}
}
}
- NTooltip {
- id: tooltip
- text: I18n.tr("clock.tooltip")
- target: clockContainer
- positionAbove: Settings.data.bar.position === "bottom"
- }
MouseArea {
id: clockMouseArea
@@ -120,14 +114,14 @@ Rectangle {
hoverEnabled: true
onEntered: {
if (!PanelService.getPanel("calendarPanel")?.active) {
- tooltip.show()
+ PanelService.tooltip.show(root, I18n.tr("clock.tooltip"), BarService.getTooltipDirection())
}
}
onExited: {
- tooltip.hide()
+ PanelService.tooltip.hide()
}
onClicked: {
- tooltip.hide()
+ PanelService.tooltip.hide()
PanelService.getPanel("calendarPanel")?.toggle(this)
}
}
diff --git a/Modules/Bar/Widgets/ControlCenter.qml b/Modules/Bar/Widgets/ControlCenter.qml
index a81199de..69c1b39b 100644
--- a/Modules/Bar/Widgets/ControlCenter.qml
+++ b/Modules/Bar/Widgets/ControlCenter.qml
@@ -36,6 +36,7 @@ NIconButton {
// If we have a custom path or distro logo, don't use the theme icon.
icon: (customIconPath === "" && !useDistroLogo) ? customIcon : ""
tooltipText: I18n.tr("tooltips.open-control-center")
+ tooltipDirection: BarService.getTooltipDirection()
baseSize: Style.capsuleHeight
compact: (Settings.data.bar.density === "compact")
colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
diff --git a/Modules/Bar/Widgets/DarkMode.qml b/Modules/Bar/Widgets/DarkMode.qml
index 1043b225..b35dd236 100644
--- a/Modules/Bar/Widgets/DarkMode.qml
+++ b/Modules/Bar/Widgets/DarkMode.qml
@@ -11,6 +11,7 @@ NIconButton {
icon: "dark-mode"
tooltipText: Settings.data.colorSchemes.darkMode ? I18n.tr("tooltips.switch-to-light-mode") : I18n.tr("tooltips.switch-to-dark-mode")
+ tooltipDirection: BarService.getTooltipDirection()
compact: (Settings.data.bar.density === "compact")
baseSize: Style.capsuleHeight
colorBg: Settings.data.colorSchemes.darkMode ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary
diff --git a/Modules/Bar/Widgets/KeepAwake.qml b/Modules/Bar/Widgets/KeepAwake.qml
index 91ca6af2..ba09d92a 100644
--- a/Modules/Bar/Widgets/KeepAwake.qml
+++ b/Modules/Bar/Widgets/KeepAwake.qml
@@ -15,6 +15,7 @@ NIconButton {
compact: (Settings.data.bar.density === "compact")
icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off"
tooltipText: IdleInhibitorService.isInhibited ? I18n.tr("tooltips.disable-keep-awake") : I18n.tr("tooltips.enable-keep-awake")
+ tooltipDirection: BarService.getTooltipDirection()
colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mOnSurface
colorBorder: Color.transparent
diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml
index 002fc67c..53914fcb 100644
--- a/Modules/Bar/Widgets/MediaMini.qml
+++ b/Modules/Bar/Widgets/MediaMini.qml
@@ -42,6 +42,21 @@ Item {
// Fixed width - no expansion
readonly property real widgetWidth: Math.max(1, screen.width * 0.06)
+ readonly property string tooltipText: {
+ var title = getTitle()
+ var controls = ""
+ if (MediaService.canGoNext) {
+ controls += "Right click for next.\n"
+ }
+ if (MediaService.canGoPrevious) {
+ controls += "Middle click for previous."
+ }
+ if (controls !== "") {
+ return title + "\n\n" + controls
+ }
+ return title
+ }
+
implicitHeight: visible ? ((barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling)) : 0
implicitWidth: visible ? ((barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (widgetWidth * scaling)) : 0
@@ -360,39 +375,14 @@ Item {
}
onEntered: {
- if ((tooltip.text !== "") && (barPosition === "left" || barPosition === "right")) {
- tooltip.show()
- } else if ((tooltip.text !== "") && (scrollingMode === "never")) {
- tooltip.show()
+ if ((tooltipText !== "") && (barPosition === "left" || barPosition === "right") || (scrollingMode === "never")) {
+ PanelService.tooltip.show(root, tooltipText, BarService.getTooltipDirection())
}
}
onExited: {
- tooltip.hide()
+ PanelService.tooltip.hide()
}
}
}
}
-
- NTooltip {
- id: tooltip
- text: {
- var title = getTitle()
- var controls = ""
- if (MediaService.canGoNext) {
- controls += "Right click for next.\n"
- }
- if (MediaService.canGoPrevious) {
- controls += "Middle click for previous."
- }
- if (controls !== "") {
- return title + "\n\n" + controls
- }
- return title
- }
- target: (barPosition === "left" || barPosition === "right") ? verticalLayout : mediaMini
- positionLeft: barPosition === "right"
- positionRight: barPosition === "left"
- positionAbove: Settings.data.bar.position === "bottom"
- delay: Style.tooltipDelay
- }
}
diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml
index 3be8cf53..b972d37d 100644
--- a/Modules/Bar/Widgets/NightLight.qml
+++ b/Modules/Bar/Widgets/NightLight.qml
@@ -23,7 +23,14 @@ NIconButton {
icon: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? "nightlight-forced" : "nightlight-on") : "nightlight-off"
tooltipText: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? I18n.tr("tooltips.night-light-forced") : I18n.tr("tooltips.night-light-enabled")) : I18n.tr("tooltips.night-light-disabled")
+ tooltipDirection: BarService.getTooltipDirection()
onClicked: {
+ // Check if wlsunset is available before enabling night light
+ if (!ProgramCheckerService.wlsunsetAvailable) {
+ ToastService.showWarning(I18n.tr("settings.display.night-light.section.label"), I18n.tr("toast.night-light.not-installed"))
+ return
+ }
+
if (!Settings.data.nightLight.enabled) {
Settings.data.nightLight.enabled = true
Settings.data.nightLight.forced = false
diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml
index d33f3116..2fee32ae 100644
--- a/Modules/Bar/Widgets/NotificationHistory.qml
+++ b/Modules/Bar/Widgets/NotificationHistory.qml
@@ -53,6 +53,7 @@ NIconButton {
compact: (Settings.data.bar.density === "compact")
icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell"
tooltipText: Settings.data.notifications.doNotDisturb ? I18n.tr("tooltips.open-notification-history-disable-dnd") : I18n.tr("tooltips.open-notification-history-enable-dnd")
+ tooltipDirection: BarService.getTooltipDirection()
colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
colorFg: Color.mOnSurface
colorBorder: Color.transparent
diff --git a/Modules/Bar/Widgets/PowerProfile.qml b/Modules/Bar/Widgets/PowerProfile.qml
index 691c72ca..fbd2a719 100644
--- a/Modules/Bar/Widgets/PowerProfile.qml
+++ b/Modules/Bar/Widgets/PowerProfile.qml
@@ -19,6 +19,7 @@ NIconButton {
tooltipText: I18n.tr("tooltips.power-profile", {
"profile": PowerProfileService.getName()
})
+ tooltipDirection: BarService.getTooltipDirection()
compact: (Settings.data.bar.density === "compact")
colorBg: (PowerProfileService.profile === PowerProfile.Balanced) ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary
colorFg: (PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnSurface : Color.mOnPrimary
diff --git a/Modules/Bar/Widgets/ScreenRecorder.qml b/Modules/Bar/Widgets/ScreenRecorder.qml
index 28b5e7c2..5149a3a6 100644
--- a/Modules/Bar/Widgets/ScreenRecorder.qml
+++ b/Modules/Bar/Widgets/ScreenRecorder.qml
@@ -12,6 +12,7 @@ NIconButton {
icon: "camera-video"
tooltipText: ScreenRecorderService.isRecording ? I18n.tr("tooltips.click-to-stop-recording") : I18n.tr("tooltips.click-to-start-recording")
+ tooltipDirection: BarService.getTooltipDirection()
compact: (Settings.data.bar.density === "compact")
baseSize: Style.capsuleHeight
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
diff --git a/Modules/Bar/Widgets/SessionMenu.qml b/Modules/Bar/Widgets/SessionMenu.qml
index 8aea7785..f8f09929 100644
--- a/Modules/Bar/Widgets/SessionMenu.qml
+++ b/Modules/Bar/Widgets/SessionMenu.qml
@@ -15,6 +15,7 @@ NIconButton {
baseSize: Style.capsuleHeight
icon: "power"
tooltipText: I18n.tr("tooltips.session-menu")
+ tooltipDirection: BarService.getTooltipDirection()
colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
colorFg: Color.mError
colorBorder: Color.transparent
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index 2c14b242..2376af86 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -39,12 +39,39 @@ Rectangle {
readonly property bool showNetworkStats: (widgetSettings.showNetworkStats !== undefined) ? widgetSettings.showNetworkStats : widgetMetadata.showNetworkStats
readonly property bool showDiskUsage: (widgetSettings.showDiskUsage !== undefined) ? widgetSettings.showDiskUsage : widgetMetadata.showDiskUsage
+ readonly property real iconSize: textSize * 1.4
readonly property real textSize: {
var base = isVertical ? width * 0.82 : height
return Math.max(1, compact ? base * 0.43 : base * 0.33)
}
- readonly property real iconSize: textSize * 1.25
+ readonly property int percentTextWidth: Math.ceil(percentMetrics.tightBoundingRect.width + 2)
+ readonly property int tempTextWidth: Math.ceil(tempMetrics.tightBoundingRect.width + 2)
+ readonly property int memTextWidth: Math.ceil(memMetrics.tightBoundingRect.width + 2)
+
+ TextMetrics {
+ id: percentMetrics
+ font.family: Settings.data.ui.fontFixed
+ font.weight: Style.fontWeightMedium
+ font.pointSize: textSize
+ text: "99%" // Use the longest possible string for measurement
+ }
+
+ TextMetrics {
+ id: tempMetrics
+ font.family: Settings.data.ui.fontFixed
+ font.weight: Style.fontWeightMedium
+ font.pointSize: textSize
+ text: "99°" // Use the longest possible string for measurement
+ }
+
+ TextMetrics {
+ id: memMetrics
+ font.family: Settings.data.ui.fontFixed
+ font.weight: Style.fontWeightMedium
+ font.pointSize: textSize
+ text: "99.9K" // Longest value part of network speed
+ }
anchors.centerIn: parent
implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : Math.round(mainGrid.implicitWidth + Style.marginM * 2 * scaling)
@@ -55,18 +82,15 @@ Rectangle {
GridLayout {
id: mainGrid
anchors.centerIn: parent
-
- // Dynamic layout based on bar orientation
flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: isVertical ? -1 : 1
columns: isVertical ? 1 : -1
-
- rowSpacing: isVertical ? (Style.marginS * scaling) : (Style.marginXS * scaling)
- columnSpacing: isVertical ? (Style.marginXS * scaling) : (Style.marginXS * scaling)
+ rowSpacing: isVertical ? (Style.marginM * scaling) : 0
+ columnSpacing: isVertical ? 0 : (Style.marginM * scaling)
// CPU Usage Component
Item {
- Layout.preferredWidth: cpuUsageContent.implicitWidth
+ Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showCpuUsage
@@ -80,19 +104,6 @@ Rectangle {
rowSpacing: Style.marginXXS * scaling
columnSpacing: Style.marginXXS * scaling
- NText {
- text: isVertical ? `${Math.round(SystemStatService.cpuUsage)}%` : `${SystemStatService.cpuUsage}%`
- font.family: Settings.data.ui.fontFixed
- font.pointSize: textSize
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignCenter
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
- Layout.row: isVertical ? 0 : 0
- Layout.column: isVertical ? 0 : 1
- }
-
NIcon {
icon: "cpu-usage"
font.pointSize: iconSize
@@ -100,12 +111,27 @@ Rectangle {
Layout.row: isVertical ? 1 : 0
Layout.column: 0
}
+
+ NText {
+ text: `${Math.round(SystemStatService.cpuUsage)}%`
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: textSize
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignCenter
+ Layout.preferredWidth: isVertical ? -1 : percentTextWidth
+ horizontalAlignment: isVertical ? Text.AlignHCenter : Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ Layout.row: isVertical ? 0 : 0
+ Layout.column: isVertical ? 0 : 1
+ scale: isVertical ? Math.min(1.0, root.width / implicitWidth) : 1.0
+ }
}
}
// CPU Temperature Component
Item {
- Layout.preferredWidth: cpuTempContent.implicitWidth
+ Layout.preferredWidth: isVertical ? root.width : (iconSize + tempTextWidth) + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showCpuTemp
@@ -119,22 +145,6 @@ Rectangle {
rowSpacing: Style.marginXXS * scaling
columnSpacing: Style.marginXXS * scaling
- NText {
- text: I18n.tr("system.cpu-temperature", {
- "temp": SystemStatService.cpuTemp
- })
- font.family: Settings.data.ui.fontFixed
- font.pointSize: textSize
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignCenter
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
- scale: isVertical ? Math.min(1.0, cpuTempContent.width / implicitWidth) : 1.0
- Layout.row: isVertical ? 0 : 0
- Layout.column: isVertical ? 0 : 1
- }
-
NIcon {
icon: "cpu-temperature"
font.pointSize: iconSize
@@ -142,12 +152,27 @@ Rectangle {
Layout.row: isVertical ? 1 : 0
Layout.column: 0
}
+
+ NText {
+ text: `${Math.round(SystemStatService.cpuTemp)}°`
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: textSize
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignCenter
+ Layout.preferredWidth: isVertical ? -1 : tempTextWidth
+ horizontalAlignment: isVertical ? Text.AlignHCenter : Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ Layout.row: isVertical ? 0 : 0
+ Layout.column: isVertical ? 0 : 1
+ scale: isVertical ? Math.min(1.0, root.width / implicitWidth) : 1.0
+ }
}
}
// Memory Usage Component
Item {
- Layout.preferredWidth: memoryContent.implicitWidth
+ Layout.preferredWidth: isVertical ? root.width : iconSize + (showMemoryAsPercent ? percentTextWidth : memTextWidth) + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showMemoryUsage
@@ -161,25 +186,6 @@ Rectangle {
rowSpacing: Style.marginXXS * scaling
columnSpacing: Style.marginXXS * scaling
- NText {
- text: {
- if (showMemoryAsPercent) {
- return `${SystemStatService.memPercent}%`
- } else {
- return isVertical ? `${Math.round(SystemStatService.memGb)}G` : `${SystemStatService.memGb}G`
- }
- }
- font.family: Settings.data.ui.fontFixed
- font.pointSize: textSize
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignCenter
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
- Layout.row: isVertical ? 0 : 0
- Layout.column: isVertical ? 0 : 1
- }
-
NIcon {
icon: "memory"
font.pointSize: iconSize
@@ -187,12 +193,27 @@ Rectangle {
Layout.row: isVertical ? 1 : 0
Layout.column: 0
}
+
+ NText {
+ text: showMemoryAsPercent ? `${Math.round(SystemStatService.memPercent)}%` : `${SystemStatService.memGb.toFixed(1)}G`
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: textSize
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignCenter
+ Layout.preferredWidth: isVertical ? -1 : (showMemoryAsPercent ? percentTextWidth : memTextWidth)
+ horizontalAlignment: isVertical ? Text.AlignHCenter : Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ Layout.row: isVertical ? 0 : 0
+ Layout.column: isVertical ? 0 : 1
+ scale: isVertical ? Math.min(1.0, root.width / implicitWidth) : 1.0
+ }
}
}
// Network Download Speed Component
Item {
- Layout.preferredWidth: downloadContent.implicitWidth
+ Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showNetworkStats
@@ -204,20 +225,7 @@ Rectangle {
rows: isVertical ? 2 : 1
columns: isVertical ? 1 : 2
rowSpacing: Style.marginXXS * scaling
- columnSpacing: isVertical ? (Style.marginXXS * scaling) : (Style.marginXS * scaling)
-
- NText {
- text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.rxSpeed) : SystemStatService.formatSpeed(SystemStatService.rxSpeed)
- font.family: Settings.data.ui.fontFixed
- font.pointSize: textSize
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignCenter
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
- Layout.row: isVertical ? 0 : 0
- Layout.column: isVertical ? 0 : 1
- }
+ columnSpacing: Style.marginXXS * scaling
NIcon {
icon: "download-speed"
@@ -226,12 +234,27 @@ Rectangle {
Layout.row: isVertical ? 1 : 0
Layout.column: 0
}
+
+ NText {
+ text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.rxSpeed) : SystemStatService.formatSpeed(SystemStatService.rxSpeed)
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: textSize
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignCenter
+ Layout.preferredWidth: isVertical ? -1 : memTextWidth
+ horizontalAlignment: isVertical ? Text.AlignHCenter : Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ Layout.row: isVertical ? 0 : 0
+ Layout.column: isVertical ? 0 : 1
+ scale: isVertical ? Math.min(1.0, root.width / implicitWidth) : 1.0
+ }
}
}
// Network Upload Speed Component
Item {
- Layout.preferredWidth: uploadContent.implicitWidth
+ Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showNetworkStats
@@ -243,20 +266,7 @@ Rectangle {
rows: isVertical ? 2 : 1
columns: isVertical ? 1 : 2
rowSpacing: Style.marginXXS * scaling
- columnSpacing: isVertical ? (Style.marginXXS * scaling) : (Style.marginXS * scaling)
-
- NText {
- text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.txSpeed) : SystemStatService.formatSpeed(SystemStatService.txSpeed)
- font.family: Settings.data.ui.fontFixed
- font.pointSize: textSize
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignCenter
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
- Layout.row: isVertical ? 0 : 0
- Layout.column: isVertical ? 0 : 1
- }
+ columnSpacing: Style.marginXXS * scaling
NIcon {
icon: "upload-speed"
@@ -265,12 +275,27 @@ Rectangle {
Layout.row: isVertical ? 1 : 0
Layout.column: 0
}
+
+ NText {
+ text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.txSpeed) : SystemStatService.formatSpeed(SystemStatService.txSpeed)
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: textSize
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignCenter
+ Layout.preferredWidth: isVertical ? -1 : memTextWidth
+ horizontalAlignment: isVertical ? Text.AlignHCenter : Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ Layout.row: isVertical ? 0 : 0
+ Layout.column: isVertical ? 0 : 1
+ scale: isVertical ? Math.min(1.0, root.width / implicitWidth) : 1.0
+ }
}
}
// Disk Usage Component (primary drive)
Item {
- Layout.preferredWidth: diskContent.implicitWidth
+ Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showDiskUsage
@@ -282,22 +307,7 @@ Rectangle {
rows: isVertical ? 2 : 1
columns: isVertical ? 1 : 2
rowSpacing: Style.marginXXS * scaling
- columnSpacing: isVertical ? (Style.marginXXS * scaling) : (Style.marginXS * scaling)
-
- NText {
- text: I18n.tr("system.disk-usage", {
- "percent": SystemStatService.diskPercent
- })
- font.family: Settings.data.ui.fontFixed
- font.pointSize: textSize
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignCenter
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
- Layout.row: isVertical ? 0 : 0
- Layout.column: isVertical ? 0 : 1
- }
+ columnSpacing: Style.marginXXS * scaling
NIcon {
icon: "storage"
@@ -306,6 +316,21 @@ Rectangle {
Layout.row: isVertical ? 1 : 0
Layout.column: 0
}
+
+ NText {
+ text: `${SystemStatService.diskPercent}%`
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: textSize
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignCenter
+ Layout.preferredWidth: isVertical ? -1 : percentTextWidth
+ horizontalAlignment: isVertical ? Text.AlignHCenter : Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ Layout.row: isVertical ? 0 : 0
+ Layout.column: isVertical ? 0 : 1
+ scale: isVertical ? Math.min(1.0, root.width / implicitWidth) : 1.0
+ }
}
}
}
diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml
index 63e7326d..5f7d7ed3 100644
--- a/Modules/Bar/Widgets/Taskbar.qml
+++ b/Modules/Bar/Widgets/Taskbar.qml
@@ -98,15 +98,8 @@ Rectangle {
}
}
}
- onEntered: taskbarTooltip.show()
- onExited: taskbarTooltip.hide()
- }
-
- NTooltip {
- id: taskbarTooltip
- text: taskbarItem.modelData.title || taskbarItem.modelData.appId || "Unknown app."
- target: taskbarItem
- positionAbove: Settings.data.bar.position === "bottom"
+ onEntered: PanelService.tooltip.show(taskbarItem, taskbarItem.modelData.title || taskbarItem.modelData.appId || "Unknown app.", BarService.getTooltipDirection())
+ onExited: PanelService.tooltip.hide()
}
}
}
diff --git a/Modules/Bar/Widgets/Tray.qml b/Modules/Bar/Widgets/Tray.qml
index 3904a9cf..927ffae9 100644
--- a/Modules/Bar/Widgets/Tray.qml
+++ b/Modules/Bar/Widgets/Tray.qml
@@ -135,15 +135,8 @@ Rectangle {
}
}
}
- onEntered: trayTooltip.show()
- onExited: trayTooltip.hide()
- }
-
- NTooltip {
- id: trayTooltip
- target: trayIcon
- text: modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item"
- positionAbove: Settings.data.bar.position === "bottom"
+ onEntered: PanelService.tooltip.show(trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection())
+ onExited: PanelService.tooltip.hide()
}
}
}
diff --git a/Modules/Bar/Widgets/WallpaperSelector.qml b/Modules/Bar/Widgets/WallpaperSelector.qml
index 341df6df..4be3e9a1 100644
--- a/Modules/Bar/Widgets/WallpaperSelector.qml
+++ b/Modules/Bar/Widgets/WallpaperSelector.qml
@@ -15,6 +15,7 @@ NIconButton {
compact: (Settings.data.bar.density === "compact")
icon: "wallpaper-selector"
tooltipText: I18n.tr("tooltips.open-wallpaper-selector")
+ tooltipDirection: BarService.getTooltipDirection()
colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
colorFg: Color.mOnSurface
colorBorder: Color.transparent
diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml
index 0e8d3f9b..00fefab6 100644
--- a/Modules/Bar/Widgets/WiFi.qml
+++ b/Modules/Bar/Widgets/WiFi.qml
@@ -19,7 +19,8 @@ NIconButton {
colorFg: Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
-
+ tooltipText: I18n.tr("tooltips.manage-wifi")
+ tooltipDirection: BarService.getTooltipDirection()
icon: {
try {
if (NetworkService.ethernetConnected) {
@@ -40,7 +41,6 @@ NIconButton {
return "signal_wifi_bad"
}
}
- tooltipText: I18n.tr("tooltips.manage-wifi")
onClicked: PanelService.getPanel("wifiPanel")?.toggle(this)
onRightClicked: PanelService.getPanel("wifiPanel")?.toggle(this)
}
diff --git a/Modules/Dock/Dock.qml b/Modules/Dock/Dock.qml
index f6135c37..6b8d7484 100644
--- a/Modules/Dock/Dock.qml
+++ b/Modules/Dock/Dock.qml
@@ -373,14 +373,6 @@ Variants {
}
}
- // Individual tooltip for this app
- NTooltip {
- id: appTooltip
- target: appButton
- positionAbove: true
- visible: false
- }
-
Image {
id: appIcon
width: iconSize
@@ -481,8 +473,8 @@ Variants {
onEntered: {
anyAppHovered = true
const appName = appButton.appTitle || appButton.appId || "Unknown"
- appTooltip.text = appName.length > 40 ? appName.substring(0, 37) + "..." : appName
- appTooltip.isVisible = true
+ const tooltipText = appName.length > 40 ? appName.substring(0, 37) + "..." : appName
+ PanelService.tooltip.show(appButton, tooltipText, "top")
if (autoHide) {
showTimer.stop()
hideTimer.stop()
@@ -492,7 +484,7 @@ Variants {
onExited: {
anyAppHovered = false
- appTooltip.hide()
+ PanelService.tooltip.hide()
if (autoHide && !dockHovered && !peekHovered && !menuHovered) {
hideTimer.restart()
}
@@ -508,7 +500,7 @@ Variants {
// Close any other existing context menu first
root.closeAllContextMenus()
// Hide tooltip when showing context menu
- appTooltip.hide()
+ PanelService.tooltip.hide()
contextMenu.show(appButton, modelData.toplevel || modelData)
return
}
diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml
index 3cf73d3f..b7f48abe 100644
--- a/Modules/Notification/Notification.qml
+++ b/Modules/Notification/Notification.qml
@@ -341,11 +341,14 @@ Variants {
}
// Notification actions
- RowLayout {
+ Flow {
Layout.fillWidth: true
spacing: Style.marginS * scaling
Layout.topMargin: Style.marginM * scaling
+ flow: Flow.LeftToRight
+ layoutDirection: Qt.LeftToRight
+
// Store the notification ID for access in button delegates
property string parentNotificationId: notificationId
@@ -378,17 +381,12 @@ Variants {
textColor: hovered ? Color.mOnTertiary : Color.mOnPrimary
hoverColor: Color.mTertiary
outlined: false
- Layout.preferredHeight: 24 * scaling
+ implicitHeight: 24 * scaling
onClicked: {
NotificationService.invokeAction(parent.parentNotificationId, actionData.identifier)
}
}
}
-
- // Spacer to push buttons to the left
- Item {
- Layout.fillWidth: true
- }
}
}
}
diff --git a/Modules/OSD/OSD.qml b/Modules/OSD/OSD.qml
index 1ad395a7..059dcb5d 100644
--- a/Modules/OSD/OSD.qml
+++ b/Modules/OSD/OSD.qml
@@ -410,10 +410,10 @@ Variants {
// Make visible and animate in
osdItem.visible = true
// Use Qt.callLater to ensure the visible change is processed before animation
- Qt.callLater(function () {
- osdItem.opacity = 1
- osdItem.scale = 1.0
- })
+ Qt.callLater(() => {
+ osdItem.opacity = 1
+ osdItem.scale = 1.0
+ })
// Start the auto-hide timer
hideTimer.start()
@@ -524,11 +524,11 @@ Variants {
root.item.showOSD()
} else {
// If item not ready yet, wait for it
- Qt.callLater(function () {
- if (root.item) {
- root.item.showOSD()
- }
- })
+ Qt.callLater(() => {
+ if (root.item) {
+ root.item.showOSD()
+ }
+ })
}
}
diff --git a/Modules/Settings/Bar/BarWidgetSettingsDialog.qml b/Modules/Settings/Bar/BarWidgetSettingsDialog.qml
index 68310021..a198b1e3 100644
--- a/Modules/Settings/Bar/BarWidgetSettingsDialog.qml
+++ b/Modules/Settings/Bar/BarWidgetSettingsDialog.qml
@@ -69,6 +69,7 @@ Popup {
NIconButton {
icon: "close"
+ tooltipText: "Close"
onClicked: widgetSettings.close()
}
}
diff --git a/Modules/Settings/Bar/WidgetSettings/ActiveWindowSettings.qml b/Modules/Settings/Bar/WidgetSettings/ActiveWindowSettings.qml
index c2ef8983..f28c4bac 100644
--- a/Modules/Settings/Bar/WidgetSettings/ActiveWindowSettings.qml
+++ b/Modules/Settings/Bar/WidgetSettings/ActiveWindowSettings.qml
@@ -29,20 +29,23 @@ ColumnLayout {
NToggle {
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.active-window.auto-hide")
+ label: I18n.tr("bar.widget-settings.active-window.auto-hide.label")
+ description: I18n.tr("bar.widget-settings.active-window.auto-hide.description")
checked: root.valueAutoHide
onToggled: checked => root.valueAutoHide = checked
}
NToggle {
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.active-window.show-app-icon")
+ label: I18n.tr("bar.widget-settings.active-window.show-app-icon.label")
+ description: I18n.tr("bar.widget-settings.active-window.show-app-icon.description")
checked: root.valueShowIcon
onToggled: checked => root.valueShowIcon = checked
}
NComboBox {
- label: I18n.tr("bar.widget-settings.active-window.scrolling-mode")
+ label: I18n.tr("bar.widget-settings.active-window.scrolling-mode.label")
+ description: I18n.tr("bar.widget-settings.active-window.scrolling-mode.description")
model: [{
"key": "always",
"name": I18n.tr("options.scrolling-modes.always")
diff --git a/Modules/Settings/Bar/WidgetSettings/ControlCenterSettings.qml b/Modules/Settings/Bar/WidgetSettings/ControlCenterSettings.qml
index 75aacb97..cd44b941 100644
--- a/Modules/Settings/Bar/WidgetSettings/ControlCenterSettings.qml
+++ b/Modules/Settings/Bar/WidgetSettings/ControlCenterSettings.qml
@@ -28,7 +28,8 @@ ColumnLayout {
}
NToggle {
- label: I18n.tr("bar.widget-settings.control-center.use-distro-logo")
+ label: I18n.tr("bar.widget-settings.control-center.use-distro-logo.label")
+ description: I18n.tr("bar.widget-settings.control-center.use-distro-logo.description")
checked: valueUseDistroLogo
onToggled: {
valueUseDistroLogo = checked
@@ -90,8 +91,7 @@ ColumnLayout {
NFilePicker {
id: imagePicker
title: I18n.tr("bar.widget-settings.control-center.select-custom-icon")
- selectFiles: true
- selectFolders: false
+ selectionMode: "files"
nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.pnm", "*.bmp"]
initialPath: Quickshell.env("HOME")
onAccepted: paths => {
diff --git a/Modules/Settings/Bar/WidgetSettings/CustomButtonSettings.qml b/Modules/Settings/Bar/WidgetSettings/CustomButtonSettings.qml
index 0733091a..9c7aaed0 100644
--- a/Modules/Settings/Bar/WidgetSettings/CustomButtonSettings.qml
+++ b/Modules/Settings/Bar/WidgetSettings/CustomButtonSettings.qml
@@ -58,7 +58,8 @@ ColumnLayout {
NTextInput {
id: leftClickExecInput
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.custom-button.left-click")
+ label: I18n.tr("bar.widget-settings.custom-button.left-click.label")
+ description: I18n.tr("bar.widget-settings.custom-button.left-click.description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.leftClickExec || widgetMetadata.leftClickExec
}
@@ -66,7 +67,8 @@ ColumnLayout {
NTextInput {
id: rightClickExecInput
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.custom-button.right-click")
+ label: I18n.tr("bar.widget-settings.custom-button.right-click.label")
+ description: I18n.tr("bar.widget-settings.custom-button.right-click.description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.rightClickExec || widgetMetadata.rightClickExec
}
@@ -74,7 +76,8 @@ ColumnLayout {
NTextInput {
id: middleClickExecInput
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.custom-button.middle-click")
+ label: I18n.tr("bar.widget-settings.custom-button.middle-click.label")
+ description: I18n.tr("bar.widget-settings.custom-button.middle-click.description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData.middleClickExec || widgetMetadata.middleClickExec
}
diff --git a/Modules/Settings/Bar/WidgetSettings/MediaMiniSettings.qml b/Modules/Settings/Bar/WidgetSettings/MediaMiniSettings.qml
index d2391434..184a37e5 100644
--- a/Modules/Settings/Bar/WidgetSettings/MediaMiniSettings.qml
+++ b/Modules/Settings/Bar/WidgetSettings/MediaMiniSettings.qml
@@ -32,26 +32,30 @@ ColumnLayout {
NToggle {
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.media-mini.auto-hide")
+ label: I18n.tr("bar.widget-settings.media-mini.auto-hide.label")
+ description: I18n.tr("bar.widget-settings.media-mini.auto-hide.description")
checked: root.valueAutoHide
onToggled: checked => root.valueAutoHide = checked
}
NToggle {
- label: I18n.tr("bar.widget-settings.media-mini.show-album-art")
+ label: I18n.tr("bar.widget-settings.media-mini.show-album-art.label")
+ description: I18n.tr("bar.widget-settings.media-mini.show-album-art.description")
checked: valueShowAlbumArt
onToggled: checked => valueShowAlbumArt = checked
}
NToggle {
- label: I18n.tr("bar.widget-settings.media-mini.show-visualizer")
+ label: I18n.tr("bar.widget-settings.media-mini.show-visualizer.label")
+ description: I18n.tr("bar.widget-settings.media-mini.show-visualizer.description")
checked: valueShowVisualizer
onToggled: checked => valueShowVisualizer = checked
}
NComboBox {
visible: valueShowVisualizer
- label: I18n.tr("bar.widget-settings.media-mini.visualizer-type")
+ label: I18n.tr("bar.widget-settings.media-mini.visualizer-type.label")
+ description: I18n.tr("bar.widget-settings.media-mini.visualizer-type.description")
model: [{
"key": "linear",
"name": I18n.tr("options.visualizer-types.linear")
@@ -68,7 +72,8 @@ ColumnLayout {
}
NComboBox {
- label: I18n.tr("bar.widget-settings.media-mini.scrolling-mode")
+ label: I18n.tr("bar.widget-settings.media-mini.scrolling-mode.label")
+ description: I18n.tr("bar.widget-settings.media-mini.scrolling-mode.description")
model: [{
"key": "always",
"name": I18n.tr("options.scrolling-modes.always")
diff --git a/Modules/Settings/Bar/WidgetSettings/NotificationHistorySettings.qml b/Modules/Settings/Bar/WidgetSettings/NotificationHistorySettings.qml
index 206c2797..4510a605 100644
--- a/Modules/Settings/Bar/WidgetSettings/NotificationHistorySettings.qml
+++ b/Modules/Settings/Bar/WidgetSettings/NotificationHistorySettings.qml
@@ -25,13 +25,15 @@ ColumnLayout {
}
NToggle {
- label: I18n.tr("bar.widget-settings.notification-history.show-unread-badge")
+ label: I18n.tr("bar.widget-settings.notification-history.show-unread-badge.label")
+ description: I18n.tr("bar.widget-settings.notification-history.show-unread-badge.description")
checked: valueShowUnreadBadge
onToggled: checked => valueShowUnreadBadge = checked
}
NToggle {
- label: I18n.tr("bar.widget-settings.notification-history.hide-badge-when-zero")
+ label: I18n.tr("bar.widget-settings.notification-history.hide-badge-when-zero.label")
+ description: I18n.tr("bar.widget-settings.notification-history.hide-badge-when-zero.description")
checked: valueHideWhenZero
onToggled: checked => valueHideWhenZero = checked
}
diff --git a/Modules/Settings/Bar/WidgetSettings/SystemMonitorSettings.qml b/Modules/Settings/Bar/WidgetSettings/SystemMonitorSettings.qml
index b7524c86..852ea8d8 100644
--- a/Modules/Settings/Bar/WidgetSettings/SystemMonitorSettings.qml
+++ b/Modules/Settings/Bar/WidgetSettings/SystemMonitorSettings.qml
@@ -35,7 +35,8 @@ ColumnLayout {
NToggle {
id: showCpuUsage
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.system-monitor.cpu-usage")
+ label: I18n.tr("bar.widget-settings.system-monitor.cpu-usage.label")
+ description: I18n.tr("bar.widget-settings.system-monitor.cpu-usage.description")
checked: valueShowCpuUsage
onToggled: checked => valueShowCpuUsage = checked
}
@@ -43,7 +44,8 @@ ColumnLayout {
NToggle {
id: showCpuTemp
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.system-monitor.cpu-temperature")
+ label: I18n.tr("bar.widget-settings.system-monitor.cpu-temperature.label")
+ description: I18n.tr("bar.widget-settings.system-monitor.cpu-temperature.description")
checked: valueShowCpuTemp
onToggled: checked => valueShowCpuTemp = checked
}
@@ -51,7 +53,8 @@ ColumnLayout {
NToggle {
id: showMemoryUsage
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.system-monitor.memory-usage")
+ label: I18n.tr("bar.widget-settings.system-monitor.memory-usage.label")
+ description: I18n.tr("bar.widget-settings.system-monitor.memory-usage.description")
checked: valueShowMemoryUsage
onToggled: checked => valueShowMemoryUsage = checked
}
@@ -59,15 +62,18 @@ ColumnLayout {
NToggle {
id: showMemoryAsPercent
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.system-monitor.memory-percentage")
+ label: I18n.tr("bar.widget-settings.system-monitor.memory-percentage.label")
+ description: I18n.tr("bar.widget-settings.system-monitor.memory-percentage.description")
checked: valueShowMemoryAsPercent
onToggled: checked => valueShowMemoryAsPercent = checked
+ visible: valueShowMemoryUsage
}
NToggle {
id: showNetworkStats
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.system-monitor.network-traffic")
+ label: I18n.tr("bar.widget-settings.system-monitor.network-traffic.label")
+ description: I18n.tr("bar.widget-settings.system-monitor.network-traffic.description")
checked: valueShowNetworkStats
onToggled: checked => valueShowNetworkStats = checked
}
@@ -75,7 +81,8 @@ ColumnLayout {
NToggle {
id: showDiskUsage
Layout.fillWidth: true
- label: I18n.tr("bar.widget-settings.system-monitor.storage-usage")
+ label: I18n.tr("bar.widget-settings.system-monitor.storage-usage.label")
+ description: I18n.tr("bar.widget-settings.system-monitor.storage-usage.description")
checked: valueShowDiskUsage
onToggled: checked => valueShowDiskUsage = checked
}
diff --git a/Modules/Settings/Bar/WidgetSettings/WorkspaceSettings.qml b/Modules/Settings/Bar/WidgetSettings/WorkspaceSettings.qml
index 27c4b057..b44f16b9 100644
--- a/Modules/Settings/Bar/WidgetSettings/WorkspaceSettings.qml
+++ b/Modules/Settings/Bar/WidgetSettings/WorkspaceSettings.qml
@@ -23,7 +23,8 @@ ColumnLayout {
NComboBox {
id: labelModeCombo
- label: I18n.tr("bar.widget-settings.workspace.label-mode")
+ label: I18n.tr("bar.widget-settings.workspace.label-mode.label")
+ description: I18n.tr("bar.widget-settings.workspace.label-mode.description")
model: [{
"key": "none",
"name": I18n.tr("options.workspace-labels.none")
diff --git a/Modules/Settings/Tabs/ColorSchemeTab.qml b/Modules/Settings/Tabs/ColorSchemeTab.qml
index 443d01be..57f3d399 100644
--- a/Modules/Settings/Tabs/ColorSchemeTab.qml
+++ b/Modules/Settings/Tabs/ColorSchemeTab.qml
@@ -140,16 +140,62 @@ ColumnLayout {
}
}
+ // Matugen Scheme Type Selection
+ NComboBox {
+ label: I18n.tr("settings.color-scheme.color-source.matugen-scheme-type.label")
+ description: I18n.tr("settings.color-scheme.color-source.matugen-scheme-type.description")
+ enabled: Settings.data.colorSchemes.useWallpaperColors
+ opacity: Settings.data.colorSchemes.useWallpaperColors ? 1.0 : 0.6
+ visible: Settings.data.colorSchemes.useWallpaperColors
+
+ model: [{
+ "key": "scheme-content",
+ "name": "Content"
+ }, {
+ "key": "scheme-expressive",
+ "name": "Expressive"
+ }, {
+ "key": "scheme-fidelity",
+ "name": "Fidelity"
+ }, {
+ "key": "scheme-fruit-salad",
+ "name": "Fruit Salad"
+ }, {
+ "key": "scheme-monochrome",
+ "name": "Monochrome"
+ }, {
+ "key": "scheme-neutral",
+ "name": "Neutral"
+ }, {
+ "key": "scheme-rainbow",
+ "name": "Rainbow"
+ }, {
+ "key": "scheme-tonal-spot",
+ "name": "Tonal Spot"
+ }]
+
+ currentKey: Settings.data.colorSchemes.matugenSchemeType
+
+ onSelected: key => {
+ Settings.data.colorSchemes.matugenSchemeType = key
+ if (Settings.data.colorSchemes.useWallpaperColors) {
+ MatugenService.generateFromWallpaper()
+ }
+ }
+ }
+
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
+ visible: !Settings.data.colorSchemes.useWallpaperColors
}
// Predefined Color Schemes
ColumnLayout {
spacing: Style.marginM * scaling
Layout.fillWidth: true
+ visible: !Settings.data.colorSchemes.useWallpaperColors
NHeader {
label: I18n.tr("settings.color-scheme.predefined.section.label")
diff --git a/Modules/Settings/Tabs/GeneralTab.qml b/Modules/Settings/Tabs/GeneralTab.qml
index c2e08693..93cd9c49 100644
--- a/Modules/Settings/Tabs/GeneralTab.qml
+++ b/Modules/Settings/Tabs/GeneralTab.qml
@@ -49,8 +49,7 @@ ColumnLayout {
NFilePicker {
id: avatarPicker
title: I18n.tr("settings.general.profile.select-avatar")
- selectFiles: true
- selectFolders: true
+ selectionMode: "files"
initialPath: Settings.data.general.avatarImage.substr(0, Settings.data.general.avatarImage.lastIndexOf("/")) || Quickshell.env("HOME")
nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.pnm", "*.bmp"]
onAccepted: paths => {
@@ -105,22 +104,35 @@ ColumnLayout {
// Animation Speed
ColumnLayout {
- spacing: Style.marginXXS * scaling
+ spacing: Style.marginL * scaling
Layout.fillWidth: true
- NLabel {
- label: I18n.tr("settings.general.ui.animation-speed.label")
- description: I18n.tr("settings.general.ui.animation-speed.description")
+ NToggle {
+ label: I18n.tr("settings.general.ui.animation-disable.label")
+ description: I18n.tr("settings.general.ui.animation-disable.description")
+ checked: Settings.data.general.animationDisabled
+ onToggled: checked => Settings.data.general.animationDisabled = checked
}
- NValueSlider {
+ ColumnLayout {
+ spacing: Style.marginXXS * scaling
Layout.fillWidth: true
- from: 0.1
- to: 2.0
- stepSize: 0.01
- value: Settings.data.general.animationSpeed
- onMoved: value => Settings.data.general.animationSpeed = value
- text: Math.round(Settings.data.general.animationSpeed * 100) + "%"
+ visible: !Settings.data.general.animationDisabled
+
+ NLabel {
+ label: I18n.tr("settings.general.ui.animation-speed.label")
+ description: I18n.tr("settings.general.ui.animation-speed.description")
+ }
+
+ NValueSlider {
+ Layout.fillWidth: true
+ from: 0.1
+ to: 2.0
+ stepSize: 0.01
+ value: Settings.data.general.animationSpeed
+ onMoved: value => Settings.data.general.animationSpeed = value
+ text: Math.round(Settings.data.general.animationSpeed * 100) + "%"
+ }
}
}
}
diff --git a/Modules/Settings/Tabs/NetworkTab.qml b/Modules/Settings/Tabs/NetworkTab.qml
index 104ac149..b19a0819 100644
--- a/Modules/Settings/Tabs/NetworkTab.qml
+++ b/Modules/Settings/Tabs/NetworkTab.qml
@@ -23,7 +23,7 @@ ColumnLayout {
NToggle {
label: I18n.tr("settings.network.bluetooth.label")
- checked: Settings.data.network.bluetoothEnabled
+ checked: BluetoothService.enabled
onToggled: checked => BluetoothService.setBluetoothEnabled(checked)
}
diff --git a/Modules/Settings/Tabs/ScreenRecorderTab.qml b/Modules/Settings/Tabs/ScreenRecorderTab.qml
index cdd2be99..957579bf 100644
--- a/Modules/Settings/Tabs/ScreenRecorderTab.qml
+++ b/Modules/Settings/Tabs/ScreenRecorderTab.qml
@@ -229,8 +229,7 @@ ColumnLayout {
NFilePicker {
id: folderPicker
- selectFiles: false
- selectFolders: true
+ selectionMode: "folders"
title: I18n.tr("settings.screen-recorder.general.select-output-folder")
initialPath: Settings.data.screenRecorder.directory || Quickshell.env("HOME") + "/Videos"
onAccepted: paths => {
diff --git a/Modules/Settings/Tabs/WallpaperTab.qml b/Modules/Settings/Tabs/WallpaperTab.qml
index fa22c89a..742849b9 100644
--- a/Modules/Settings/Tabs/WallpaperTab.qml
+++ b/Modules/Settings/Tabs/WallpaperTab.qml
@@ -340,8 +340,7 @@ ColumnLayout {
NFilePicker {
id: mainFolderPicker
- selectFiles: false
- selectFolders: true
+ selectionMode: "folders"
title: I18n.tr("settings.wallpaper.settings.select-folder")
initialPath: Settings.data.wallpaper.directory || Quickshell.env("HOME") + "/Pictures"
onAccepted: paths => {
@@ -353,8 +352,7 @@ ColumnLayout {
NFilePicker {
id: monitorFolderPicker
- selectFiles: false
- selectFolders: true
+ selectionMode: "folders"
title: I18n.tr("settings.wallpaper.settings.select-monitor-folder")
initialPath: WallpaperService.getMonitorDirectory(specificFolderMonitorName) || Quickshell.env("HOME") + "/Pictures"
onAccepted: paths => {
diff --git a/Modules/Toast/ToastScreen.qml b/Modules/Toast/ToastScreen.qml
index a701c898..6a635aea 100644
--- a/Modules/Toast/ToastScreen.qml
+++ b/Modules/Toast/ToastScreen.qml
@@ -93,11 +93,11 @@ Item {
// Activate the loader and show toast
windowLoader.active = true
// Need a small delay to ensure the window is created
- Qt.callLater(function () {
- if (windowLoader.item) {
- windowLoader.item.showToast(data.message, data.description, data.type, data.duration)
- }
- })
+ Qt.callLater(() => {
+ if (windowLoader.item) {
+ windowLoader.item.showToast(data.message, data.description, data.type, data.duration)
+ }
+ })
}
function onToastHidden() {
diff --git a/Modules/Tooltip/Tooltip.qml b/Modules/Tooltip/Tooltip.qml
new file mode 100644
index 00000000..495649e1
--- /dev/null
+++ b/Modules/Tooltip/Tooltip.qml
@@ -0,0 +1,407 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import qs.Commons
+import qs.Services
+import qs.Widgets
+
+PopupWindow {
+ id: root
+
+ property string text: ""
+ property string direction: "auto" // "auto", "left", "right", "top", "bottom"
+ property int margin: Style.marginXS // distance from target
+ property int padding: Style.marginM
+ property int delay: 0
+ property int hideDelay: 0
+ property int maxWidth: 340
+ property real scaling: 1.0
+ property int animationDuration: Style.animationFast
+ property real animationScale: 0.85
+
+ // Internal properties
+ property var targetItem: null
+ property real anchorX: 0
+ property real anchorY: 0
+ property bool isPositioned: false
+ property bool pendingShow: false
+ property bool animatingOut: false
+
+ visible: false
+ color: Color.transparent
+
+ anchor.item: targetItem
+ anchor.rect.x: anchorX
+ anchor.rect.y: anchorY
+
+ // Timer for showing tooltip after delay
+ Timer {
+ id: showTimer
+ interval: root.delay
+ repeat: false
+ onTriggered: {
+ root.positionAndShow()
+ }
+ }
+
+ // Timer for hiding tooltip after delay
+ Timer {
+ id: hideTimer
+ interval: root.hideDelay
+ repeat: false
+ onTriggered: {
+ root.startHideAnimation()
+ }
+ }
+
+ // Show animation
+ ParallelAnimation {
+ id: showAnimation
+
+ PropertyAnimation {
+ target: tooltipContainer
+ property: "opacity"
+ from: 0.0
+ to: 1.0
+ duration: root.animationDuration
+ easing.type: Easing.OutCubic
+ }
+
+ PropertyAnimation {
+ target: tooltipContainer
+ property: "scale"
+ from: root.animationScale
+ to: 1.0
+ duration: root.animationDuration
+ easing.type: Easing.OutBack
+ easing.overshoot: 1.2
+ }
+ }
+
+ // Hide animation
+ ParallelAnimation {
+ id: hideAnimation
+
+ PropertyAnimation {
+ target: tooltipContainer
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ duration: root.animationDuration * 0.75 // Slightly faster hide
+ easing.type: Easing.InCubic
+ }
+
+ PropertyAnimation {
+ target: tooltipContainer
+ property: "scale"
+ from: 1.0
+ to: root.animationScale
+ duration: root.animationDuration * 0.75
+ easing.type: Easing.InCubic
+ }
+
+ onFinished: {
+ root.completeHide()
+ }
+ }
+
+ // Function to show tooltip
+ function show(target, tipText, customDirection, showDelay) {
+ if (!target || !tipText || tipText === "")
+ return
+
+ if (showDelay !== undefined) {
+ delay = showDelay
+ } else {
+ delay = Style.tooltipDelay
+ }
+
+ // Stop any running timers and animations
+ hideTimer.stop()
+ showTimer.stop()
+ hideAnimation.stop()
+ animatingOut = false
+
+ // If we're already showing for a different target, hide immediately
+ if (visible && targetItem !== target) {
+ hideImmediately()
+ }
+
+ // Set properties
+ targetItem = target
+ text = tipText
+ pendingShow = true
+
+ if (customDirection !== undefined) {
+ direction = customDirection
+ } else {
+ direction = "auto"
+ }
+
+ // Start show timer
+ showTimer.start()
+ }
+
+ // Function to position and display the tooltip
+ function positionAndShow() {
+ if (!targetItem || !pendingShow)
+ return
+
+ // Get screen dimensions - try multiple methods
+ var screenWidth = Screen.width
+ var screenHeight = Screen.height
+
+ // Try to get screen from target item
+ if (targetItem) {
+ if (targetItem.screen) {
+ screenWidth = targetItem.screen.width
+ screenHeight = targetItem.screen.height
+ scaling = ScalingService.getScreenScale(targetItem.screen)
+ }
+ }
+
+ // Calculate tooltip dimensions
+ const tipWidth = Math.min(tooltipText.implicitWidth + (padding * 2 * scaling), maxWidth * scaling)
+ root.implicitWidth = tipWidth
+
+ const tipHeight = tooltipText.implicitHeight + (padding * 2 * scaling)
+ root.implicitHeight = tipHeight
+
+ // Get target's global position
+ const targetGlobal = targetItem.mapToGlobal(0, 0)
+ const targetWidth = targetItem.width
+ const targetHeight = targetItem.height
+
+ var newAnchorX = 0
+ var newAnchorY = 0
+
+ if (direction === "auto") {
+ // Calculate available space in each direction
+ const spaceLeft = targetGlobal.x
+ const spaceRight = screenWidth - (targetGlobal.x + targetWidth)
+ const spaceTop = targetGlobal.y
+ const spaceBottom = screenHeight - (targetGlobal.y + targetHeight)
+
+ // Try positions in order of available space
+ const positions = [{
+ "dir": "bottom",
+ "space": spaceBottom,
+ "x": (targetWidth - tipWidth) / 2,
+ "y": targetHeight + margin * scaling,
+ "fits": spaceBottom >= tipHeight + margin * scaling
+ }, {
+ "dir": "top",
+ "space": spaceTop,
+ "x": (targetWidth - tipWidth) / 2,
+ "y": -tipHeight - margin * scaling,
+ "fits": spaceTop >= tipHeight + margin * scaling
+ }, {
+ "dir": "right",
+ "space": spaceRight,
+ "x": targetWidth + margin * scaling,
+ "y": (targetHeight - tipHeight) / 2,
+ "fits": spaceRight >= tipWidth + margin * scaling
+ }, {
+ "dir": "left",
+ "space": spaceLeft,
+ "x": -tipWidth - margin * scaling,
+ "y": (targetHeight - tipHeight) / 2,
+ "fits": spaceLeft >= tipWidth + margin * scaling
+ }]
+
+ // Find first position that fits
+ var selectedPosition = null
+ for (var i = 0; i < positions.length; i++) {
+ if (positions[i].fits) {
+ selectedPosition = positions[i]
+ break
+ }
+ }
+
+ // If none fit perfectly
+ if (!selectedPosition) {
+ // Sort by available space and use position with most space
+ positions.sort(function (a, b) {
+ return b.space - a.space
+ })
+ selectedPosition = positions[0]
+ }
+
+ newAnchorX = selectedPosition.x
+ newAnchorY = selectedPosition.y
+
+ // Adjust horizontal position to keep tooltip on screen
+ if (direction === "auto") {
+ const globalX = targetGlobal.x + newAnchorX
+ if (globalX < 0) {
+ newAnchorX = -targetGlobal.x + margin * scaling
+ } else if (globalX + tipWidth > screenWidth) {
+ newAnchorX = screenWidth - targetGlobal.x - tipWidth - margin * scaling
+ }
+ }
+ } else {
+ // Manual direction positioning
+ switch (direction) {
+ case "left":
+ newAnchorX = -tipWidth - margin * scaling
+ newAnchorY = (targetHeight - tipHeight) / 2
+ break
+ case "right":
+ newAnchorX = targetWidth + margin * scaling
+ newAnchorY = (targetHeight - tipHeight) / 2
+ break
+ case "top":
+ newAnchorX = (targetWidth - tipWidth) / 2
+ newAnchorY = -tipHeight - margin * scaling
+ break
+ case "bottom":
+ newAnchorX = (targetWidth - tipWidth) / 2
+ newAnchorY = targetHeight + margin * scaling
+ break
+ }
+ }
+
+ // Apply position
+ anchorX = newAnchorX
+ anchorY = newAnchorY
+ isPositioned = true
+ pendingShow = false
+
+ // Show tooltip and start animation
+ visible = true
+
+ // Initialize animation state
+ tooltipContainer.opacity = 0.0
+ tooltipContainer.scale = animationScale
+
+ // Start show animation
+ showAnimation.start()
+
+ // Force anchor update after showing
+ Qt.callLater(() => {
+ if (root.anchor && root.visible) {
+ root.anchor.updateAnchor()
+ }
+ })
+ }
+
+ // Function to hide tooltip
+ function hide() {
+ // Stop show timer if it's running
+ showTimer.stop()
+ pendingShow = false
+
+ // Stop hide timer if it's running
+ hideTimer.stop()
+
+ if (hideDelay > 0 && visible && !animatingOut) {
+ hideTimer.start()
+ } else {
+ startHideAnimation()
+ }
+ }
+
+ function startHideAnimation() {
+ if (!visible || animatingOut)
+ return
+
+ animatingOut = true
+ showAnimation.stop() // Stop show animation if running
+ hideAnimation.start()
+ }
+
+ function completeHide() {
+ visible = false
+ animatingOut = false
+ pendingShow = false
+ text = ""
+ isPositioned = false
+ tooltipContainer.opacity = 1.0
+ tooltipContainer.scale = 1.0
+ }
+
+ // Quick hide without delay or animation
+ function hideImmediately() {
+ showTimer.stop()
+ hideTimer.stop()
+ showAnimation.stop()
+ hideAnimation.stop()
+ pendingShow = false
+ animatingOut = false
+ completeHide()
+ }
+
+ // Update text function for binding support
+ function updateText(newText) {
+ if (visible && targetItem) {
+ text = newText
+ positionAndShow()
+ }
+ }
+
+ // Reset function to clean up state
+ function reset() {
+ // Stop all timers and animations
+ showTimer.stop()
+ hideTimer.stop()
+ showAnimation.stop()
+ hideAnimation.stop()
+
+ // Clear all state
+ visible = false
+ pendingShow = false
+ animatingOut = false
+ text = ""
+ isPositioned = false
+
+ // Reset to defaults
+ direction = "auto"
+ delay = 0
+ hideDelay = 0
+
+ // Reset container state
+ tooltipContainer.opacity = 1.0
+ tooltipContainer.scale = 1.0
+ }
+
+ // Tooltip content container for animations
+ Item {
+ id: tooltipContainer
+ anchors.fill: parent
+
+ // Animation properties
+ opacity: 1.0
+ scale: 1.0
+ transformOrigin: Item.Center
+
+ Rectangle {
+ anchors.fill: parent
+ color: Color.mSurface
+ border.color: Color.mOutline
+ border.width: Math.max(1, Style.borderS * scaling)
+ radius: Style.radiusS * scaling
+
+ // Only show content when we have text
+ visible: root.text !== ""
+
+ NText {
+ id: tooltipText
+ anchors.centerIn: parent
+ anchors.margins: root.padding * root.scaling
+ text: root.text
+ font.pointSize: Style.fontSizeS * scaling
+ color: Color.mOnSurfaceVariant
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ reset()
+ }
+
+ Component.onDestruction: {
+ reset()
+ }
+}
diff --git a/Services/BarService.qml b/Services/BarService.qml
index 9f8611ed..63e607cc 100644
--- a/Services/BarService.qml
+++ b/Services/BarService.qml
@@ -202,4 +202,17 @@ Singleton {
}
return false
}
+
+ function getTooltipDirection() {
+ switch (Settings.data.bar.position) {
+ case "right":
+ return "left"
+ case "left":
+ return "right"
+ case "bottom":
+ return "top"
+ default:
+ return "bottom"
+ }
+ }
}
diff --git a/Services/BluetoothService.qml b/Services/BluetoothService.qml
index 43ac4dd8..c5e17d62 100644
--- a/Services/BluetoothService.qml
+++ b/Services/BluetoothService.qml
@@ -10,6 +10,7 @@ Singleton {
readonly property BluetoothAdapter adapter: Bluetooth.defaultAdapter
readonly property bool available: (adapter !== null)
+ readonly property bool enabled: adapter?.enabled ?? false
readonly property bool discovering: (adapter && adapter.discovering) ?? false
readonly property var devices: adapter ? adapter.devices : null
readonly property var pairedDevices: {
@@ -20,6 +21,7 @@ Singleton {
return dev && (dev.paired || dev.trusted)
})
}
+
readonly property var allDevicesWithBattery: {
if (!adapter || !adapter.devices) {
return []
@@ -29,20 +31,8 @@ Singleton {
})
}
- property bool lastAdapterState: false
-
function init() {
Logger.log("Bluetooth", "Service initialized")
- syncStateTimer.running = true
- }
-
- Timer {
- id: syncStateTimer
- interval: 1000
- repeat: false
- onTriggered: {
- lastAdapterState = Settings.data.network.bluetoothEnabled = adapter.enabled
- }
}
Timer {
@@ -52,27 +42,6 @@ Singleton {
onTriggered: adapter.discovering = true
}
- Timer {
- id: stateDebounceTimer
- interval: 200
- repeat: false
- onTriggered: {
- if (!adapter) {
- Logger.warn("Bluetooth", "State debouncer", "No adapter available")
- return
- }
- if (lastAdapterState === adapter.enabled) {
- return
- }
- lastAdapterState = adapter.enabled
- if (adapter.enabled) {
- ToastService.showNotice(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.enabled"))
- } else {
- ToastService.showNotice(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.disabled"))
- }
- }
- }
-
Connections {
target: adapter
function onEnabledChanged() {
@@ -82,11 +51,11 @@ Singleton {
}
Logger.log("Bluetooth", "onEnableChanged", adapter.enabled)
- Settings.data.network.bluetoothEnabled = adapter.enabled
- stateDebounceTimer.restart()
if (adapter.enabled) {
- // Using a timer to give a little time so the adapter is really enabled
+ ToastService.showNotice(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.enabled"))
discoveryTimer.running = true
+ } else {
+ ToastService.showNotice(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.disabled"))
}
}
}
@@ -149,11 +118,8 @@ Singleton {
/*
Paired
-
Means you’ve successfully exchanged keys with the device.
-
The devices remember each other and can authenticate without repeating the pairing process.
-
Example: once your headphones are paired, you don’t need to type a PIN every time.
Hence, instead of !device.paired, should be device.connected
*/
diff --git a/Services/IPCService.qml b/Services/IPCService.qml
index d2241c38..0095705c 100644
--- a/Services/IPCService.qml
+++ b/Services/IPCService.qml
@@ -172,5 +172,15 @@ Item {
}
WallpaperService.changeWallpaper(path, screen)
}
+
+ function toggleAutomation() {
+ Settings.data.wallpaper.randomEnabled = !Settings.data.wallpaper.randomEnabled
+ }
+ function disableAutomation() {
+ Settings.data.wallpaper.randomEnabled = false
+ }
+ function enableAutomation() {
+ Settings.data.wallpaper.randomEnabled = true
+ }
}
}
diff --git a/Services/MatugenService.qml b/Services/MatugenService.qml
index c2ebcd53..e3410d57 100644
--- a/Services/MatugenService.qml
+++ b/Services/MatugenService.qml
@@ -66,14 +66,14 @@ Singleton {
var extraUser = (Settings.configDir + "matugen.d").replace(/'/g, "'\\''")
// Build the main script
- var script = "cat > '" + pathEsc + "' << 'EOF'\n" + content + "EOF\n" + "for d in '" + extraRepo + "' '" + extraUser + "'; do\n" + " if [ -d \"$d\" ]; then\n" + " for f in \"$d\"/*.toml; do\n" + " [ -f \"$f\" ] && { echo; echo \"# extra: $f\"; cat \"$f\"; } >> '" + pathEsc + "'\n" + " done\n" + " fi\n" + "done\n" + "matugen image '"
- + wp + "' --config '" + pathEsc + "' --mode " + mode
+ var script = "cat > '" + pathEsc + "' << 'EOF'\n" + content + "EOF\n" + "for d in '" + extraRepo + "' '" + extraUser + "'; do\n" + " if [ -d \"$d\" ]; then\n" + " for f in \"$d\"/*.toml; do\n" + " [ -f \"$f\" ] && { echo; echo \"# extra: $f\"; cat \"$f\"; } >> '" + pathEsc + "'\n" + " done\n" + " fi\n"
+ + "done\n" + "matugen image '" + wp + "' --config '" + pathEsc + "' --mode " + mode + " --type " + Settings.data.colorSchemes.matugenSchemeType
// Add user config execution if enabled
if (Settings.data.matugen.enableUserTemplates) {
var userConfigDir = (Quickshell.env("HOME") + "/.config/matugen/").replace(/'/g, "'\\''")
script += "\n# Execute user config if it exists\nif [ -f '" + userConfigDir + "config.toml' ]; then\n"
- script += " matugen image '" + wp + "' --config '" + userConfigDir + "config.toml' --mode " + mode + "\n"
+ script += " matugen image '" + wp + "' --config '" + userConfigDir + "config.toml' --mode " + mode + " --type " + Settings.data.colorSchemes.matugenSchemeType + "\n"
script += "fi"
}
diff --git a/Services/PanelService.qml b/Services/PanelService.qml
index 5d33aeb7..59db74b4 100644
--- a/Services/PanelService.qml
+++ b/Services/PanelService.qml
@@ -10,6 +10,9 @@ Singleton {
// This is not a panel...
property var lockScreen: null
+ // A ref. to our global tooltip
+ property var tooltip: null
+
// Panels
property var registeredPanels: ({})
property var openedPanel: null
diff --git a/Services/ProgramCheckerService.qml b/Services/ProgramCheckerService.qml
index f8e4fa98..a7d5f436 100644
--- a/Services/ProgramCheckerService.qml
+++ b/Services/ProgramCheckerService.qml
@@ -18,6 +18,7 @@ Singleton {
property bool fuzzelAvailable: false
property bool vesktopAvailable: false
property bool gpuScreenRecorderAvailable: false
+ property bool wlsunsetAvailable: false
// Signal emitted when all checks are complete
signal checksCompleted
@@ -31,7 +32,8 @@ Singleton {
"footAvailable": ["which", "foot"],
"fuzzelAvailable": ["which", "fuzzel"],
"vesktopAvailable": ["which", "vesktop"],
- "gpuScreenRecorderAvailable": ["sh", "-c", "command -v gpu-screen-recorder >/dev/null 2>&1 || (command -v flatpak >/dev/null 2>&1 && flatpak list --app | grep -q 'com.dec05eba.gpu_screen_recorder')"]
+ "gpuScreenRecorderAvailable": ["sh", "-c", "command -v gpu-screen-recorder >/dev/null 2>&1 || (command -v flatpak >/dev/null 2>&1 && flatpak list --app | grep -q 'com.dec05eba.gpu_screen_recorder')"],
+ "wlsunsetAvailable": ["which", "wlsunset"]
})
// Internal tracking
diff --git a/Services/SystemStatService.qml b/Services/SystemStatService.qml
index 7a87e5c9..9692c1ee 100644
--- a/Services/SystemStatService.qml
+++ b/Services/SystemStatService.qml
@@ -325,14 +325,20 @@ Singleton {
// Helper function to format network speeds
function formatSpeed(bytesPerSecond) {
if (bytesPerSecond < 1024 * 1024) {
- return (bytesPerSecond / 1024).toFixed(1) + "KB/s"
+ const kb = bytesPerSecond / 1024
+ if (kb < 10) {
+ return kb.toFixed(1) + "KB"
+ } else {
+ return Math.round(kb) + "KB"
+ }
} else if (bytesPerSecond < 1024 * 1024 * 1024) {
- return (bytesPerSecond / (1024 * 1024)).toFixed(1) + "MB/s"
+ return (bytesPerSecond / (1024 * 1024)).toFixed(1) + "MB"
} else {
- return (bytesPerSecond / (1024 * 1024 * 1024)).toFixed(1) + "GB/s"
+ return (bytesPerSecond / (1024 * 1024 * 1024)).toFixed(1) + "GB"
}
}
+ // -------------------------------------------------------
// Compact speed formatter for vertical bar display
function formatCompactSpeed(bytesPerSecond) {
if (!bytesPerSecond || bytesPerSecond <= 0)
diff --git a/Services/UpdateService.qml b/Services/UpdateService.qml
index 6918614e..2b24e7b8 100644
--- a/Services/UpdateService.qml
+++ b/Services/UpdateService.qml
@@ -8,7 +8,7 @@ Singleton {
id: root
// Public properties
- property string baseVersion: "2.14.1"
+ property string baseVersion: "2.14.4"
property bool isDevelopment: true
property string currentVersion: `v${!isDevelopment ? baseVersion : baseVersion + "-dev"}`
diff --git a/Widgets/NButton.qml b/Widgets/NButton.qml
index e80b6b31..89e71c12 100644
--- a/Widgets/NButton.qml
+++ b/Widgets/NButton.qml
@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.Commons
+import qs.Services
Rectangle {
id: root
@@ -126,13 +127,6 @@ Rectangle {
}
}
- NTooltip {
- id: tooltip
- target: root
- positionAbove: Settings.data.bar.position === "bottom"
- text: root.tooltipText
- }
-
// Mouse interaction
MouseArea {
id: mouseArea
@@ -145,18 +139,18 @@ Rectangle {
onEntered: {
root.hovered = true
if (tooltipText) {
- tooltip.show()
+ PanelService.tooltip.show(root, root.tooltipText)
}
}
onExited: {
root.hovered = false
if (tooltipText) {
- tooltip.hide()
+ PanelService.tooltip.hide()
}
}
onPressed: mouse => {
if (tooltipText) {
- tooltip.hide()
+ PanelService.tooltip.hide()
}
if (mouse.button === Qt.LeftButton) {
root.clicked()
@@ -170,7 +164,7 @@ Rectangle {
onCanceled: {
root.hovered = false
if (tooltipText) {
- tooltip.hide()
+ PanelService.tooltip.hide()
}
}
}
diff --git a/Widgets/NFilePicker.qml b/Widgets/NFilePicker.qml
index 87b0efb1..d2e2f766 100644
--- a/Widgets/NFilePicker.qml
+++ b/Widgets/NFilePicker.qml
@@ -15,8 +15,7 @@ Popup {
// Properties
property string title: "File Picker"
property string initialPath: Quickshell.env("HOME") || "/home"
- property bool selectFiles: true
- property bool selectFolders: true
+ property string selectionMode: "files" // "files" or "folders"
property var nameFilters: ["*"]
property bool showDirs: true
property bool showHiddenFiles: false
@@ -117,8 +116,16 @@ Popup {
const fileIsDir = folderModel.get(i, "fileIsDir")
const fileSize = folderModel.get(i, "fileSize")
- if (root.selectFolders && !root.selectFiles && !fileIsDir)
+ // Skip hidden items if showHiddenFiles is false
+ // This additional check ensures hidden files are properly filtered
+ if (!root.showHiddenFiles && fileName.startsWith(".")) {
continue
+ }
+
+ // In folder mode, hide files
+ if (root.selectionMode === "folders" && !fileIsDir)
+ continue
+
if (searchText === "" || fileName.toLowerCase().includes(searchText)) {
filteredModel.append({
"fileName": fileName,
@@ -193,10 +200,28 @@ Popup {
color: Color.mPrimary
Layout.fillWidth: true
}
+
+ // "Select Current" button only visible in folder selection mode
+ NButton {
+ text: "Select Current"
+ icon: "filepicker-folder-current"
+ visible: root.selectionMode === "folders"
+ onClicked: {
+ filePickerPanel.currentSelection = [root.currentPath]
+ root.confirmSelection()
+ }
+ }
+
NIconButton {
icon: "filepicker-refresh"
tooltipText: "Refresh"
- onClicked: folderModel.refresh()
+ onClicked: {
+ // Force a proper refresh by resetting the folder
+ const currentFolder = folderModel.folder
+ folderModel.folder = ""
+ folderModel.folder = currentFolder
+ Qt.callLater(root.updateFilteredModel)
+ }
}
NIconButton {
icon: "filepicker-close"
@@ -301,7 +326,11 @@ Popup {
baseSize: Style.baseWidgetSize * 0.8
onClicked: {
root.showHiddenFiles = !root.showHiddenFiles
- root.updateFilteredModel()
+ // Force model refresh by resetting the folder
+ const currentFolder = folderModel.folder
+ folderModel.folder = ""
+ folderModel.folder = currentFolder
+ Qt.callLater(root.updateFilteredModel)
}
}
}
@@ -375,15 +404,20 @@ Popup {
FolderListModel {
id: folderModel
folder: "file://" + root.currentPath
- nameFilters: root.nameFilters
+ // Use wildcard filters including hidden files when showHiddenFiles is true
+ nameFilters: root.showHiddenFiles ? ["*", ".*"] : root.nameFilters
showDirs: root.showDirs
- showHidden: root.showHiddenFiles
+ showHidden: true // Always true, we'll filter in updateFilteredModel
+ showDotAndDotDot: false
sortField: FolderListModel.Name
sortReversed: false
+
onFolderChanged: {
root.currentPath = folder.toString().replace("file://", "")
filePickerPanel.currentSelection = []
+ Qt.callLater(root.updateFilteredModel)
}
+
onStatusChanged: {
if (status === FolderListModel.Error) {
if (root.currentPath !== Quickshell.env("HOME")) {
@@ -396,6 +430,14 @@ Popup {
}
}
+ // Update nameFilters when showHiddenFiles changes
+ Connections {
+ target: root
+ function onShowHiddenFilesChanged() {
+ folderModel.nameFilters = root.showHiddenFiles ? ["*", ".*"] : root.nameFilters
+ }
+ }
+
ListModel {
id: filteredModel
}
@@ -618,15 +660,16 @@ Popup {
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
if (model.fileIsDir) {
- if (root.selectFolders && !root.selectFiles) {
+ // In folder mode, single click selects the folder
+ if (root.selectionMode === "folders") {
filePickerPanel.currentSelection = [model.filePath]
- } else {
- folderModel.folder = "file://" + model.filePath
- root.currentPath = model.filePath
}
+ // In file mode, single click on folder does nothing (must double-click to enter)
} else {
- if (root.selectFiles)
- filePickerPanel.currentSelection = [model.filePath]
+ // Single click on file selects it (only in file mode)
+ if (root.selectionMode === "files") {
+ filePickerPanel.currentSelection = [model.filePath]
+ }
}
}
}
@@ -634,15 +677,12 @@ Popup {
onDoubleClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
if (model.fileIsDir) {
- if (root.selectFolders && !root.selectFiles) {
- filePickerPanel.currentSelection = [model.filePath]
- root.confirmSelection()
- } else {
- folderModel.folder = "file://" + model.filePath
- root.currentPath = model.filePath
- }
+ // Double-click on folder always navigates into it
+ folderModel.folder = "file://" + model.filePath
+ root.currentPath = model.filePath
} else {
- if (root.selectFiles) {
+ // Double-click on file selects and confirms (only in file mode)
+ if (root.selectionMode === "files") {
filePickerPanel.currentSelection = [model.filePath]
root.confirmSelection()
}
@@ -719,15 +759,16 @@ Popup {
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
if (model.fileIsDir) {
- if (root.selectFolders && !root.selectFiles) {
+ // In folder mode, single click selects the folder
+ if (root.selectionMode === "folders") {
filePickerPanel.currentSelection = [model.filePath]
- } else {
- folderModel.folder = "file://" + model.filePath
- root.currentPath = model.filePath
}
+ // In file mode, single click on folder does nothing (must double-click to enter)
} else {
- if (root.selectFiles)
- filePickerPanel.currentSelection = [model.filePath]
+ // Single click on file selects it (only in file mode)
+ if (root.selectionMode === "files") {
+ filePickerPanel.currentSelection = [model.filePath]
+ }
}
}
}
@@ -735,15 +776,12 @@ Popup {
onDoubleClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
if (model.fileIsDir) {
- if (root.selectFolders && !root.selectFiles) {
- filePickerPanel.currentSelection = [model.filePath]
- root.confirmSelection()
- } else {
- folderModel.folder = "file://" + model.filePath
- root.currentPath = model.filePath
- }
+ // Double-click on folder always navigates into it
+ folderModel.folder = "file://" + model.filePath
+ root.currentPath = model.filePath
} else {
- if (root.selectFiles) {
+ // Double-click on file selects and confirms (only in file mode)
+ if (root.selectionMode === "files") {
filePickerPanel.currentSelection = [model.filePath]
root.confirmSelection()
}
@@ -765,7 +803,8 @@ Popup {
if (filePickerPanel.searchText.length > 0) {
return "Searching for: \"" + filePickerPanel.searchText + "\" (" + filteredModel.count + " matches)"
} else if (filePickerPanel.currentSelection.length > 0) {
- return filePickerPanel.currentSelection.length + " item(s) selected"
+ const selectedName = filePickerPanel.currentSelection[0].split('/').pop()
+ return "Selected: " + selectedName
} else {
return filteredModel.count + " items"
}
@@ -785,14 +824,7 @@ Popup {
}
NButton {
- text: {
- if (root.selectFolders && !root.selectFiles)
- return "Select Folder"
- else if (root.selectFiles && !root.selectFolders)
- return "Select File"
- else
- return "Select"
- }
+ text: root.selectionMode === "folders" ? "Select Folder" : "Select File"
icon: "filepicker-check"
enabled: filePickerPanel.currentSelection.length > 0
onClicked: root.confirmSelection()
diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml
index 59891903..5c82dfb3 100644
--- a/Widgets/NIconButton.qml
+++ b/Widgets/NIconButton.qml
@@ -11,6 +11,7 @@ Rectangle {
property string icon
property string tooltipText
+ property string tooltipDirection: "auto"
property bool enabled: true
property bool allowClickWhenDisabled: false
property bool hovering: false
@@ -62,13 +63,6 @@ Rectangle {
}
}
- NTooltip {
- id: tooltip
- target: root
- positionAbove: Settings.data.bar.position === "bottom"
- text: root.tooltipText
- }
-
MouseArea {
// Always enabled to allow hover/tooltip even when the button is disabled
enabled: true
@@ -79,20 +73,20 @@ Rectangle {
onEntered: {
hovering = root.enabled ? true : false
if (tooltipText) {
- tooltip.show()
+ PanelService.tooltip.show(parent, tooltipText, tooltipDirection)
}
root.entered()
}
onExited: {
hovering = false
if (tooltipText) {
- tooltip.hide()
+ PanelService.tooltip.hide()
}
root.exited()
}
onClicked: function (mouse) {
if (tooltipText) {
- tooltip.hide()
+ PanelService.tooltip.hide()
}
if (!root.enabled && !allowClickWhenDisabled) {
return
diff --git a/Widgets/NRadioButton.qml b/Widgets/NRadioButton.qml
index 9c44f133..7f7e296f 100644
--- a/Widgets/NRadioButton.qml
+++ b/Widgets/NRadioButton.qml
@@ -19,9 +19,8 @@ RadioButton {
anchors.verticalCenter: parent.verticalCenter
Rectangle {
- anchors.centerIn: parent
- implicitWidth: Style.marginS * scaling
- implicitHeight: Style.marginS * scaling
+ anchors.fill: parent
+ anchors.margins: parent.width * 0.3
radius: width * 0.5
color: Qt.alpha(Color.mPrimary, root.checked ? 1 : 0)
diff --git a/Widgets/NScrollView.qml b/Widgets/NScrollView.qml
index 1edca1c1..63e28819 100644
--- a/Widgets/NScrollView.qml
+++ b/Widgets/NScrollView.qml
@@ -14,10 +14,44 @@ T.ScrollView {
property real handleRadius: Style.radiusM * scaling
property int verticalPolicy: ScrollBar.AsNeeded
property int horizontalPolicy: ScrollBar.AsNeeded
+ property bool preventHorizontalScroll: horizontalPolicy === ScrollBar.AlwaysOff
+ property int boundsBehavior: Flickable.StopAtBounds
+ property int flickableDirection: Flickable.VerticalFlick
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, contentHeight + topPadding + bottomPadding)
+ // Configure the internal flickable when it becomes available
+ Component.onCompleted: {
+ configureFlickable()
+ }
+
+ // Function to configure the underlying Flickable
+ function configureFlickable() {
+ // Find the internal Flickable (it's usually the first child)
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i]
+ if (child.toString().indexOf("Flickable") !== -1) {
+ // Configure the flickable to prevent horizontal scrolling
+ child.boundsBehavior = root.boundsBehavior
+
+ if (root.preventHorizontalScroll) {
+ child.flickableDirection = Flickable.VerticalFlick
+ child.contentWidth = Qt.binding(() => child.width)
+ } else {
+ child.flickableDirection = root.flickableDirection
+ }
+ break
+ }
+ }
+ }
+
+ // Watch for changes in horizontalPolicy
+ onHorizontalPolicyChanged: {
+ preventHorizontalScroll = (horizontalPolicy === ScrollBar.AlwaysOff)
+ configureFlickable()
+ }
+
ScrollBar.vertical: ScrollBar {
parent: root
x: root.mirrored ? 0 : root.width - width
diff --git a/Widgets/NSearchableComboBox.qml b/Widgets/NSearchableComboBox.qml
index ed2fe374..e949405d 100644
--- a/Widgets/NSearchableComboBox.qml
+++ b/Widgets/NSearchableComboBox.qml
@@ -255,11 +255,11 @@ RowLayout {
// Ensure the model is filtered when popup opens
filterModel()
// Small delay to ensure the popup is fully rendered
- Qt.callLater(function () {
- if (searchInput && searchInput.inputItem) {
- searchInput.inputItem.forceActiveFocus()
- }
- })
+ Qt.callLater(() => {
+ if (searchInput && searchInput.inputItem) {
+ searchInput.inputItem.forceActiveFocus()
+ }
+ })
}
}
}
diff --git a/Widgets/NSlider.qml b/Widgets/NSlider.qml
index 51b2f62f..eb6d007c 100644
--- a/Widgets/NSlider.qml
+++ b/Widgets/NSlider.qml
@@ -11,9 +11,11 @@ Slider {
property bool snapAlways: true
property real heightRatio: 0.7
- readonly property real knobDiameter: Math.round(Style.baseWidgetSize * heightRatio * scaling)
- readonly property real trackHeight: knobDiameter * 0.4
- readonly property real cutoutExtra: Math.round(Style.baseWidgetSize * 0.1 * scaling)
+ readonly property real knobDiameter: Math.round((Style.baseWidgetSize * heightRatio * scaling) / 2) * 2
+ readonly property real trackHeight: Math.round((knobDiameter * 0.4) / 2) * 2
+ readonly property real cutoutExtra: Math.round((Style.baseWidgetSize * 0.1 * scaling) / 2) * 2
+
+ padding: cutoutExtra / 2
snapMode: snapAlways ? Slider.SnapAlways : Slider.SnapOnRelease
implicitHeight: Math.max(trackHeight, knobDiameter)
@@ -25,52 +27,67 @@ Slider {
implicitHeight: trackHeight
width: root.availableWidth
height: implicitHeight
- radius: 0
+ radius: height / 2
color: Qt.alpha(Color.mSurface, 0.5)
border.color: Qt.alpha(Color.mOutline, 0.5)
border.width: Math.max(1, Style.borderS * scaling)
- // Animated gradient active track
- Rectangle {
- id: activeTrack
+ // A container composite shape that puts a semicircle on the end
+ Item {
+ id: activeTrackContainer
width: root.visualPosition * parent.width
height: parent.height
- radius: parent.radius
+ clip: true
- // Animated gradient fill
- gradient: Gradient {
- orientation: Gradient.Horizontal
- GradientStop {
- position: 0.0
- color: Qt.darker(Color.mPrimary, 1.2)
- Behavior on color {
- ColorAnimation {
- duration: 300
+ // The rounded end cap made from a rounded rectangle
+ Rectangle {
+ width: parent.height
+ height: parent.height
+ radius: width / 2
+ color: Qt.darker(Color.mPrimary, 1.2) //starting color of gradient
+ }
+
+ // The main rectangle
+ Rectangle {
+ x: parent.height / 2
+ width: parent.width - x // Fills the rest of the container
+ height: parent.height
+ radius: 0
+ // Animated gradient fill
+ gradient: Gradient {
+ orientation: Gradient.Horizontal
+ GradientStop {
+ position: 0.0
+ color: Qt.darker(Color.mPrimary, 1.2)
+ Behavior on color {
+ ColorAnimation {
+ duration: 300
+ }
}
}
- }
- GradientStop {
- position: 0.5
- color: Color.mPrimary
- SequentialAnimation on position {
- loops: Animation.Infinite
- NumberAnimation {
- from: 0.3
- to: 0.7
- duration: 2000
- easing.type: Easing.InOutSine
- }
- NumberAnimation {
- from: 0.7
- to: 0.3
- duration: 2000
- easing.type: Easing.InOutSine
+ GradientStop {
+ position: 0.5
+ color: Color.mPrimary
+ SequentialAnimation on position {
+ loops: Animation.Infinite
+ NumberAnimation {
+ from: 0.3
+ to: 0.7
+ duration: 2000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ from: 0.7
+ to: 0.3
+ duration: 2000
+ easing.type: Easing.InOutSine
+ }
}
}
- }
- GradientStop {
- position: 1.0
- color: Qt.lighter(Color.mPrimary, 1.2)
+ GradientStop {
+ position: 1.0
+ color: Qt.lighter(Color.mPrimary, 1.2)
+ }
}
}
}
@@ -78,26 +95,26 @@ Slider {
// Circular cutout
Rectangle {
id: knobCutout
- width: knobDiameter + cutoutExtra
- height: knobDiameter + cutoutExtra
+ implicitWidth: knobDiameter + cutoutExtra
+ implicitHeight: knobDiameter + cutoutExtra
radius: width / 2
color: root.cutoutColor !== undefined ? root.cutoutColor : Color.mSurface
- x: root.leftPadding + root.visualPosition * (root.availableWidth - root.knobDiameter) - cutoutExtra / 2
+ x: root.leftPadding + root.visualPosition * (root.availableWidth - root.knobDiameter) - cutoutExtra
anchors.verticalCenter: parent.verticalCenter
}
}
handle: Item {
- width: knob.implicitWidth
- height: knob.implicitHeight
- x: root.leftPadding + Math.round(root.visualPosition * (root.availableWidth - width))
- y: root.topPadding + root.availableHeight / 2 - height / 2
+ implicitWidth: knobDiameter
+ implicitHeight: knobDiameter
+ x: root.leftPadding + root.visualPosition * (root.availableWidth - width)
+ anchors.verticalCenter: parent.verticalCenter
Rectangle {
id: knob
implicitWidth: knobDiameter
implicitHeight: knobDiameter
- radius: width * 0.5
+ radius: width / 2
color: root.pressed ? Color.mTertiary : Color.mSurface
border.color: Color.mPrimary
border.width: Math.max(1, Style.borderL * scaling)
diff --git a/Widgets/NToggle.qml b/Widgets/NToggle.qml
index 1381213b..3e464bb8 100644
--- a/Widgets/NToggle.qml
+++ b/Widgets/NToggle.qml
@@ -27,8 +27,8 @@ RowLayout {
Rectangle {
id: switcher
- implicitWidth: Math.round(root.baseSize * 1.625 * scaling)
- implicitHeight: Math.round(root.baseSize * scaling)
+ implicitWidth: Math.round(root.baseSize * .85 * scaling) * 2
+ implicitHeight: Math.round(root.baseSize * scaling * .5) * 2
radius: height * 0.5
color: root.checked ? Color.mPrimary : Color.mSurface
border.color: Color.mOutline
@@ -47,8 +47,9 @@ RowLayout {
}
Rectangle {
- implicitWidth: Math.round((root.baseSize * 0.8) * scaling)
- implicitHeight: Math.round((root.baseSize * 0.8) * scaling)
+
+ implicitWidth: Math.round(root.baseSize * 0.4 * scaling) * 2
+ implicitHeight: Math.round(root.baseSize * 0.4 * scaling) * 2
radius: height * 0.5
color: root.checked ? Color.mOnPrimary : Color.mPrimary
border.color: root.checked ? Color.mSurface : Color.mSurface
diff --git a/Widgets/NTooltip.qml b/Widgets/NTooltip.qml
deleted file mode 100644
index 67cf6169..00000000
--- a/Widgets/NTooltip.qml
+++ /dev/null
@@ -1,214 +0,0 @@
-import QtQuick
-import qs.Commons
-import qs.Services
-
-Window {
- id: root
-
- property bool isVisible: false
- property string text: I18n.tr("widgets.tooltip.placeholder")
- property Item target: null
- property int delay: Style.tooltipDelay
- property bool positionAbove: false
- property bool positionLeft: false
- property bool positionRight: false
-
- readonly property string barPosition: Settings.data.bar.position
-
- flags: Qt.ToolTip | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
- color: Color.transparent
- visible: false
-
- onIsVisibleChanged: {
- if (isVisible) {
- if (delay > 0) {
- timerShow.running = true
- } else {
- _showNow()
- }
- } else {
- _hideNow()
- }
- }
-
- function show() {
- isVisible = true
- }
- function hide() {
- isVisible = false
- timerShow.running = false
- }
-
- function _showNow() {
- // Compute new size everytime we show the tooltip
- width = Math.max(50 * scaling, tooltipText.implicitWidth + Style.marginL * 2 * scaling)
- height = Math.max(40 * scaling, tooltipText.implicitHeight + Style.marginM * 2 * scaling)
-
- if (!target) {
- return
- }
-
- // Auto-detect positioning based on bar position if not explicitly set
- var shouldPositionLeft = positionLeft
- var shouldPositionRight = positionRight
- var shouldPositionAbove = positionAbove
-
- // If no explicit positioning is set, auto-detect based on bar position
- if (!positionLeft && !positionRight && !positionAbove) {
- if (barPosition === "left") {
- shouldPositionRight = true
- } else if (barPosition === "right") {
- shouldPositionLeft = true
- } else if (barPosition === "bottom") {
- shouldPositionAbove = true
- }
- // For "top" bar, default to below (no change needed)
- }
-
- if (shouldPositionLeft) {
- // Position tooltip to the left of the target
- var pos = target.mapToGlobal(0, 0)
- x = pos.x - width - 12 // 12 px margin to the left
- y = pos.y - height / 2 + target.height / 2
- } else if (shouldPositionRight) {
- // Position tooltip to the right of the target
- var pos = target.mapToGlobal(target.width, 0)
- x = pos.x + 12 // 12 px margin to the right
- y = pos.y - height / 2 + target.height / 2
- } else if (shouldPositionAbove) {
- // Position tooltip above the target
- var pos = target.mapToGlobal(0, 0)
- x = pos.x - width / 2 + target.width / 2
- y = pos.y - height - 12 // 12 px margin above
- } else {
- // Position tooltip below the target
- var pos = target.mapToGlobal(0, target.height)
- x = pos.x - width / 2 + target.width / 2
- y = pos.y + 12 // 12 px margin below
- }
-
- // Start with animation values
- tooltipRect.scaleValue = 0.8
- tooltipRect.opacityValue = 0.0
- visible = true
-
- // Use a timer to trigger the animation after the component is visible
- showTimer.start()
- }
-
- function _hideNow() {
- // Start hide animation
- tooltipRect.scaleValue = 0.8
- tooltipRect.opacityValue = 0.0
-
- // Hide after animation completes
- hideTimer.start()
- }
-
- Connections {
- target: root.target
- function onXChanged() {
- if (root.visible) {
- root._showNow()
- }
- }
- function onYChanged() {
- if (root.visible) {
- root._showNow()
- }
- }
- function onWidthChanged() {
- if (root.visible) {
- root._showNow()
- }
- }
- function onHeightChanged() {
- if (root.visible) {
- root._showNow()
- }
- }
- }
- Connections {
- target: root
- function onTextChanged() {
- if (root.visible) {
- root._showNow()
- }
- }
- }
-
- Timer {
- id: timerShow
- interval: delay
- running: false
- repeat: false
- onTriggered: {
- _showNow()
- running = false
- }
- }
-
- // Timer to hide tooltip after animation
- Timer {
- id: hideTimer
- interval: Style.animationNormal
- repeat: false
- onTriggered: {
- visible = false
- }
- }
-
- // Timer to trigger show animation
- Timer {
- id: showTimer
- interval: Style.animationFast / 15 // Very short delay to ensure component is visible
- repeat: false
- onTriggered: {
- // Animate to final values
- tooltipRect.scaleValue = 1.0
- tooltipRect.opacityValue = 1.0
- }
- }
-
- Rectangle {
- id: tooltipRect
- anchors.fill: parent
- radius: Style.radiusM * scaling
- color: Color.mSurface
- border.color: Color.mOutline
- border.width: Math.max(1, Style.borderS * scaling)
- z: 1
-
- // Animation properties
- property real scaleValue: 1.0
- property real opacityValue: 1.0
-
- scale: scaleValue
- opacity: opacityValue
-
- // Animation behaviors
- Behavior on scale {
- NumberAnimation {
- duration: Style.animationNormal
- easing.type: Easing.OutExpo
- }
- }
-
- Behavior on opacity {
- NumberAnimation {
- duration: Style.animationNormal
- easing.type: Easing.OutQuad
- }
- }
-
- NText {
- id: tooltipText
- anchors.centerIn: parent
- text: root.text
- font.pointSize: Style.fontSizeM * scaling
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- wrapMode: Text.Wrap
- }
- }
-}
diff --git a/flake.nix b/flake.nix
index 490e35cc..9b869208 100644
--- a/flake.nix
+++ b/flake.nix
@@ -110,6 +110,16 @@
}:
let
cfg = config.programs.noctalia-shell;
+ defaultSettings = builtins.fromJSON (builtins.readFile ./Assets/settings-default.json);
+
+ # Deep merge user settings with defaults
+ mergedSettings =
+ if cfg.settings == null then
+ defaultSettings
+ else if builtins.isAttrs cfg.settings then
+ lib.recursiveUpdate defaultSettings cfg.settings
+ else
+ cfg.settings; # Pass through strings/paths as-is
in
{
options.programs.noctalia-shell = {
@@ -144,6 +154,8 @@
description = ''
Noctalia shell configuration settings as an attribute set, string
or filepath, to be written to ~/.config/noctalia/settings.json.
+ When provided as an attribute set, it will be deep-merged with
+ the default settings.
'';
};
@@ -189,18 +201,16 @@
in
lib.mkIf cfg.enable {
xdg.configFile = {
- "noctalia/settings.json" = lib.mkIf (cfg.settings != null) (
- {
- onChange = restart;
- }
- // (
- if builtins.isAttrs cfg.settings then
- { text = builtins.toJSON cfg.settings; }
- else if builtins.isString cfg.settings then
- { text = cfg.settings; }
- else
- { source = cfg.settings; }
- )
+ "noctalia/settings.json" = {
+ onChange = restart;
+ }
+ // (
+ if builtins.isAttrs mergedSettings then
+ { text = builtins.toJSON mergedSettings + "\n"; }
+ else if builtins.isString mergedSettings then
+ { text = mergedSettings; }
+ else
+ { source = mergedSettings; }
);
"noctalia/colors.json" = lib.mkIf (cfg.colors != null) (
{
diff --git a/shell.qml b/shell.qml
index cd1689bc..e333472c 100644
--- a/shell.qml
+++ b/shell.qml
@@ -39,6 +39,7 @@ import qs.Modules.Notification
import qs.Modules.OSD
import qs.Modules.Settings
import qs.Modules.Toast
+import qs.Modules.Tooltip
import qs.Modules.Wallpaper
ShellRoot {
@@ -50,6 +51,10 @@ ShellRoot {
Bar {}
Dock {}
+ Tooltip {
+ id: globalTooltip
+ }
+
Notification {
id: notification
}
@@ -115,6 +120,7 @@ ShellRoot {
Component.onCompleted: {
// Save a ref. to our lockScreen so we can access it easily
PanelService.lockScreen = lockScreen
+ PanelService.tooltip = globalTooltip
BarWidgetRegistry.init()
}