mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2025-12-06 06:36:15 +00:00
Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53d885a8ae | ||
|
|
82c6578a9f | ||
|
|
691dcc9c97 | ||
|
|
c036ff0d7a | ||
|
|
87144df024 | ||
|
|
aad8cd46b5 | ||
|
|
c3cf3dcf32 | ||
|
|
c16ee69de6 | ||
|
|
8e6e110447 | ||
|
|
17bd4e79f8 | ||
|
|
698be35791 | ||
|
|
c0d50b87c0 | ||
|
|
2b6bcdc570 | ||
|
|
13f82d10e2 | ||
|
|
56203e1a07 | ||
|
|
7316695aac | ||
|
|
640ed729e5 | ||
|
|
08191678df | ||
|
|
9680dd83fd | ||
|
|
3b166bd270 | ||
|
|
cf12b98351 | ||
|
|
066d6f2e2f | ||
|
|
81edc14e63 | ||
|
|
5303a88003 | ||
|
|
3a534f8f72 | ||
|
|
1bacf397ed | ||
|
|
18501a5b9e | ||
|
|
d6cc4660dd | ||
|
|
1152453d84 | ||
|
|
436ff56c93 | ||
|
|
b7dc1aed84 | ||
|
|
336deba554 | ||
|
|
0af85721b3 | ||
|
|
b047837543 | ||
|
|
aa30e90ec7 | ||
|
|
3b63384a51 | ||
|
|
cf36389fa6 | ||
|
|
abf346e485 | ||
|
|
d4be3a2cc2 | ||
|
|
84e058fb07 | ||
|
|
833a9c1a8f | ||
|
|
0cdc5bd518 | ||
|
|
f955e2c87d | ||
|
|
64dcb0d34e | ||
|
|
75acc2fd82 | ||
|
|
a6d7d077f1 | ||
|
|
6a74924e04 | ||
|
|
c955db20b7 | ||
|
|
928b64e64a | ||
|
|
5f79dac0f2 | ||
|
|
129609ec2c | ||
|
|
f42bcef239 | ||
|
|
9f62eacf27 | ||
|
|
c5cb1e6500 | ||
|
|
9a02f58d29 | ||
|
|
29ad654a58 | ||
|
|
e1d39f3bbc | ||
|
|
bc9fe06fd8 | ||
|
|
77e004566c | ||
|
|
4377637790 | ||
|
|
691b2e3a7d | ||
|
|
e60e2b5eb1 | ||
|
|
8db8913bd3 | ||
|
|
db8803d137 | ||
|
|
cd5b48f26d | ||
|
|
ca72a5ca8f | ||
|
|
114cbc9f9f | ||
|
|
6e156c3ae5 | ||
|
|
4cc4c364d4 | ||
|
|
344b5f9a8c | ||
|
|
1a1ef85fa5 | ||
|
|
49e2bc6905 | ||
|
|
fba4bf6b74 | ||
|
|
b7ff9e73e4 | ||
|
|
732f58b967 | ||
|
|
916c2d67ea | ||
|
|
6ec3a61157 | ||
|
|
2c0062390d | ||
|
|
66db74eb71 | ||
|
|
8a78d8cb34 | ||
|
|
c0e5d7d419 | ||
|
|
3dd02b8367 | ||
|
|
3c04fddcf1 | ||
|
|
890c86ac68 | ||
|
|
d4a73e05ee | ||
|
|
b57e77df9b | ||
|
|
ddb0b90ef7 | ||
|
|
f39ea9e704 | ||
|
|
9c66d64d85 | ||
|
|
475f4a6bda | ||
|
|
376dedeb6f | ||
|
|
b3cddc1ede | ||
|
|
f75a056550 | ||
|
|
0cf9de0fc4 | ||
|
|
04d89905cf | ||
|
|
6fbbf38ffa | ||
|
|
3db3226b6f | ||
|
|
94d3ea9c94 | ||
|
|
d171e81be1 | ||
|
|
05ea9af4db | ||
|
|
10adaf955b | ||
|
|
7fbfcfd9ef |
2001
Assets/MatugenTemplates/code.json
Normal file
2001
Assets/MatugenTemplates/code.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -257,6 +257,10 @@
|
||||
},
|
||||
"dock": {
|
||||
"title": "Dock",
|
||||
"enabled": {
|
||||
"label": "Dock aktivieren",
|
||||
"description": "Dock vollständig anzeigen oder ausblenden"
|
||||
},
|
||||
"appearance": {
|
||||
"section": {
|
||||
"label": "Erscheinungsbild",
|
||||
@@ -289,7 +293,7 @@
|
||||
"monitors": {
|
||||
"section": {
|
||||
"label": "Monitor-Anzeige",
|
||||
"description": "Monitor auswählen, auf dem das Dock angezeigt werden soll."
|
||||
"description": "Dock auf bestimmten Monitoren anzeigen. Standardmäßig werden alle angezeigt, wenn keine ausgewählt wurden."
|
||||
},
|
||||
"only-same-output": {
|
||||
"description": "Zeige nur Apps von dem Bildschirm, auf dem sich das Dock befindet.",
|
||||
@@ -604,6 +608,10 @@
|
||||
"pywalfox": {
|
||||
"description": "Schreibt {filepath} und führt pywalfox update aus",
|
||||
"description-missing": "Erfordert die Installation von {app}"
|
||||
},
|
||||
"code": {
|
||||
"description": "Schreibe {Dateipfad}. Das Hyprluna-Theme muss manuell installiert und aktiviert werden.",
|
||||
"description-missing": "Benötigt die Installation von {app}"
|
||||
}
|
||||
},
|
||||
"misc": {
|
||||
@@ -645,6 +653,10 @@
|
||||
"fahrenheit": {
|
||||
"label": "Temperatur in Fahrenheit (°F) anzeigen",
|
||||
"description": "Temperatur in Fahrenheit statt Celsius anzeigen."
|
||||
},
|
||||
"show-in-calendar": {
|
||||
"description": "Zeige die tägliche Wettervorhersage direkt in deiner Kalenderansicht an.",
|
||||
"label": "Wetter im Kalender anzeigen"
|
||||
}
|
||||
},
|
||||
"date-time": {
|
||||
@@ -653,8 +665,8 @@
|
||||
"description": "Anpassen, wie Datum und Zeit erscheinen."
|
||||
},
|
||||
"12hour-format": {
|
||||
"description": "An für AM/PM-Format (z.B. 8:00 PM), aus für 24-Stunden-Format (z.B. 20:00).",
|
||||
"label": "12-Stunden-Zeitformat benutzen"
|
||||
"label": "12-Stunden-Zeitformat benutzen",
|
||||
"description": "Zeigt die Uhrzeit im 12-Stunden-Format auf dem Sperrbildschirm und im Kalender an. Die Uhr in der Statusleiste hat eigene Einstellungen."
|
||||
},
|
||||
"week-numbers": {
|
||||
"label": "Wochennummern anzeigen",
|
||||
@@ -667,6 +679,11 @@
|
||||
"use-analog": {
|
||||
"description": "Eine Analoguhr auf dem Kalenderbildschirm anzeigen.",
|
||||
"label": "Analoge Uhr verwenden"
|
||||
},
|
||||
"first-day-of-week": {
|
||||
"automatic": "Automatisch (Systemgebietsschema verwenden)",
|
||||
"description": "Wähle, welcher Tag die Woche im Kalender beginnen soll.",
|
||||
"label": "Erster Tag der Woche"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -838,10 +855,6 @@
|
||||
"label": "Eckenradius",
|
||||
"reset": "Rahmenradius zurücksetzen"
|
||||
},
|
||||
"dim-desktop": {
|
||||
"description": "Den Desktop abdunkeln, wenn Bedienfelder oder Menüs geöffnet sind.",
|
||||
"label": "Desktop abdunkeln"
|
||||
},
|
||||
"scaling": {
|
||||
"description": "Ändert die Größe der allgemeinen Benutzeroberfläche, mit Ausnahme der Leiste.",
|
||||
"label": "Oberflächenskalierung",
|
||||
@@ -855,6 +868,10 @@
|
||||
"tooltips": {
|
||||
"description": "Tooltips in der gesamten Benutzeroberfläche aktivieren oder deaktivieren.",
|
||||
"label": "Tooltips anzeigen"
|
||||
},
|
||||
"panels-attached-to-bar": {
|
||||
"description": "Wenn aktiviert, werden die Panels mit einem schönen, umgekehrten Eckdesign an der Leiste befestigt.",
|
||||
"label": "Paneele an Stange befestigen"
|
||||
}
|
||||
},
|
||||
"lock-screen": {
|
||||
@@ -1251,6 +1268,36 @@
|
||||
"width": {
|
||||
"label": "Breite",
|
||||
"description": "Benutzerdefinierte Komponentenbreite."
|
||||
},
|
||||
"hide-when-idle": {
|
||||
"label": "Ausblenden, wenn keine Medien wiedergegeben werden",
|
||||
"description": "Wenn aktiviert, wird der Visualizer ausgeblendet, sofern keine Wiedergabe läuft."
|
||||
}
|
||||
},
|
||||
"lock-keys": {
|
||||
"show-caps-lock": {
|
||||
"description": "Caps Lock Status anzeigen.",
|
||||
"label": "Feststelltaste"
|
||||
},
|
||||
"show-num-lock": {
|
||||
"description": "Num-Lock-Status anzeigen.",
|
||||
"label": "Num-Taste"
|
||||
},
|
||||
"show-scroll-lock": {
|
||||
"description": "Scroll-Lock-Status anzeigen.",
|
||||
"label": "Rollenfeststelltaste"
|
||||
},
|
||||
"indicator-style": {
|
||||
"circle": "Kreisbuchstaben",
|
||||
"circle-dash": "Gestrichelte Kreisbuchstaben",
|
||||
"circle-dot": "Punktierte Kreisbuchstaben",
|
||||
"description": "Symbolstil für die Feststelltastenanzeigen",
|
||||
"hex": "Sechseck-Buchstaben",
|
||||
"label": "Indikatorstil",
|
||||
"large": "Große Buchstaben",
|
||||
"small": "Kleinbuchstaben",
|
||||
"square": "Quadratische Buchstaben",
|
||||
"square-round": "Abgerundete quadratische Buchstaben"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1372,8 +1419,6 @@
|
||||
"click-to-start-recording": "Klicken zum Starten einer Bildschirmaufnahme",
|
||||
"click-to-stop-recording": "Klicken zum Stoppen einer Bildschirmaufnahme",
|
||||
"open-control-center": "Kontrollzentrum öffnen",
|
||||
"volume-at": "Lautstärke bei {volume}%\nLinksklick zum Stumm-/Lautschalten. Rechtsklick für Einstellungen.\nScrollen zum Ändern der Lautstärke.",
|
||||
"microphone-volume-at": "Mikrofon-Lautstärke bei {volume}%\nLinksklick zum Stumm-/Lautschalten. Rechtsklick für Einstellungen.\nScrollen zum Ändern der Lautstärke.",
|
||||
"brightness-at": "Helligkeit: {brightness}%\nRechtsklick für Einstellungen.\nScrollen zum Ändern der Helligkeit.",
|
||||
"manage-wifi": "WLAN verwalten",
|
||||
"bluetooth-devices": "Bluetooth-Geräte",
|
||||
@@ -1387,7 +1432,9 @@
|
||||
"power-profile": "'{profile}' Energieprofil",
|
||||
"keyboard-layout": "{layout} Tastaturlayout",
|
||||
"output-muted": "Audio-Ausgabe stummschalten",
|
||||
"input-muted": "Audio-Eingabe stummschalten"
|
||||
"input-muted": "Audio-Eingabe stummschalten",
|
||||
"microphone-volume-at": "Mikrofonlautstärke bei {volume}%.\nLinksklick für Einstellungen. Rechtsklick zum Stummschalten.\nScrollen zum Ändern der Lautstärke.",
|
||||
"volume-at": "Lautstärke bei {volume}%.\nLinksklick für Einstellungen. Rechtsklick zum Stummschalten.\nScrollen zum Ändern der Lautstärke."
|
||||
},
|
||||
"clock": {
|
||||
"tooltip": "Kalender öffnen"
|
||||
|
||||
@@ -257,6 +257,10 @@
|
||||
},
|
||||
"dock": {
|
||||
"title": "Dock",
|
||||
"enabled": {
|
||||
"label": "Enable dock",
|
||||
"description": "Show or hide the dock entirely"
|
||||
},
|
||||
"appearance": {
|
||||
"section": {
|
||||
"label": "Appearance",
|
||||
@@ -289,7 +293,7 @@
|
||||
"monitors": {
|
||||
"section": {
|
||||
"label": "Monitor display",
|
||||
"description": "Choose which monitor to display the dock on."
|
||||
"description": "Show dock on specific monitors. Defaults to all if none are chosen."
|
||||
},
|
||||
"only-same-output": {
|
||||
"label": "Only apps from same output",
|
||||
@@ -602,12 +606,16 @@
|
||||
"description-missing": "Requires {app} to be installed"
|
||||
},
|
||||
"discord": {
|
||||
"description": "Write {filepath} for {client}",
|
||||
"description": "Write {filepath} for {client}. Hyprluna theme needs to be activated manually.",
|
||||
"description-missing": "No Discord client detected. Install vencord, vesktop, webcord, armcord, equibop, lightcord, or dorion."
|
||||
},
|
||||
"pywalfox": {
|
||||
"description": "Write {filepath} and run pywalfox update",
|
||||
"description-missing": "Requires {app} to be installed"
|
||||
},
|
||||
"code": {
|
||||
"description": "Write {filepath}. Hyprluna theme needs to be installed and activated manually.",
|
||||
"description-missing": "Requires {app} to be installed"
|
||||
}
|
||||
},
|
||||
"misc": {
|
||||
@@ -645,6 +653,10 @@
|
||||
"fahrenheit": {
|
||||
"label": "Display temperature in Fahrenheit (°F)",
|
||||
"description": "Display temperature in Fahrenheit instead of Celsius."
|
||||
},
|
||||
"show-in-calendar": {
|
||||
"label": "Display weather in calendar",
|
||||
"description": "Show the daily weather forecast directly in your calendar view."
|
||||
}
|
||||
},
|
||||
"date-time": {
|
||||
@@ -654,12 +666,17 @@
|
||||
},
|
||||
"12hour-format": {
|
||||
"label": "Use 12-hour time format",
|
||||
"description": "On for AM/PM format (e.g., 8:00 PM), off for 24-hour format (e.g., 20:00)."
|
||||
"description": "Displays time in 12-hour format on the lock screen and calendar. The bar clock has its own settings."
|
||||
},
|
||||
"week-numbers": {
|
||||
"label": "Show week numbers",
|
||||
"description": "Displays the week of the year (e.g., Week 38) in the calendar."
|
||||
},
|
||||
"first-day-of-week": {
|
||||
"label": "First day of week",
|
||||
"description": "Choose which day starts the week in the calendar.",
|
||||
"automatic": "Automatic (use system locale)"
|
||||
},
|
||||
"show-events": {
|
||||
"label": "Show calendar events",
|
||||
"description": "Display events in the calendar panel."
|
||||
@@ -834,10 +851,6 @@
|
||||
"description": "Changes the size of the general user interface, excluding the bar.",
|
||||
"reset-scaling": "Reset interface scaling"
|
||||
},
|
||||
"dim-desktop": {
|
||||
"label": "Dim desktop",
|
||||
"description": "Dim the desktop when panels or menus are open."
|
||||
},
|
||||
"border-radius": {
|
||||
"label": "Border radius",
|
||||
"description": "Controls the corner roundness of windows, buttons, and other elements.",
|
||||
@@ -852,6 +865,10 @@
|
||||
"label": "Disable UI Animations",
|
||||
"description": "Disable all animations for a faster, more responsive experience."
|
||||
},
|
||||
"panels-attached-to-bar": {
|
||||
"label": "Attach panels to bar",
|
||||
"description": "When enabled, panels will be attached to the bar with beautiful inverted corner design"
|
||||
},
|
||||
"panels-overlay": {
|
||||
"label": "Open panels in overlay layer",
|
||||
"description": "Panels will appear above fullscreen windows"
|
||||
@@ -1234,6 +1251,36 @@
|
||||
"width": {
|
||||
"label": "Width",
|
||||
"description": "Custom component width."
|
||||
},
|
||||
"hide-when-idle": {
|
||||
"label": "Hide when no media is playing",
|
||||
"description": "When enabled, the visualizer is hidden unless a player is actively playing."
|
||||
}
|
||||
},
|
||||
"lock-keys": {
|
||||
"indicator-style": {
|
||||
"label": "Indicator Style",
|
||||
"description": "Icon style for the lock key indicators",
|
||||
"large": "Large Letters",
|
||||
"small": "Small Letters",
|
||||
"square": "Square Letters",
|
||||
"square-round": "Rounded Squre Letters",
|
||||
"circle": "Circle Letters",
|
||||
"circle-dash": "Dashed Circle Letters",
|
||||
"circle-dot": "Dotted Circle Letters",
|
||||
"hex": "Hexagon Letters"
|
||||
},
|
||||
"show-caps-lock": {
|
||||
"label": "Caps Lock",
|
||||
"description": "Display caps lock status."
|
||||
},
|
||||
"show-num-lock": {
|
||||
"label": "Num Lock",
|
||||
"description": "Display num lock status."
|
||||
},
|
||||
"show-scroll-lock": {
|
||||
"label": "Scroll Lock",
|
||||
"description": "Display scroll lock status."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1347,8 +1394,8 @@
|
||||
"click-to-start-recording": "Click to start recording",
|
||||
"click-to-stop-recording": "Click to stop recording",
|
||||
"open-control-center": "Open control center",
|
||||
"volume-at": "Volume at {volume}%\nLeft click to toggle mute. Right click for settings.\nScroll to modify volume.",
|
||||
"microphone-volume-at": "Microphone volume at {volume}%\nLeft click to toggle mute. Right click for settings.\nScroll to modify volume.",
|
||||
"volume-at": "Output volume at {volume}%\nLeft click for settings. Right click to toggle mute.\nScroll to modify volume.",
|
||||
"microphone-volume-at": "Microphone volume at {volume}%\nLeft click for settings. Right click to toggle mute.\nScroll to modify volume.",
|
||||
"brightness-at": "Brightness: {brightness}%\nRight click for settings.\nScroll to modify brightness.",
|
||||
"manage-wifi": "Manage Wi-Fi",
|
||||
"bluetooth-devices": "Bluetooth devices",
|
||||
|
||||
@@ -257,6 +257,10 @@
|
||||
},
|
||||
"dock": {
|
||||
"title": "Dock",
|
||||
"enabled": {
|
||||
"label": "Habilitar dock",
|
||||
"description": "Mostrar u ocultar el dock por completo"
|
||||
},
|
||||
"appearance": {
|
||||
"section": {
|
||||
"label": "Apariencia",
|
||||
@@ -289,7 +293,7 @@
|
||||
"monitors": {
|
||||
"section": {
|
||||
"label": "Visualización en monitor",
|
||||
"description": "Elige en qué monitor mostrar el dock."
|
||||
"description": "Mostrar el dock en monitores específicos. Por defecto, se muestra en todos si no se elige ninguno."
|
||||
},
|
||||
"only-same-output": {
|
||||
"description": "Mostrar solo las aplicaciones de la salida donde se encuentra el dock.",
|
||||
@@ -604,6 +608,10 @@
|
||||
"pywalfox": {
|
||||
"description": "Escribir {filepath} y ejecutar pywalfox update",
|
||||
"description-missing": "Requiere que {app} esté instalado"
|
||||
},
|
||||
"code": {
|
||||
"description": "Escribe {filepath}. El tema Hyprluna debe ser instalado y activado manualmente.",
|
||||
"description-missing": "Requiere que {app} esté instalado/a."
|
||||
}
|
||||
},
|
||||
"misc": {
|
||||
@@ -645,6 +653,10 @@
|
||||
"fahrenheit": {
|
||||
"label": "Mostrar temperatura en Fahrenheit (°F)",
|
||||
"description": "Muestra la temperatura en Fahrenheit en lugar de Celsius."
|
||||
},
|
||||
"show-in-calendar": {
|
||||
"description": "Muestra el pronóstico del tiempo diario directamente en la vista de tu calendario.",
|
||||
"label": "Mostrar el clima en el calendario"
|
||||
}
|
||||
},
|
||||
"date-time": {
|
||||
@@ -653,8 +665,8 @@
|
||||
"description": "Personaliza cómo aparecen la fecha y la hora."
|
||||
},
|
||||
"12hour-format": {
|
||||
"description": "Activado para formato AM/PM (ej., 8:00 PM), desactivado para formato de 24 horas (ej., 20:00).",
|
||||
"label": "Utilice el formato de hora de 12 horas"
|
||||
"label": "Utilice el formato de hora de 12 horas",
|
||||
"description": "Muestra la hora en formato de 12 horas en la pantalla de bloqueo y el calendario. El reloj de la barra tiene su propia configuración."
|
||||
},
|
||||
"week-numbers": {
|
||||
"label": "Mostrar números de semana",
|
||||
@@ -667,6 +679,11 @@
|
||||
"use-analog": {
|
||||
"description": "Mostrar un reloj de estilo analógico en la pantalla del calendario.",
|
||||
"label": "Usar reloj de estilo analógico"
|
||||
},
|
||||
"first-day-of-week": {
|
||||
"automatic": "Automático (usar la configuración regional del sistema)",
|
||||
"description": "Elige qué día empieza la semana en el calendario.",
|
||||
"label": "Primer día de la semana"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -838,10 +855,6 @@
|
||||
"label": "Radio de borde",
|
||||
"reset": "Restablecer el radio del borde"
|
||||
},
|
||||
"dim-desktop": {
|
||||
"description": "Atenuar el escritorio cuando los paneles o menús estén abiertos.",
|
||||
"label": "Dim escritorio"
|
||||
},
|
||||
"scaling": {
|
||||
"description": "Cambia el tamaño de la interfaz de usuario general, excluyendo la barra.",
|
||||
"label": "Escalado de la interfaz",
|
||||
@@ -855,6 +868,10 @@
|
||||
"tooltips": {
|
||||
"description": "Activar o desactivar los avisos emergentes en toda la interfaz.",
|
||||
"label": "Mostrar sugerencias"
|
||||
},
|
||||
"panels-attached-to-bar": {
|
||||
"description": "Cuando está habilitado, los paneles se adjuntarán a la barra con un hermoso diseño de esquina invertida.",
|
||||
"label": "Adjuntar paneles a la barra"
|
||||
}
|
||||
},
|
||||
"lock-screen": {
|
||||
@@ -1234,6 +1251,36 @@
|
||||
"width": {
|
||||
"label": "Ancho",
|
||||
"description": "Ancho del componente personalizado."
|
||||
},
|
||||
"hide-when-idle": {
|
||||
"label": "Ocultar cuando no se reproduce",
|
||||
"description": "Si está activado, el visualizador se oculta salvo que haya reproducción activa."
|
||||
}
|
||||
},
|
||||
"lock-keys": {
|
||||
"show-caps-lock": {
|
||||
"description": "Mostrar el estado de Bloq Mayús.",
|
||||
"label": "Bloq Mayús"
|
||||
},
|
||||
"show-num-lock": {
|
||||
"description": "Mostrar el estado de bloqueo numérico.",
|
||||
"label": "Bloq Num"
|
||||
},
|
||||
"show-scroll-lock": {
|
||||
"description": "Mostrar el estado de Bloq Despl.",
|
||||
"label": "Bloq Despl"
|
||||
},
|
||||
"indicator-style": {
|
||||
"circle": "Letras circulares",
|
||||
"circle-dash": "Letras de círculo discontinuo",
|
||||
"circle-dot": "Letras de círculo punteado",
|
||||
"description": "Estilo de icono para los indicadores de las teclas de bloqueo",
|
||||
"hex": "Letras hexagonales",
|
||||
"label": "Estilo del indicador",
|
||||
"large": "Letras grandes",
|
||||
"small": "Letras minúsculas",
|
||||
"square": "Letras cuadradas",
|
||||
"square-round": "Letras cuadradas redondeadas"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1355,8 +1402,6 @@
|
||||
"click-to-start-recording": "Haz clic para iniciar la grabación",
|
||||
"click-to-stop-recording": "Haz clic para detener la grabación",
|
||||
"open-control-center": "Abrir el centro de control",
|
||||
"volume-at": "Volumen al {volume}%\nClic izquierdo para silenciar. Clic derecho para configuración.\nDesplaza para modificar el volumen.",
|
||||
"microphone-volume-at": "Volumen del micrófono al {volume}%\nClic izquierdo para silenciar. Clic derecho para configuración.\nDesplaza para modificar el volumen.",
|
||||
"brightness-at": "Brillo: {brightness}%\nClic derecho para configuración.\nDesplaza para modificar el brillo.",
|
||||
"manage-wifi": "Gestionar Wi-Fi",
|
||||
"bluetooth-devices": "Dispositivos Bluetooth",
|
||||
@@ -1370,7 +1415,9 @@
|
||||
"power-profile": "Perfil de energía '{profile}'",
|
||||
"keyboard-layout": "Distribución de teclado {layout}",
|
||||
"output-muted": "Silenciar salida de audio",
|
||||
"input-muted": "Silenciar entrada de audio"
|
||||
"input-muted": "Silenciar entrada de audio",
|
||||
"microphone-volume-at": "Volumen del micrófono al {volume}%.\nClic izquierdo para ajustes. Clic derecho para activar/desactivar el silencio.\nDesplázate para modificar el volumen.",
|
||||
"volume-at": "Volumen de salida al {volume}%.\nClic izquierdo para ajustes. Clic derecho para activar/desactivar el silencio.\nDesplázate para modificar el volumen."
|
||||
},
|
||||
"clock": {
|
||||
"tooltip": "Abrir calendario"
|
||||
|
||||
@@ -257,6 +257,10 @@
|
||||
},
|
||||
"dock": {
|
||||
"title": "Dock",
|
||||
"enabled": {
|
||||
"label": "Activer le dock",
|
||||
"description": "Afficher ou masquer complètement le dock"
|
||||
},
|
||||
"appearance": {
|
||||
"section": {
|
||||
"label": "Apparence",
|
||||
@@ -289,7 +293,7 @@
|
||||
"monitors": {
|
||||
"section": {
|
||||
"label": "Affichage sur les moniteur",
|
||||
"description": "Choisissez sur quels moniteurs afficher le dock."
|
||||
"description": "Afficher le dock sur des écrans spécifiques. Par défaut, il s'affiche sur tous les écrans si aucun n'est sélectionné."
|
||||
},
|
||||
"only-same-output": {
|
||||
"description": "Afficher uniquement les applications de la sortie où le dock est situé.",
|
||||
@@ -604,6 +608,10 @@
|
||||
"pywalfox": {
|
||||
"description": "Écrire ~/.cache/wal/colors.json et exécuter pywalfox update",
|
||||
"description-missing": "Nécessite que le paquet pywalfox soit installé"
|
||||
},
|
||||
"code": {
|
||||
"description": "Écrire {filepath}. Le thème Hyprluna doit être installé et activé manuellement.",
|
||||
"description-missing": "Nécessite l'installation de {app}"
|
||||
}
|
||||
},
|
||||
"misc": {
|
||||
@@ -645,6 +653,10 @@
|
||||
"fahrenheit": {
|
||||
"label": "Afficher la température en Fahrenheit (°F)",
|
||||
"description": "Afficher la température en Fahrenheit au lieu de Celsius."
|
||||
},
|
||||
"show-in-calendar": {
|
||||
"description": "Afficher les prévisions météo quotidiennes directement dans votre vue calendrier.",
|
||||
"label": "Afficher la météo dans le calendrier"
|
||||
}
|
||||
},
|
||||
"date-time": {
|
||||
@@ -654,7 +666,7 @@
|
||||
},
|
||||
"12hour-format": {
|
||||
"label": "Utiliser le format horaire de 12 heures",
|
||||
"description": "Activé pour le format AM/PM (ex: 8:00 PM), désactivé pour le format 24 heures (ex: 20:00)."
|
||||
"description": "Affiche l'heure au format 12 heures sur l'écran de verrouillage et dans le calendrier. L'horloge de la barre possède ses propres paramètres."
|
||||
},
|
||||
"week-numbers": {
|
||||
"label": "Afficher les numéros de semaine",
|
||||
@@ -667,6 +679,11 @@
|
||||
"use-analog": {
|
||||
"description": "Afficher une horloge de style analogique sur l'écran du calendrier.",
|
||||
"label": "Utiliser une horloge de style analogique."
|
||||
},
|
||||
"first-day-of-week": {
|
||||
"automatic": "Automatique (utiliser les paramètres régionaux du système)",
|
||||
"description": "Choisissez quel jour commence la semaine dans le calendrier.",
|
||||
"label": "Premier jour de la semaine"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -838,10 +855,6 @@
|
||||
"label": "Rayon de bordure",
|
||||
"reset": "Réinitialiser le rayon de la bordure"
|
||||
},
|
||||
"dim-desktop": {
|
||||
"description": "Atténuer le bureau lorsque des panneaux ou des menus sont ouverts.",
|
||||
"label": "Dim bureau"
|
||||
},
|
||||
"scaling": {
|
||||
"description": "Modifie la taille de l'interface utilisateur générale, à l'exception de la barre.",
|
||||
"label": "Mise à l'échelle de l'interface",
|
||||
@@ -855,6 +868,10 @@
|
||||
"tooltips": {
|
||||
"description": "Activer ou désactiver les info-bulles dans toute l'interface.",
|
||||
"label": "Afficher les infobulles"
|
||||
},
|
||||
"panels-attached-to-bar": {
|
||||
"description": "Lorsque cette option est activée, les panneaux seront attachés à la barre avec un design élégant de coin inversé.",
|
||||
"label": "Fixer les panneaux à la barre."
|
||||
}
|
||||
},
|
||||
"lock-screen": {
|
||||
@@ -1234,6 +1251,36 @@
|
||||
"width": {
|
||||
"label": "Largeur",
|
||||
"description": "Largeur personnalisée du composant."
|
||||
},
|
||||
"hide-when-idle": {
|
||||
"label": "Masquer lorsqu'aucun média n'est en lecture",
|
||||
"description": "Si activé, le visualiseur est masqué sauf lorsqu'un lecteur est en lecture."
|
||||
}
|
||||
},
|
||||
"lock-keys": {
|
||||
"show-caps-lock": {
|
||||
"description": "Afficher l'état du verrouillage majuscule.",
|
||||
"label": "Verr Maj"
|
||||
},
|
||||
"show-num-lock": {
|
||||
"description": "Afficher l'état du verrouillage numérique.",
|
||||
"label": "Verr Num"
|
||||
},
|
||||
"show-scroll-lock": {
|
||||
"description": "Afficher l'état du verrouillage du défilement.",
|
||||
"label": "Verr Maj"
|
||||
},
|
||||
"indicator-style": {
|
||||
"circle": "Lettres circulaires",
|
||||
"circle-dash": "Lettres en cercle pointillé",
|
||||
"circle-dot": "Lettres en pointillés dans un cercle",
|
||||
"description": "Style d'icône pour les indicateurs de la touche de verrouillage",
|
||||
"hex": "Lettres hexagonales",
|
||||
"label": "Style d'indicateur",
|
||||
"large": "Grandes lettres",
|
||||
"small": "Petites lettres",
|
||||
"square": "Lettres carrées",
|
||||
"square-round": "Lettres carrées arrondies"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1355,8 +1402,6 @@
|
||||
"click-to-start-recording": "Cliquez pour démarrer l'enregistrement",
|
||||
"click-to-stop-recording": "Cliquez pour arrêter l'enregistrement",
|
||||
"open-control-center": "Ouvrir le centre de contrôle",
|
||||
"volume-at": "Volume à {volume}%\nClic gauche pour couper/rétablir le son. Clic droit pour les paramètres.\nFaites défiler pour modifier le volume.",
|
||||
"microphone-volume-at": "Volume du microphone à {volume}%\nClic gauche pour couper/rétablir le son. Clic droit pour les paramètres.\nFaites défiler pour modifier le volume.",
|
||||
"brightness-at": "Luminosité : {brightness}%\nClic droit pour les paramètres.\nFaites défiler pour modifier la luminosité.",
|
||||
"manage-wifi": "Gérer le Wi-Fi",
|
||||
"bluetooth-devices": "Appareils Bluetooth",
|
||||
@@ -1370,7 +1415,9 @@
|
||||
"power-profile": "Profil d'alimentation '{profile}'",
|
||||
"keyboard-layout": "Disposition du clavier {layout}",
|
||||
"output-muted": "Couper la sortie audio",
|
||||
"input-muted": "Couper l'entrée audio"
|
||||
"input-muted": "Couper l'entrée audio",
|
||||
"microphone-volume-at": "Volume du microphone à {volume}%.\nClic gauche pour les paramètres. Clic droit pour activer/désactiver le mode muet.\nFaites défiler pour modifier le volume.",
|
||||
"volume-at": "Volume de sortie à {volume}%.\nClic gauche pour les paramètres. Clic droit pour activer/désactiver le mode muet.\nFaites défiler pour modifier le volume."
|
||||
},
|
||||
"clock": {
|
||||
"tooltip": "Ouvrir le calendrier"
|
||||
|
||||
@@ -257,6 +257,10 @@
|
||||
},
|
||||
"dock": {
|
||||
"title": "Dock",
|
||||
"enabled": {
|
||||
"label": "Ativar dock",
|
||||
"description": "Mostrar ou ocultar o dock completamente"
|
||||
},
|
||||
"appearance": {
|
||||
"section": {
|
||||
"label": "Aparência",
|
||||
@@ -289,7 +293,7 @@
|
||||
"monitors": {
|
||||
"section": {
|
||||
"label": "Exibição no monitor",
|
||||
"description": "Escolha em qual monitor exibir a dock."
|
||||
"description": "Mostrar dock em monitores específicos. O padrão é todos se nenhum for escolhido."
|
||||
},
|
||||
"only-same-output": {
|
||||
"description": "Mostrar apenas aplicativos da saída onde o dock está localizado.",
|
||||
@@ -566,6 +570,10 @@
|
||||
"pywalfox": {
|
||||
"description": "Escrever {filepath} e executar pywalfox update",
|
||||
"description-missing": "Requer que o {app} esteja instalado"
|
||||
},
|
||||
"code": {
|
||||
"description": "Escreva em {filepath}. O tema Hyprluna precisa ser instalado e ativado manualmente.",
|
||||
"description-missing": "Requer que o {app} esteja instalado."
|
||||
}
|
||||
},
|
||||
"misc": {
|
||||
@@ -607,6 +615,10 @@
|
||||
"fahrenheit": {
|
||||
"label": "Exibir temperatura em Fahrenheit (°F)",
|
||||
"description": "Exibe a temperatura em Fahrenheit em vez de Celsius."
|
||||
},
|
||||
"show-in-calendar": {
|
||||
"description": "Mostre a previsão do tempo diária diretamente na sua visualização de calendário.",
|
||||
"label": "Exibir clima no calendário"
|
||||
}
|
||||
},
|
||||
"date-time": {
|
||||
@@ -615,8 +627,8 @@
|
||||
"description": "Personalize como a data e a hora aparecem."
|
||||
},
|
||||
"12hour-format": {
|
||||
"description": "Ativado para formato AM/PM (ex., 8:00 PM), desativado para formato de 24 horas (ex., 20:00).",
|
||||
"label": "Use o formato de hora de 12 horas"
|
||||
"label": "Use o formato de hora de 12 horas",
|
||||
"description": "Exibe a hora no formato de 12 horas na tela de bloqueio e no calendário. O relógio da barra tem suas próprias configurações."
|
||||
},
|
||||
"week-numbers": {
|
||||
"label": "Mostrar números da semana",
|
||||
@@ -629,6 +641,11 @@
|
||||
"use-analog": {
|
||||
"description": "Mostrar um relógio estilo analógico na tela do calendário.",
|
||||
"label": "Use um relógio de estilo analógico."
|
||||
},
|
||||
"first-day-of-week": {
|
||||
"automatic": "Automático (usar localização do sistema)",
|
||||
"description": "Escolha qual dia começa a semana no calendário.",
|
||||
"label": "Primeiro dia da semana"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -838,10 +855,6 @@
|
||||
"label": "Raio da borda",
|
||||
"reset": "Redefinir raio da borda"
|
||||
},
|
||||
"dim-desktop": {
|
||||
"description": "Escurecer a área de trabalho quando painéis ou menus estiverem abertos.",
|
||||
"label": "Dim área de trabalho"
|
||||
},
|
||||
"scaling": {
|
||||
"description": "Altera o tamanho da interface geral do usuário, excluindo a barra.",
|
||||
"label": "Escalonamento da interface",
|
||||
@@ -855,6 +868,10 @@
|
||||
"tooltips": {
|
||||
"description": "Ativar ou desativar dicas de ferramentas em toda a interface.",
|
||||
"label": "Mostrar dicas de ferramenta"
|
||||
},
|
||||
"panels-attached-to-bar": {
|
||||
"description": "Quando ativado, os painéis serão anexados à barra com um belo design de canto invertido.",
|
||||
"label": "Anexar painéis à barra"
|
||||
}
|
||||
},
|
||||
"lock-screen": {
|
||||
@@ -1234,6 +1251,36 @@
|
||||
"width": {
|
||||
"label": "Largura",
|
||||
"description": "Largura do componente personalizado."
|
||||
},
|
||||
"hide-when-idle": {
|
||||
"label": "Ocultar quando não houver reprodução",
|
||||
"description": "Quando ativado, o visualizador fica oculto a menos que haja reprodução ativa."
|
||||
}
|
||||
},
|
||||
"lock-keys": {
|
||||
"show-caps-lock": {
|
||||
"description": "Exibir o status do Caps Lock.",
|
||||
"label": "Caps Lock"
|
||||
},
|
||||
"show-num-lock": {
|
||||
"description": "Exibir o status do Num Lock.",
|
||||
"label": "Bloq Num"
|
||||
},
|
||||
"show-scroll-lock": {
|
||||
"description": "Exibir o status do Scroll Lock.",
|
||||
"label": "Scroll Lock"
|
||||
},
|
||||
"indicator-style": {
|
||||
"circle": "Letras Circulares",
|
||||
"circle-dash": "Letras em Círculo Tracejadas",
|
||||
"circle-dot": "Letras de Círculo Pontilhado",
|
||||
"description": "Estilo de ícone para os indicadores da tecla de bloqueio.",
|
||||
"hex": "Letras Hexagonais",
|
||||
"label": "Estilo do Indicador",
|
||||
"large": "Letras grandes",
|
||||
"small": "Letras minúsculas",
|
||||
"square": "Letras Quadradas",
|
||||
"square-round": "Letras Quadradas Arredondadas"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1355,8 +1402,6 @@
|
||||
"click-to-start-recording": "Clique para iniciar a gravação",
|
||||
"click-to-stop-recording": "Clique para parar a gravação",
|
||||
"open-control-center": "Abrir central de controle",
|
||||
"volume-at": "Volume em {volume}%\nClique esquerdo para silenciar. Clique direito para configurações.\nRole para modificar o volume.",
|
||||
"microphone-volume-at": "Volume do microfone em {volume}%\nClique esquerdo para silenciar. Clique direito para configurações.\nRole para modificar o volume.",
|
||||
"brightness-at": "Brilho: {brightness}%\nClique direito para configurações.\nRole para modificar o brilho.",
|
||||
"manage-wifi": "Gerenciar Wi-Fi",
|
||||
"bluetooth-devices": "Dispositivos Bluetooth",
|
||||
@@ -1370,7 +1415,9 @@
|
||||
"power-profile": "Perfil de energia '{profile}'",
|
||||
"keyboard-layout": "Layout de teclado {layout}",
|
||||
"output-muted": "Silenciar saída de áudio",
|
||||
"input-muted": "Silenciar entrada de áudio"
|
||||
"input-muted": "Silenciar entrada de áudio",
|
||||
"microphone-volume-at": "Volume do microfone em {volume}%.\nClique esquerdo para configurações. Clique direito para ativar/desativar o mudo.\nRole para modificar o volume.",
|
||||
"volume-at": "Volume de saída em {volume}%.\nClique esquerdo para configurações. Clique direito para alternar o mudo.\nRole para modificar o volume."
|
||||
},
|
||||
"clock": {
|
||||
"tooltip": "Abrir calendário"
|
||||
|
||||
@@ -257,6 +257,10 @@
|
||||
},
|
||||
"dock": {
|
||||
"title": "Dock",
|
||||
"enabled": {
|
||||
"label": "启用 Dock",
|
||||
"description": "完全显示或隐藏 Dock"
|
||||
},
|
||||
"appearance": {
|
||||
"section": {
|
||||
"label": "外观",
|
||||
@@ -289,7 +293,7 @@
|
||||
"monitors": {
|
||||
"section": {
|
||||
"label": "显示器显示",
|
||||
"description": "选择在哪个显示器上显示 Dock。"
|
||||
"description": "在特定显示器上显示 Dock。如果未选择任何显示器,则默认为全部。"
|
||||
},
|
||||
"only-same-output": {
|
||||
"description": "仅显示输出结果中dock所在位置的应用。",
|
||||
@@ -604,6 +608,10 @@
|
||||
"pywalfox": {
|
||||
"description": "写入 {filepath} 并运行 pywalfox update",
|
||||
"description-missing": "需要安装 {app}"
|
||||
},
|
||||
"code": {
|
||||
"description": "写入 {filepath}。Hyprluna 主题需要手动安装和激活。",
|
||||
"description-missing": "需要安装 {app}"
|
||||
}
|
||||
},
|
||||
"misc": {
|
||||
@@ -645,6 +653,10 @@
|
||||
"fahrenheit": {
|
||||
"label": "以华氏度显示温度 (°F)",
|
||||
"description": "以华氏度而非摄氏度显示温度。"
|
||||
},
|
||||
"show-in-calendar": {
|
||||
"description": "直接在您的日历视图中显示每日天气预报。",
|
||||
"label": "在日历中显示天气"
|
||||
}
|
||||
},
|
||||
"date-time": {
|
||||
@@ -653,8 +665,8 @@
|
||||
"description": "自定义日期和时间的显示方式。"
|
||||
},
|
||||
"12hour-format": {
|
||||
"description": "开启为 AM/PM 格式(例如:8:00 PM),关闭为 24 小时制(例如:20:00)。",
|
||||
"label": "使用12小时制时间格式"
|
||||
"label": "使用12小时制时间格式",
|
||||
"description": "在锁屏和日历上以 12 小时制格式显示时间。状态栏时钟有其自己的设置。"
|
||||
},
|
||||
"week-numbers": {
|
||||
"label": "显示周数",
|
||||
@@ -667,6 +679,11 @@
|
||||
"use-analog": {
|
||||
"description": "在日历屏幕上显示一个模拟时钟。",
|
||||
"label": "使用模拟时钟样式"
|
||||
},
|
||||
"first-day-of-week": {
|
||||
"automatic": "自动(使用系统区域设置)",
|
||||
"description": "选择日历中一周的起始日。",
|
||||
"label": "一周的第一天"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -838,10 +855,6 @@
|
||||
"label": "边框半径",
|
||||
"reset": "重置边框半径"
|
||||
},
|
||||
"dim-desktop": {
|
||||
"description": "当面板或菜单打开时,桌面变暗。",
|
||||
"label": "昏暗的桌面"
|
||||
},
|
||||
"scaling": {
|
||||
"description": "更改通用用户界面大小,不包括栏。",
|
||||
"label": "界面缩放",
|
||||
@@ -855,6 +868,10 @@
|
||||
"tooltips": {
|
||||
"description": "启用或禁用整个界面的工具提示。",
|
||||
"label": "显示工具提示"
|
||||
},
|
||||
"panels-attached-to-bar": {
|
||||
"description": "启用后,面板将以美观的倒角设计附加到栏上。",
|
||||
"label": "将面板连接到杆上"
|
||||
}
|
||||
},
|
||||
"lock-screen": {
|
||||
@@ -1234,6 +1251,36 @@
|
||||
"width": {
|
||||
"label": "宽度",
|
||||
"description": "自定义组件的宽度。"
|
||||
},
|
||||
"hide-when-idle": {
|
||||
"label": "无媒体播放时隐藏",
|
||||
"description": "启用后,除非正在播放媒体,否则隐藏可视化显示。"
|
||||
}
|
||||
},
|
||||
"lock-keys": {
|
||||
"show-caps-lock": {
|
||||
"description": "显示大写锁定状态。",
|
||||
"label": "大写锁定"
|
||||
},
|
||||
"show-num-lock": {
|
||||
"description": "显示数字锁定键状态。",
|
||||
"label": "数字锁定"
|
||||
},
|
||||
"show-scroll-lock": {
|
||||
"description": "显示滚动锁定状态。",
|
||||
"label": "滚动锁定"
|
||||
},
|
||||
"indicator-style": {
|
||||
"hex": "六边形字母",
|
||||
"large": "大写字母",
|
||||
"small": "小写字母",
|
||||
"square": "方块字",
|
||||
"square-round": "圆角方形字母",
|
||||
"circle": "圆圈字母",
|
||||
"circle-dash": "虚线圆圈字母",
|
||||
"circle-dot": "虚线圆圈字母",
|
||||
"description": "锁键指示器的图标样式",
|
||||
"label": "指标样式"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1355,8 +1402,6 @@
|
||||
"click-to-start-recording": "点击开始录制",
|
||||
"click-to-stop-recording": "点击停止录制",
|
||||
"open-control-center": "打开控制中心",
|
||||
"volume-at": "音量 {volume}%\n左键点击切换静音。右键点击进入设置。\n滚动调整音量。",
|
||||
"microphone-volume-at": "麦克风音量 {volume}%\n左键点击切换静音。右键点击进入设置。\n滚动调整音量。",
|
||||
"brightness-at": "亮度:{brightness}%\n右键点击进入设置。\n滚动调整亮度。",
|
||||
"manage-wifi": "管理 Wi-Fi",
|
||||
"bluetooth-devices": "蓝牙设备",
|
||||
@@ -1370,7 +1415,9 @@
|
||||
"power-profile": "'{profile}' 电源模式",
|
||||
"keyboard-layout": "{layout} 键盘布局",
|
||||
"output-muted": "静音输出设备",
|
||||
"input-muted": "静音输入设备"
|
||||
"input-muted": "静音输入设备",
|
||||
"microphone-volume-at": "麦克风音量 {volume}%\n左键点击进入设置。右键点击切换静音。\n滚动滚轮调节音量。",
|
||||
"volume-at": "音量设为 {volume}%\n\n左键点击进入设置。右键点击切换静音。\n\n滚动滚轮调节音量。"
|
||||
},
|
||||
"clock": {
|
||||
"tooltip": "打开日历"
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
},
|
||||
"general": {
|
||||
"avatarImage": "",
|
||||
"dimDesktop": true,
|
||||
"showScreenCorners": false,
|
||||
"forceBlackScreenCorners": false,
|
||||
"scaleRatio": 1,
|
||||
@@ -76,7 +75,9 @@
|
||||
"use12hourFormat": false,
|
||||
"showWeekNumberInCalendar": false,
|
||||
"showCalendarEvents": true,
|
||||
"analogClockInCalendar": false
|
||||
"showCalendarWeather": true,
|
||||
"analogClockInCalendar": false,
|
||||
"firstDayOfWeek": -1
|
||||
},
|
||||
"screenRecorder": {
|
||||
"directory": "",
|
||||
@@ -172,6 +173,7 @@
|
||||
]
|
||||
},
|
||||
"dock": {
|
||||
"enabled": true,
|
||||
"displayMode": "always_visible",
|
||||
"backgroundOpacity": 1,
|
||||
"floatingRatio": 1,
|
||||
@@ -216,6 +218,7 @@
|
||||
"fontDefaultScale": 1,
|
||||
"fontFixedScale": 1,
|
||||
"tooltipsEnabled": true,
|
||||
"panelsAttachedToBar": true,
|
||||
"panelsOverlayLayer": true
|
||||
},
|
||||
"brightness": {
|
||||
@@ -250,6 +253,7 @@
|
||||
"pywalfox": false,
|
||||
"vicinae": false,
|
||||
"walker": false,
|
||||
"code": false,
|
||||
"enableUserTemplates": false
|
||||
},
|
||||
"nightLight": {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
if [ "$#" -ne 1 ]; then
|
||||
# Print usage information to standard error.
|
||||
echo "Error: No application specified." >&2
|
||||
echo "Usage: $0 {kitty|ghostty|foot|fuzzel|pywalfox}" >&2
|
||||
echo "Usage: $0 {kitty|ghostty|foot|fuzzel|walker|pywalfox}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -43,8 +43,18 @@ case "$APP_NAME" in
|
||||
echo "🎨 Applying 'noctalia' theme to foot..."
|
||||
CONFIG_FILE="$HOME/.config/foot/foot.ini"
|
||||
|
||||
# Check if the config file exists before trying to modify it.
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
# Check if the config file exists, create it if it doesn't.
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo "Config file not found, creating $CONFIG_FILE..."
|
||||
# Create the config directory if it doesn't exist
|
||||
mkdir -p "$(dirname "$CONFIG_FILE")"
|
||||
# Create the config file with the noctalia theme
|
||||
cat > "$CONFIG_FILE" << 'EOF'
|
||||
[main]
|
||||
include=~/.config/foot/themes/noctalia
|
||||
EOF
|
||||
echo "Created new config file with noctalia theme."
|
||||
else
|
||||
# Check if theme is already set to noctalia
|
||||
if grep -q "include=~/.config/foot/themes/noctalia" "$CONFIG_FILE"; then
|
||||
echo "Theme already set to noctalia, skipping modification."
|
||||
@@ -59,9 +69,6 @@ case "$APP_NAME" in
|
||||
sed -i '1i [main]\ninclude=~/.config/foot/themes/noctalia\n' "$CONFIG_FILE"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Error: foot config file not found at $CONFIG_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
@@ -86,6 +93,29 @@ case "$APP_NAME" in
|
||||
fi
|
||||
;;
|
||||
|
||||
walker)
|
||||
echo "🎨 Applying 'noctalia' theme to walker..."
|
||||
CONFIG_FILE="$HOME/.config/walker/config.toml"
|
||||
|
||||
# Check if the config file exists.
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
# Check if theme is already set to noctalia
|
||||
if grep -q '^theme = "noctalia"' "$CONFIG_FILE"; then
|
||||
echo "Theme already set to noctalia, skipping modification."
|
||||
else
|
||||
# Check if a theme line exists and replace it, otherwise append
|
||||
if grep -q '^theme = ' "$CONFIG_FILE"; then
|
||||
sed -i 's/^theme = .*/theme = "noctalia"/' "$CONFIG_FILE"
|
||||
else
|
||||
echo 'theme = "noctalia"' >> "$CONFIG_FILE"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Error: walker config file not found at $CONFIG_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
vicinae)
|
||||
echo "🎨 Applying 'matugen' theme to vicinae..."
|
||||
# Apply the theme
|
||||
|
||||
@@ -10,6 +10,7 @@ Singleton {
|
||||
|
||||
property bool isLoaded: false
|
||||
property string langCode: ""
|
||||
property var locale: Qt.locale()
|
||||
property string systemDetectedLangCode: ""
|
||||
property var availableLanguages: []
|
||||
property var translations: ({})
|
||||
@@ -198,6 +199,7 @@ Singleton {
|
||||
function setLanguage(newLangCode) {
|
||||
if (newLangCode !== langCode && availableLanguages.includes(newLangCode)) {
|
||||
langCode = newLangCode
|
||||
locale = Qt.locale(langCode)
|
||||
Logger.i("I18n", `Language set to "${langCode}"`)
|
||||
languageChanged(langCode)
|
||||
loadTranslations()
|
||||
|
||||
@@ -55,7 +55,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
|
||||
@@ -182,7 +182,6 @@ Singleton {
|
||||
// general
|
||||
property JsonObject general: JsonObject {
|
||||
property string avatarImage: ""
|
||||
property bool dimDesktop: true
|
||||
property bool showScreenCorners: false
|
||||
property bool forceBlackScreenCorners: false
|
||||
property real scaleRatio: 1.0
|
||||
@@ -203,7 +202,9 @@ Singleton {
|
||||
property bool use12hourFormat: false
|
||||
property bool showWeekNumberInCalendar: false
|
||||
property bool showCalendarEvents: true
|
||||
property bool showCalendarWeather: true
|
||||
property bool analogClockInCalendar: false
|
||||
property int firstDayOfWeek: -1 // -1 = auto (use locale), 0 = Sunday, 1 = Monday, 6 = Saturday
|
||||
}
|
||||
|
||||
// screen recorder
|
||||
@@ -296,6 +297,7 @@ Singleton {
|
||||
|
||||
// dock
|
||||
property JsonObject dock: JsonObject {
|
||||
property bool enabled: true
|
||||
property string displayMode: "always_visible" // "always_visible", "auto_hide", "exclusive"
|
||||
property real backgroundOpacity: 1.0
|
||||
property real floatingRatio: 1.0
|
||||
@@ -351,6 +353,7 @@ Singleton {
|
||||
property real fontDefaultScale: 1.0
|
||||
property real fontFixedScale: 1.0
|
||||
property bool tooltipsEnabled: true
|
||||
property bool panelsAttachedToBar: true
|
||||
property bool panelsOverlayLayer: true
|
||||
}
|
||||
|
||||
@@ -390,6 +393,7 @@ Singleton {
|
||||
property bool pywalfox: false
|
||||
property bool vicinae: false
|
||||
property bool walker: false
|
||||
property bool code: false
|
||||
property bool enableUserTemplates: false
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Loader {
|
||||
active: Settings.data.general.showScreenCorners
|
||||
active: Settings.data.general.showScreenCorners && (!Settings.data.ui.panelsAttachedToBar || Settings.data.bar.backgroundOpacity >= 1 || Settings.data.bar.floating)
|
||||
|
||||
sourceComponent: Variants {
|
||||
model: Quickshell.screens
|
||||
|
||||
@@ -63,54 +63,57 @@ NPanel {
|
||||
spacing: Style.marginM
|
||||
|
||||
// HEADER
|
||||
RowLayout {
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
implicitHeight: headerRow.implicitHeight + (Style.marginM * 2)
|
||||
|
||||
NIcon {
|
||||
icon: "settings-audio"
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: Color.mPrimary
|
||||
}
|
||||
RowLayout {
|
||||
id: headerRow
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginM
|
||||
|
||||
NText {
|
||||
text: I18n.tr("settings.audio.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
NIcon {
|
||||
icon: "settings-audio"
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: Color.mPrimary
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: AudioService.getOutputIcon()
|
||||
tooltipText: I18n.tr("tooltips.output-muted")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
AudioService.setOutputMuted(!AudioService.muted)
|
||||
NText {
|
||||
text: I18n.tr("settings.audio.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: AudioService.getOutputIcon()
|
||||
tooltipText: I18n.tr("tooltips.output-muted")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
AudioService.setOutputMuted(!AudioService.muted)
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: AudioService.getInputIcon()
|
||||
tooltipText: I18n.tr("tooltips.input-muted")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
AudioService.setInputMuted(!AudioService.inputMuted)
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: AudioService.getInputIcon()
|
||||
tooltipText: I18n.tr("tooltips.input-muted")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
AudioService.setInputMuted(!AudioService.inputMuted)
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NScrollView {
|
||||
@@ -123,8 +126,8 @@ NPanel {
|
||||
|
||||
// AudioService Devices
|
||||
ColumnLayout {
|
||||
spacing: Style.marginS
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
width: parent.width
|
||||
|
||||
// -------------------------------
|
||||
// Output Devices
|
||||
@@ -132,26 +135,27 @@ NPanel {
|
||||
id: sinks
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.marginL
|
||||
Layout.preferredHeight: outputColumn.implicitHeight + (Style.marginM * 2)
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.spacingM * Style.uiScaling
|
||||
Layout.bottomMargin: Style.marginL
|
||||
ColumnLayout {
|
||||
id: outputColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginS
|
||||
|
||||
NText {
|
||||
text: I18n.tr("settings.audio.devices.output-device.label")
|
||||
pointSize: Style.fontSizeL
|
||||
color: Color.mPrimary
|
||||
Layout.preferredWidth: root.preferredWidth * 0.3
|
||||
}
|
||||
|
||||
// Output Volume Slider
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: root.preferredWidth * 0.6
|
||||
from: 0
|
||||
to: Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
|
||||
value: localOutputVolume
|
||||
@@ -160,55 +164,55 @@ NPanel {
|
||||
onMoved: value => localOutputVolume = value
|
||||
onPressedChanged: (pressed, value) => localOutputVolumeChanging = pressed
|
||||
text: Math.round(localOutputVolume * 100) + "%"
|
||||
Layout.bottomMargin: Style.marginM
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: AudioService.sinks
|
||||
NRadioButton {
|
||||
ButtonGroup.group: sinks
|
||||
required property PwNode modelData
|
||||
pointSize: Style.fontSizeS
|
||||
text: modelData.description
|
||||
checked: AudioService.sink?.id === modelData.id
|
||||
onClicked: {
|
||||
AudioService.setAudioSink(modelData)
|
||||
localOutputVolume = AudioService.volume
|
||||
Repeater {
|
||||
model: AudioService.sinks
|
||||
NRadioButton {
|
||||
ButtonGroup.group: sinks
|
||||
required property PwNode modelData
|
||||
pointSize: Style.fontSizeS
|
||||
text: modelData.description
|
||||
checked: AudioService.sink?.id === modelData.id
|
||||
onClicked: {
|
||||
AudioService.setAudioSink(modelData)
|
||||
localOutputVolume = AudioService.volume
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Input Devices
|
||||
ButtonGroup {
|
||||
id: sources
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: inputColumn.implicitHeight + (Style.marginM * 2)
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.spacingM * Style.uiScaling
|
||||
Layout.bottomMargin: Style.marginL
|
||||
ColumnLayout {
|
||||
id: inputColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginS
|
||||
|
||||
NText {
|
||||
text: I18n.tr("settings.audio.devices.input-device.label")
|
||||
pointSize: Style.fontSizeL
|
||||
color: Color.mPrimary
|
||||
Layout.preferredWidth: root.preferredWidth * 0.3
|
||||
}
|
||||
|
||||
// Input Volume Slider
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: root.preferredWidth * 0.6
|
||||
from: 0
|
||||
to: Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
|
||||
value: localInputVolume
|
||||
@@ -217,23 +221,24 @@ NPanel {
|
||||
onMoved: value => localInputVolume = value
|
||||
onPressedChanged: (pressed, value) => localInputVolumeChanging = pressed
|
||||
text: Math.round(localInputVolume * 100) + "%"
|
||||
Layout.bottomMargin: Style.marginM
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: AudioService.sources
|
||||
//Layout.fillWidth: true
|
||||
NRadioButton {
|
||||
ButtonGroup.group: sources
|
||||
required property PwNode modelData
|
||||
pointSize: Style.fontSizeS
|
||||
text: modelData.description
|
||||
checked: AudioService.source?.id === modelData.id
|
||||
onClicked: AudioService.setAudioSource(modelData)
|
||||
Layout.fillWidth: true
|
||||
Repeater {
|
||||
model: AudioService.sources
|
||||
NRadioButton {
|
||||
ButtonGroup.group: sources
|
||||
required property PwNode modelData
|
||||
pointSize: Style.fontSizeS
|
||||
text: modelData.description
|
||||
checked: AudioService.source?.id === modelData.id
|
||||
onClicked: AudioService.setAudioSource(modelData)
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
@@ -34,59 +34,62 @@ NPanel {
|
||||
updateOptionsModel()
|
||||
}
|
||||
|
||||
panelContent: Rectangle {
|
||||
color: Color.transparent
|
||||
panelContent: Item {
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginL
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginM
|
||||
|
||||
// HEADER
|
||||
RowLayout {
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
Layout.preferredHeight: header.implicitHeight + Style.marginM * 2
|
||||
|
||||
NText {
|
||||
text: I18n.tr("battery.panel.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
RowLayout {
|
||||
id: header
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginM
|
||||
|
||||
NToggle {
|
||||
id: batteryManagerSwitch
|
||||
checked: BatteryService.chargingMode !== BatteryService.ChargingMode.Disabled
|
||||
onToggled: checked => BatteryService.toggleEnabled(checked)
|
||||
baseSize: Style.baseWidgetSize * 0.65
|
||||
}
|
||||
NText {
|
||||
text: I18n.tr("battery.panel.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
root.close()
|
||||
NToggle {
|
||||
id: batteryManagerSwitch
|
||||
checked: BatteryService.chargingMode !== BatteryService.ChargingMode.Disabled
|
||||
onToggled: checked => BatteryService.toggleEnabled(checked)
|
||||
baseSize: Style.baseWidgetSize * 0.65
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
id: batteryGroup
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: Color.transparent
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginM
|
||||
|
||||
Repeater {
|
||||
|
||||
@@ -8,7 +8,7 @@ import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
NBox {
|
||||
id: root
|
||||
|
||||
property string label: ""
|
||||
@@ -18,161 +18,170 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
Layout.preferredHeight: column.implicitHeight + Style.marginM * 2
|
||||
|
||||
NText {
|
||||
text: root.label
|
||||
pointSize: Style.fontSizeL
|
||||
color: Color.mSecondary
|
||||
font.weight: Style.fontWeightMedium
|
||||
Layout.fillWidth: true
|
||||
visible: root.model.length > 0
|
||||
}
|
||||
ColumnLayout {
|
||||
id: column
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
|
||||
Repeater {
|
||||
id: deviceList
|
||||
Layout.fillWidth: true
|
||||
model: root.model
|
||||
visible: BluetoothService.adapter && BluetoothService.adapter.enabled
|
||||
|
||||
Rectangle {
|
||||
id: device
|
||||
|
||||
readonly property bool canConnect: BluetoothService.canConnect(modelData)
|
||||
readonly property bool canDisconnect: BluetoothService.canDisconnect(modelData)
|
||||
readonly property bool isBusy: BluetoothService.isDeviceBusy(modelData)
|
||||
|
||||
function getContentColor(defaultColor = Color.mOnSurface) {
|
||||
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
||||
return Color.mPrimary
|
||||
if (modelData.blocked)
|
||||
return Color.mError
|
||||
return defaultColor
|
||||
}
|
||||
spacing: Style.marginM
|
||||
|
||||
NText {
|
||||
text: root.label
|
||||
pointSize: Style.fontSizeL
|
||||
color: Color.mSecondary
|
||||
font.weight: Style.fontWeightMedium
|
||||
visible: root.model.length > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: deviceLayout.implicitHeight + (Style.marginM * 2)
|
||||
radius: Style.radiusM
|
||||
color: Color.mSurface
|
||||
border.width: Style.borderS
|
||||
border.color: getContentColor(Color.mOutline)
|
||||
Layout.leftMargin: Style.marginM
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: deviceLayout
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginM
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Repeater {
|
||||
id: deviceList
|
||||
Layout.fillWidth: true
|
||||
model: root.model
|
||||
visible: BluetoothService.adapter && BluetoothService.adapter.enabled
|
||||
|
||||
// One device BT icon
|
||||
NIcon {
|
||||
icon: BluetoothService.getDeviceIcon(modelData)
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: getContentColor(Color.mOnSurface)
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Rectangle {
|
||||
id: device
|
||||
|
||||
readonly property bool canConnect: BluetoothService.canConnect(modelData)
|
||||
readonly property bool canDisconnect: BluetoothService.canDisconnect(modelData)
|
||||
readonly property bool isBusy: BluetoothService.isDeviceBusy(modelData)
|
||||
|
||||
function getContentColor(defaultColor = Color.mOnSurface) {
|
||||
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
||||
return Color.mPrimary
|
||||
if (modelData.blocked)
|
||||
return Color.mError
|
||||
return defaultColor
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: deviceLayout.implicitHeight + (Style.marginM * 2)
|
||||
radius: Style.radiusM
|
||||
color: Color.mSurface
|
||||
border.width: Style.borderS
|
||||
border.color: getContentColor(Color.mOutline)
|
||||
|
||||
// Device name
|
||||
NText {
|
||||
text: modelData.name || modelData.deviceName
|
||||
pointSize: Style.fontSizeM
|
||||
font.weight: Style.fontWeightMedium
|
||||
elide: Text.ElideRight
|
||||
RowLayout {
|
||||
id: deviceLayout
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginM
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
// One device BT icon
|
||||
NIcon {
|
||||
icon: BluetoothService.getDeviceIcon(modelData)
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: getContentColor(Color.mOnSurface)
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
// Status
|
||||
NText {
|
||||
text: BluetoothService.getStatusString(modelData)
|
||||
visible: text !== ""
|
||||
pointSize: Style.fontSizeXS
|
||||
color: getContentColor(Color.mOnSurfaceVariant)
|
||||
}
|
||||
|
||||
// Signal Strength
|
||||
RowLayout {
|
||||
visible: modelData.signalStrength !== undefined
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXS
|
||||
spacing: Style.marginXXS
|
||||
|
||||
// Device signal strength - "Unknown" when not connected
|
||||
// Device name
|
||||
NText {
|
||||
text: BluetoothService.getSignalStrength(modelData)
|
||||
text: modelData.name || modelData.deviceName
|
||||
pointSize: Style.fontSizeM
|
||||
font.weight: Style.fontWeightMedium
|
||||
elide: Text.ElideRight
|
||||
color: getContentColor(Color.mOnSurface)
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Status
|
||||
NText {
|
||||
text: BluetoothService.getStatusString(modelData)
|
||||
visible: text !== ""
|
||||
pointSize: Style.fontSizeXS
|
||||
color: getContentColor(Color.mOnSurfaceVariant)
|
||||
}
|
||||
|
||||
NIcon {
|
||||
visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
|
||||
icon: BluetoothService.getSignalIcon(modelData)
|
||||
pointSize: Style.fontSizeXS
|
||||
color: getContentColor(Color.mOnSurface)
|
||||
// Signal Strength
|
||||
RowLayout {
|
||||
visible: modelData.signalStrength !== undefined
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXS
|
||||
|
||||
// Device signal strength - "Unknown" when not connected
|
||||
NText {
|
||||
text: BluetoothService.getSignalStrength(modelData)
|
||||
pointSize: Style.fontSizeXS
|
||||
color: getContentColor(Color.mOnSurfaceVariant)
|
||||
}
|
||||
|
||||
NIcon {
|
||||
visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
|
||||
icon: BluetoothService.getSignalIcon(modelData)
|
||||
pointSize: Style.fontSizeXS
|
||||
color: getContentColor(Color.mOnSurface)
|
||||
}
|
||||
|
||||
NText {
|
||||
visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
|
||||
text: (modelData.signalStrength !== undefined && modelData.signalStrength > 0) ? modelData.signalStrength + "%" : ""
|
||||
pointSize: Style.fontSizeXS
|
||||
color: getContentColor(Color.mOnSurface)
|
||||
}
|
||||
}
|
||||
|
||||
// Battery
|
||||
NText {
|
||||
visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
|
||||
text: (modelData.signalStrength !== undefined && modelData.signalStrength > 0) ? modelData.signalStrength + "%" : ""
|
||||
visible: modelData.batteryAvailable
|
||||
text: BluetoothService.getBattery(modelData)
|
||||
pointSize: Style.fontSizeXS
|
||||
color: getContentColor(Color.mOnSurface)
|
||||
color: getContentColor(Color.mOnSurfaceVariant)
|
||||
}
|
||||
}
|
||||
|
||||
// Battery
|
||||
NText {
|
||||
visible: modelData.batteryAvailable
|
||||
text: BluetoothService.getBattery(modelData)
|
||||
pointSize: Style.fontSizeXS
|
||||
color: getContentColor(Color.mOnSurfaceVariant)
|
||||
// Spacer to push connect button to the right
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
// Spacer to push connect button to the right
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Call to action
|
||||
NButton {
|
||||
id: button
|
||||
visible: (modelData.state !== BluetoothDeviceState.Connecting)
|
||||
enabled: (canConnect || canDisconnect) && !isBusy
|
||||
outlined: !button.hovered
|
||||
fontSize: Style.fontSizeXS
|
||||
fontWeight: Style.fontWeightMedium
|
||||
backgroundColor: {
|
||||
if (device.canDisconnect && !isBusy) {
|
||||
return Color.mError
|
||||
// Call to action
|
||||
NButton {
|
||||
id: button
|
||||
visible: (modelData.state !== BluetoothDeviceState.Connecting)
|
||||
enabled: (canConnect || canDisconnect) && !isBusy
|
||||
outlined: !button.hovered
|
||||
fontSize: Style.fontSizeXS
|
||||
fontWeight: Style.fontWeightMedium
|
||||
backgroundColor: {
|
||||
if (device.canDisconnect && !isBusy) {
|
||||
return Color.mError
|
||||
}
|
||||
return Color.mPrimary
|
||||
}
|
||||
return Color.mPrimary
|
||||
}
|
||||
tooltipText: root.tooltipText
|
||||
text: {
|
||||
if (modelData.pairing) {
|
||||
return "Pairing..."
|
||||
tooltipText: root.tooltipText
|
||||
text: {
|
||||
if (modelData.pairing) {
|
||||
return "Pairing..."
|
||||
}
|
||||
if (modelData.blocked) {
|
||||
return "Blocked"
|
||||
}
|
||||
if (modelData.connected) {
|
||||
return "Disconnect"
|
||||
}
|
||||
return "Connect"
|
||||
}
|
||||
if (modelData.blocked) {
|
||||
return "Blocked"
|
||||
icon: (isBusy ? "busy" : null)
|
||||
onClicked: {
|
||||
if (modelData.connected) {
|
||||
BluetoothService.disconnectDevice(modelData)
|
||||
} else {
|
||||
BluetoothService.connectDeviceWithTrust(modelData)
|
||||
}
|
||||
}
|
||||
if (modelData.connected) {
|
||||
return "Disconnect"
|
||||
onRightClicked: {
|
||||
BluetoothService.forgetDevice(modelData)
|
||||
}
|
||||
return "Connect"
|
||||
}
|
||||
icon: (isBusy ? "busy" : null)
|
||||
onClicked: {
|
||||
if (modelData.connected) {
|
||||
BluetoothService.disconnectDevice(modelData)
|
||||
} else {
|
||||
BluetoothService.connectDeviceWithTrust(modelData)
|
||||
}
|
||||
}
|
||||
onRightClicked: {
|
||||
BluetoothService.forgetDevice(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import qs.Widgets
|
||||
NPanel {
|
||||
id: root
|
||||
|
||||
preferredWidth: 380 * Style.uiScaleRatio
|
||||
preferredWidth: 420 * Style.uiScaleRatio
|
||||
preferredHeight: 500 * Style.uiScaleRatio
|
||||
panelKeyboardFocus: true
|
||||
|
||||
@@ -23,63 +23,67 @@ NPanel {
|
||||
anchors.margins: Style.marginL
|
||||
spacing: Style.marginM
|
||||
|
||||
// HEADER
|
||||
RowLayout {
|
||||
// Header
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
implicitHeight: headerRow.implicitHeight + (Style.marginM * 2)
|
||||
|
||||
NIcon {
|
||||
icon: "bluetooth"
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: Color.mPrimary
|
||||
}
|
||||
RowLayout {
|
||||
id: headerRow
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Style.marginM
|
||||
anchors.rightMargin: Style.marginM
|
||||
spacing: Style.marginM
|
||||
|
||||
NText {
|
||||
text: I18n.tr("bluetooth.panel.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
NIcon {
|
||||
icon: "bluetooth"
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: Color.mPrimary
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: bluetoothSwitch
|
||||
checked: BluetoothService.enabled
|
||||
onToggled: checked => BluetoothService.setBluetoothEnabled(checked)
|
||||
baseSize: Style.baseWidgetSize * 0.65
|
||||
}
|
||||
NText {
|
||||
text: I18n.tr("bluetooth.panel.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
enabled: BluetoothService.enabled
|
||||
icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop" : "refresh"
|
||||
tooltipText: I18n.tr("tooltips.refresh-devices")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
if (BluetoothService.adapter) {
|
||||
BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering
|
||||
NToggle {
|
||||
id: bluetoothSwitch
|
||||
checked: BluetoothService.enabled
|
||||
onToggled: checked => BluetoothService.setBluetoothEnabled(checked)
|
||||
baseSize: Style.baseWidgetSize * 0.65
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
enabled: BluetoothService.enabled
|
||||
icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop" : "refresh"
|
||||
tooltipText: I18n.tr("tooltips.refresh-devices")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
if (BluetoothService.adapter) {
|
||||
BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// Adapter not available of disabled
|
||||
NBox {
|
||||
visible: !(BluetoothService.adapter && BluetoothService.adapter.enabled)
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: Color.transparent
|
||||
|
||||
// Center the content within this rectangle
|
||||
ColumnLayout {
|
||||
@@ -166,9 +170,9 @@ NPanel {
|
||||
}
|
||||
|
||||
// Fallback - No devices, scanning
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: Style.marginM
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: columnScanning.implicitHeight + Style.marginM * 2
|
||||
visible: {
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.discovering || !Bluetooth.devices) {
|
||||
return false
|
||||
@@ -180,37 +184,45 @@ NPanel {
|
||||
return (availableCount === 0)
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: Style.marginXS
|
||||
ColumnLayout {
|
||||
id: columnScanning
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
|
||||
NIcon {
|
||||
icon: "refresh"
|
||||
pointSize: Style.fontSizeXXL * 1.5
|
||||
color: Color.mPrimary
|
||||
spacing: Style.marginM
|
||||
|
||||
RotationAnimation on rotation {
|
||||
running: true
|
||||
loops: Animation.Infinite
|
||||
from: 0
|
||||
to: 360
|
||||
duration: Style.animationSlow * 4
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: Style.marginXS
|
||||
|
||||
NIcon {
|
||||
icon: "refresh"
|
||||
pointSize: Style.fontSizeXXL * 1.5
|
||||
color: Color.mPrimary
|
||||
|
||||
RotationAnimation on rotation {
|
||||
running: true
|
||||
loops: Animation.Infinite
|
||||
from: 0
|
||||
to: 360
|
||||
duration: Style.animationSlow * 4
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
text: I18n.tr("bluetooth.panel.scanning")
|
||||
pointSize: Style.fontSizeL
|
||||
color: Color.mOnSurface
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
text: I18n.tr("bluetooth.panel.scanning")
|
||||
pointSize: Style.fontSizeL
|
||||
color: Color.mOnSurface
|
||||
text: I18n.tr("bluetooth.panel.pairing-mode")
|
||||
pointSize: Style.fontSizeM
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
text: I18n.tr("bluetooth.panel.pairing-mode")
|
||||
pointSize: Style.fontSizeM
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
|
||||
106
Modules/Bar/Calendar/AnalogClock.qml
Normal file
106
Modules/Bar/Calendar/AnalogClock.qml
Normal file
@@ -0,0 +1,106 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
import Quickshell
|
||||
|
||||
Item {
|
||||
property var now
|
||||
property color backgroundColor: Color.mPrimary
|
||||
property color clockColor: Color.mOnPrimary
|
||||
property color secondHandColor: Color.mError
|
||||
anchors.fill: parent
|
||||
|
||||
Canvas {
|
||||
id: clockCanvas
|
||||
anchors.fill: parent
|
||||
|
||||
property int hours: now.getHours()
|
||||
property int minutes: now.getMinutes()
|
||||
property int seconds: now.getSeconds()
|
||||
|
||||
onPaint: {
|
||||
const markAlpha = 0.7
|
||||
var ctx = getContext("2d")
|
||||
ctx.reset()
|
||||
ctx.translate(width / 2, height / 2)
|
||||
var radius = Math.min(width, height) / 2
|
||||
|
||||
// Hour marks
|
||||
ctx.strokeStyle = Qt.alpha(clockColor, markAlpha)
|
||||
ctx.lineWidth = 2 * Style.uiScaleRatio
|
||||
var scaleFactor = 0.7
|
||||
|
||||
for (var i = 0; i < 12; i++) {
|
||||
var scaleFactor = 0.8
|
||||
if (i % 3 === 0) {
|
||||
scaleFactor = 0.65
|
||||
}
|
||||
ctx.save()
|
||||
ctx.rotate(i * Math.PI / 6)
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, -radius * scaleFactor)
|
||||
ctx.lineTo(0, -radius)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
}
|
||||
|
||||
// Hour hand
|
||||
ctx.save()
|
||||
var hourAngle = (hours % 12 + minutes / 60) * Math.PI / 6
|
||||
ctx.rotate(hourAngle)
|
||||
ctx.strokeStyle = clockColor
|
||||
ctx.lineWidth = 3 * Style.uiScaleRatio
|
||||
ctx.lineCap = "round"
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, 0)
|
||||
ctx.lineTo(0, -radius * 0.6)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
|
||||
// Minute hand
|
||||
ctx.save()
|
||||
var minuteAngle = (minutes + seconds / 60) * Math.PI / 30
|
||||
ctx.rotate(minuteAngle)
|
||||
ctx.strokeStyle = clockColor
|
||||
ctx.lineWidth = 2 * Style.uiScaleRatio
|
||||
ctx.lineCap = "round"
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, 0)
|
||||
ctx.lineTo(0, -radius * 0.9)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
|
||||
// Second hand
|
||||
ctx.save()
|
||||
var secondAngle = seconds * Math.PI / 30
|
||||
ctx.rotate(secondAngle)
|
||||
ctx.strokeStyle = secondHandColor
|
||||
ctx.lineWidth = 1.6 * Style.uiScaleRatio
|
||||
ctx.lineCap = "round"
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, 0)
|
||||
ctx.lineTo(0, -radius)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
|
||||
// Center dot
|
||||
ctx.beginPath()
|
||||
ctx.arc(0, 0, 3 * Style.uiScaleRatio, 0, 2 * Math.PI)
|
||||
ctx.fillStyle = clockColor
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
clockCanvas.hours = now.getHours()
|
||||
clockCanvas.minutes = now.getMinutes()
|
||||
clockCanvas.seconds = now.getSeconds()
|
||||
clockCanvas.requestPaint()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: requestPaint()
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
78
Modules/Bar/Calendar/ClockLoader.qml
Normal file
78
Modules/Bar/Calendar/ClockLoader.qml
Normal file
@@ -0,0 +1,78 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import Quickshell
|
||||
import "../../../Helpers/ColorsConvert.js" as ColorsConvert
|
||||
|
||||
Item {
|
||||
id: clockRoot
|
||||
property var now
|
||||
|
||||
// Default colors
|
||||
property color backgroundColor: Color.mPrimary
|
||||
property color clockColor: Color.mOnPrimary
|
||||
|
||||
property color secondHandColor: {
|
||||
var defaultColor = Color.mError
|
||||
var bestContrast = 1.0 // 1.0 is "no contrast"
|
||||
var bestColor = defaultColor
|
||||
var candidates = [Color.mSecondary, Color.mTertiary, Color.mError]
|
||||
|
||||
const minContrast = 1.149
|
||||
|
||||
for (var i = 0; i < candidates.length; i++) {
|
||||
var candidate = candidates[i]
|
||||
var contrastClock = ColorsConvert.getContrastRatio(candidate.toString(), clockColor.toString())
|
||||
if (contrastClock < minContrast) {
|
||||
continue
|
||||
}
|
||||
var contrastBg = ColorsConvert.getContrastRatio(candidate.toString(), backgroundColor.toString())
|
||||
if (contrastBg < minContrast) {
|
||||
continue
|
||||
}
|
||||
|
||||
var currentWorstContrast = Math.min(contrastBg, contrastClock)
|
||||
|
||||
if (currentWorstContrast > bestContrast) {
|
||||
bestContrast = currentWorstContrast
|
||||
bestColor = candidate
|
||||
}
|
||||
}
|
||||
|
||||
return bestColor
|
||||
}
|
||||
|
||||
property color progressColor: clockRoot.secondHandColor
|
||||
|
||||
height: Math.round((Style.fontSizeXXXL * 1.9) / 2 * Style.uiScaleRatio) * 2
|
||||
width: clockRoot.height
|
||||
|
||||
Loader {
|
||||
id: clockLoader
|
||||
anchors.fill: parent
|
||||
|
||||
source: Settings.data.location.analogClockInCalendar ? "AnalogClock.qml" : "DigitalClock.qml"
|
||||
|
||||
onLoaded: {
|
||||
item.now = Qt.binding(function () {
|
||||
return clockRoot.now
|
||||
})
|
||||
item.backgroundColor = Qt.binding(function () {
|
||||
return clockRoot.backgroundColor
|
||||
})
|
||||
item.clockColor = Qt.binding(function () {
|
||||
return clockRoot.clockColor
|
||||
})
|
||||
if (item.hasOwnProperty("secondHandColor")) {
|
||||
item.secondHandColor = Qt.binding(function () {
|
||||
return clockRoot.secondHandColor
|
||||
})
|
||||
}
|
||||
if (item.hasOwnProperty("progressColor")) {
|
||||
item.progressColor = Qt.binding(function () {
|
||||
return clockRoot.progressColor
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Modules/Bar/Calendar/DigitalClock.qml
Normal file
80
Modules/Bar/Calendar/DigitalClock.qml
Normal file
@@ -0,0 +1,80 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
import Quickshell
|
||||
|
||||
Item {
|
||||
|
||||
property var now
|
||||
property color backgroundColor: Color.mPrimary
|
||||
property color clockColor: Color.mOnPrimary
|
||||
property color progressColor: Color.mError
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
// Digital clock's seconds circular progress
|
||||
Canvas {
|
||||
id: secondsProgress
|
||||
anchors.fill: parent
|
||||
property real progress: now.getSeconds() / 60
|
||||
onProgressChanged: requestPaint()
|
||||
Connections {
|
||||
target: Time
|
||||
function onDateChanged() {
|
||||
const total = now.getSeconds() * 1000 + now.getMilliseconds()
|
||||
secondsProgress.progress = total / 60000
|
||||
}
|
||||
}
|
||||
onPaint: {
|
||||
var ctx = getContext("2d")
|
||||
var centerX = width / 2
|
||||
var centerY = height / 2
|
||||
var radius = Math.min(width, height) / 2 - 3
|
||||
ctx.reset()
|
||||
|
||||
// Background circle
|
||||
ctx.beginPath()
|
||||
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI)
|
||||
ctx.lineWidth = 2.5
|
||||
ctx.strokeStyle = Qt.alpha(clockColor, 0.15)
|
||||
ctx.stroke()
|
||||
|
||||
// Progress arc
|
||||
ctx.beginPath()
|
||||
ctx.arc(centerX, centerY, radius, -Math.PI / 2, -Math.PI / 2 + progress * 2 * Math.PI)
|
||||
ctx.lineWidth = 2.5
|
||||
ctx.strokeStyle = progressColor
|
||||
ctx.lineCap = "round"
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
// Digital clock
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: -Style.marginXXS
|
||||
|
||||
NText {
|
||||
text: {
|
||||
var t = Settings.data.location.use12hourFormat ? I18n.locale.toString(now, "hh AP") : I18n.locale.toString(now, "HH")
|
||||
return t.split(" ")[0]
|
||||
}
|
||||
|
||||
pointSize: Style.fontSizeXS
|
||||
font.weight: Style.fontWeightBold
|
||||
color: clockColor
|
||||
family: Settings.data.ui.fontFixed
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: Qt.formatTime(now, "mm")
|
||||
pointSize: Style.fontSizeXXS
|
||||
font.weight: Style.fontWeightBold
|
||||
color: clockColor
|
||||
family: Settings.data.ui.fontFixed
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import qs.Widgets
|
||||
NPanel {
|
||||
id: root
|
||||
|
||||
preferredWidth: 400 * Style.uiScaleRatio
|
||||
preferredWidth: 420 * Style.uiScaleRatio
|
||||
preferredHeight: 500 * Style.uiScaleRatio
|
||||
panelKeyboardFocus: true
|
||||
|
||||
@@ -29,51 +29,53 @@ NPanel {
|
||||
spacing: Style.marginM
|
||||
|
||||
// Header
|
||||
RowLayout {
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
Layout.preferredHeight: headerRow.implicitHeight + Style.marginM * 2
|
||||
|
||||
NIcon {
|
||||
icon: Settings.data.network.wifiEnabled ? "wifi" : "wifi-off"
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: Settings.data.network.wifiEnabled ? Color.mPrimary : Color.mOnSurfaceVariant
|
||||
}
|
||||
RowLayout {
|
||||
id: headerRow
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginM
|
||||
|
||||
NText {
|
||||
text: I18n.tr("wifi.panel.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
NIcon {
|
||||
icon: Settings.data.network.wifiEnabled ? "wifi" : "wifi-off"
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: Settings.data.network.wifiEnabled ? Color.mPrimary : Color.mOnSurfaceVariant
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: wifiSwitch
|
||||
checked: Settings.data.network.wifiEnabled
|
||||
onToggled: checked => NetworkService.setWifiEnabled(checked)
|
||||
baseSize: Style.baseWidgetSize * 0.65
|
||||
}
|
||||
NText {
|
||||
text: I18n.tr("wifi.panel.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "refresh"
|
||||
tooltipText: I18n.tr("tooltips.refresh")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
enabled: Settings.data.network.wifiEnabled && !NetworkService.scanning
|
||||
onClicked: NetworkService.scan()
|
||||
}
|
||||
NToggle {
|
||||
id: wifiSwitch
|
||||
checked: Settings.data.network.wifiEnabled
|
||||
onToggled: checked => NetworkService.setWifiEnabled(checked)
|
||||
baseSize: Style.baseWidgetSize * 0.65
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: root.close()
|
||||
NIconButton {
|
||||
icon: "refresh"
|
||||
tooltipText: I18n.tr("tooltips.refresh")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
enabled: Settings.data.network.wifiEnabled && !NetworkService.scanning
|
||||
onClicked: NetworkService.scan()
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Error message
|
||||
Rectangle {
|
||||
visible: NetworkService.lastError.length > 0
|
||||
@@ -113,16 +115,15 @@ NPanel {
|
||||
}
|
||||
|
||||
// Main content area
|
||||
Rectangle {
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: Color.transparent
|
||||
|
||||
// WiFi disabled state
|
||||
ColumnLayout {
|
||||
visible: !Settings.data.network.wifiEnabled
|
||||
anchors.fill: parent
|
||||
spacing: Style.marginM
|
||||
anchors.margins: Style.marginM
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
@@ -158,6 +159,7 @@ NPanel {
|
||||
ColumnLayout {
|
||||
visible: Settings.data.network.wifiEnabled && NetworkService.scanning && Object.keys(NetworkService.networks).length === 0
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginL
|
||||
|
||||
Item {
|
||||
@@ -187,6 +189,7 @@ NPanel {
|
||||
NScrollView {
|
||||
visible: Settings.data.network.wifiEnabled && (!NetworkService.scanning || Object.keys(NetworkService.networks).length > 0)
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AsNeeded
|
||||
clip: true
|
||||
|
||||
@@ -29,9 +29,25 @@ Item {
|
||||
|
||||
// Resolve settings: try user settings or defaults from BarWidgetRegistry
|
||||
readonly property int visualizerWidth: widgetSettings.width !== undefined ? widgetSettings.width : widgetMetadata.width
|
||||
readonly property bool hideWhenIdle: widgetSettings.hideWhenIdle !== undefined ? widgetSettings.hideWhenIdle : (widgetMetadata.hideWhenIdle !== undefined ? widgetMetadata.hideWhenIdle : false)
|
||||
readonly property bool shouldShow: (currentVisualizerType !== "" && currentVisualizerType !== "none") && (!hideWhenIdle || MediaService.isPlaying)
|
||||
|
||||
implicitWidth: visualizerWidth
|
||||
implicitHeight: Style.capsuleHeight
|
||||
implicitWidth: shouldShow ? visualizerWidth : 0
|
||||
implicitHeight: shouldShow ? Style.capsuleHeight : 0
|
||||
visible: shouldShow
|
||||
|
||||
Behavior on implicitWidth {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
Behavior on implicitHeight {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
@@ -43,27 +59,14 @@ Item {
|
||||
// Store visualizer type to force re-evaluation
|
||||
readonly property string currentVisualizerType: Settings.data.audio.visualizerType
|
||||
|
||||
// Timer to delay reload
|
||||
Timer {
|
||||
id: reloadTimer
|
||||
interval: 50
|
||||
onTriggered: {
|
||||
visualizerLoader.active = true
|
||||
}
|
||||
}
|
||||
|
||||
// Force reload when visualizer type changes
|
||||
onCurrentVisualizerTypeChanged: {
|
||||
visualizerLoader.active = false
|
||||
reloadTimer.restart()
|
||||
}
|
||||
// When visualizer type or playback changes, shouldShow updates automatically
|
||||
|
||||
// The Loader dynamically loads the appropriate visualizer based on settings
|
||||
Loader {
|
||||
id: visualizerLoader
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginS
|
||||
active: false
|
||||
active: shouldShow
|
||||
asynchronous: false
|
||||
|
||||
sourceComponent: {
|
||||
@@ -99,13 +102,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Initial activation on component complete
|
||||
Component.onCompleted: {
|
||||
if (currentVisualizerType !== "" && currentVisualizerType !== "none") {
|
||||
visualizerLoader.active = true
|
||||
}
|
||||
}
|
||||
|
||||
// No imperative activation needed; bound to shouldShow
|
||||
Component {
|
||||
id: linearComponent
|
||||
LinearSpectrum {
|
||||
|
||||
@@ -62,7 +62,7 @@ Rectangle {
|
||||
spacing: Settings.data.bar.showCapsule ? -4 : -2
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: Qt.locale().toString(now, formatHorizontal.trim()).split("\\n")
|
||||
model: I18n.locale.toString(now, formatHorizontal.trim()).split("\\n")
|
||||
NText {
|
||||
visible: text !== ""
|
||||
text: modelData
|
||||
@@ -95,7 +95,7 @@ Rectangle {
|
||||
anchors.centerIn: parent
|
||||
spacing: -2
|
||||
Repeater {
|
||||
model: Qt.locale().toString(now, formatVertical.trim()).split(" ")
|
||||
model: I18n.locale.toString(now, formatVertical.trim()).split(" ")
|
||||
delegate: NText {
|
||||
visible: text !== ""
|
||||
text: modelData
|
||||
|
||||
123
Modules/Bar/Widgets/LockKeys.qml
Normal file
123
Modules/Bar/Widgets/LockKeys.qml
Normal file
@@ -0,0 +1,123 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
import qs.Modules.Settings
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
//import qs.Modules.Bar.Extras
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string widgetId: ""
|
||||
property string section: ""
|
||||
property int sectionWidgetIndex: -1
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.data.bar.widgets[section]
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex]
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.data.bar.position
|
||||
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
||||
|
||||
readonly property string iconStyle: (widgetSettings.indicatorStyle !== undefined) ? widgetSettings.indicatorStyle : widgetMetadata.indicatorStyle
|
||||
readonly property bool showCaps: (widgetSettings.showCapsLock !== undefined) ? widgetSettings.showCapsLock : widgetMetadata.showCapsLock
|
||||
readonly property bool showNum: (widgetSettings.showNumLock !== undefined) ? widgetSettings.showNumLock : widgetMetadata.showNumLock
|
||||
readonly property bool showScroll: (widgetSettings.showScrollLock !== undefined) ? widgetSettings.showScrollLock : widgetMetadata.showScrollLock
|
||||
|
||||
implicitWidth: isVertical ? Style.capsuleHeight : Math.round(layout.implicitWidth + Style.marginM * 2)
|
||||
implicitHeight: isVertical ? Math.round(layout.implicitHeight + Style.marginM * 2) : Style.capsuleHeight
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
radius: Style.radiusM
|
||||
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
|
||||
|
||||
Item {
|
||||
id: layout
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
implicitWidth: rowLayout.visible ? rowLayout.implicitWidth : colLayout.implicitWidth
|
||||
implicitHeight: rowLayout.visible ? rowLayout.implicitHeight : colLayout.implicitHeight
|
||||
|
||||
readonly property var indicatorStyle: root.getIndicatorStyle(root.iconStyle)
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
visible: !root.isVertical
|
||||
spacing: 0
|
||||
|
||||
NIcon {
|
||||
visible: root.showCaps
|
||||
icon: layout.indicatorStyle[0]
|
||||
color: LockKeysService.capsLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showNum
|
||||
icon: layout.indicatorStyle[1]
|
||||
color: LockKeysService.numLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showScroll
|
||||
icon: layout.indicatorStyle[2]
|
||||
color: LockKeysService.scrollLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: colLayout
|
||||
visible: root.isVertical
|
||||
spacing: 0
|
||||
|
||||
NIcon {
|
||||
visible: root.showCaps
|
||||
icon: layout.indicatorStyle[0]
|
||||
color: LockKeysService.capsLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showNum
|
||||
icon: layout.indicatorStyle[1]
|
||||
color: LockKeysService.numLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showScroll
|
||||
icon: layout.indicatorStyle[2]
|
||||
color: LockKeysService.scrollLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getIndicatorStyle(styleName) {
|
||||
switch (styleName) {
|
||||
case "large":
|
||||
return ["letter-c", "letter-n", "letter-s"]
|
||||
case "small":
|
||||
return ["letter-c-small", "letter-n-small", "letter-s-small"]
|
||||
case "square":
|
||||
return ["square-letter-c", "square-letter-n", "square-letter-s"]
|
||||
case "square-round":
|
||||
return ["square-rounded-letter-c", "square-rounded-letter-n", "square-rounded-letter-s"]
|
||||
case "circle":
|
||||
return ["circle-letter-c", "circle-letter-n", "circle-letter-s"]
|
||||
case "circle-dash":
|
||||
return ["circle-dashed-letter-c", "circle-dashed-letter-n", "circle-dashed-letter-s"]
|
||||
case "circle-dot":
|
||||
return ["circle-dotted-letter-c", "circle-dotted-letter-n", "circle-dotted-letter-s"]
|
||||
case "hex":
|
||||
return ["hexagon-letter-c", "hexagon-letter-n", "hexagon-letter-s"]
|
||||
default:
|
||||
return ["letter-c", "letter-n", "letter-s"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,10 +105,10 @@ Item {
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
AudioService.setInputMuted(!AudioService.inputMuted)
|
||||
PanelService.getPanel("audioPanel")?.toggle(this)
|
||||
}
|
||||
onRightClicked: {
|
||||
PanelService.getPanel("audioPanel")?.toggle(this)
|
||||
AudioService.setInputMuted(!AudioService.inputMuted)
|
||||
}
|
||||
onMiddleClicked: {
|
||||
Quickshell.execDetached(["pwvucontrol"])
|
||||
|
||||
@@ -347,12 +347,12 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
onClicked: {
|
||||
var directPanel = PanelService.getPanel("directWidgetSettingsPanel")
|
||||
directPanel.openWidgetSettings(root.section, root.sectionWidgetIndex, root.widgetId, root.widgetSettings)
|
||||
}
|
||||
}
|
||||
// MouseArea {
|
||||
// anchors.fill: parent
|
||||
// acceptedButtons: Qt.RightButton
|
||||
// onClicked: {
|
||||
// var directPanel = PanelService.getPanel("directWidgetSettingsPanel")
|
||||
// directPanel.openWidgetSettings(root.section, root.sectionWidgetIndex, root.widgetId, root.widgetSettings)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -90,10 +90,10 @@ Item {
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
AudioService.setOutputMuted(!AudioService.muted)
|
||||
PanelService.getPanel("audioPanel")?.toggle(this)
|
||||
}
|
||||
onRightClicked: {
|
||||
PanelService.getPanel("audioPanel")?.toggle(this)
|
||||
AudioService.setOutputMuted(!AudioService.muted)
|
||||
}
|
||||
onMiddleClicked: {
|
||||
Quickshell.execDetached(["sh", "-c", "pwvucontrol || pavucontrol"])
|
||||
|
||||
@@ -179,8 +179,7 @@ NBox {
|
||||
onTriggered: function (action) {
|
||||
var index = parseInt(action)
|
||||
if (!isNaN(index)) {
|
||||
MediaService.selectedPlayerIndex = index
|
||||
MediaService.updateCurrentPlayer()
|
||||
MediaService.switchToPlayer(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,13 @@ import qs.Widgets
|
||||
NBox {
|
||||
id: root
|
||||
|
||||
property int forecastDays: 7
|
||||
property bool showLocation: true
|
||||
readonly property bool weatherReady: Settings.data.location.weatherEnabled && (LocationService.data.weather !== null)
|
||||
|
||||
visible: Settings.data.location.weatherEnabled
|
||||
implicitHeight: Math.max(100 * Style.uiScaleRatio, content.implicitHeight + (Style.marginXL * 2))
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.left: parent.left
|
||||
@@ -43,6 +48,7 @@ NBox {
|
||||
}
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
visible: showLocation
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
@@ -61,7 +67,7 @@ NBox {
|
||||
temp = Math.round(temp)
|
||||
return `${temp}°${suffix}`
|
||||
}
|
||||
pointSize: Style.fontSizeXL
|
||||
pointSize: showLocation ? Style.fontSizeXL : Style.fontSizeXL * 1.6
|
||||
font.weight: Style.fontWeightBold
|
||||
}
|
||||
|
||||
@@ -69,7 +75,7 @@ NBox {
|
||||
text: weatherReady ? `(${LocationService.data.weather.timezone_abbreviation})` : ""
|
||||
pointSize: Style.fontSizeXS
|
||||
color: Color.mOnSurfaceVariant
|
||||
visible: LocationService.data.weather
|
||||
visible: LocationService.data.weather && showLocation
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +93,7 @@ NBox {
|
||||
spacing: Style.marginM
|
||||
|
||||
Repeater {
|
||||
model: weatherReady ? LocationService.data.weather.daily.time : []
|
||||
model: weatherReady ? Math.min(root.forecastDays, LocationService.data.weather.daily.time.length) : 0
|
||||
delegate: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXS
|
||||
@@ -98,7 +104,7 @@ NBox {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
text: {
|
||||
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"))
|
||||
return Qt.locale().toString(weatherDate, "ddd")
|
||||
return I18n.locale.toString(weatherDate, "ddd")
|
||||
}
|
||||
color: Color.mOnSurface
|
||||
}
|
||||
|
||||
@@ -63,6 +63,14 @@ NPanel {
|
||||
readonly property int weatherHeight: Math.round(190 * Style.uiScaleRatio)
|
||||
readonly property int mediaSysMonHeight: Math.round(260 * Style.uiScaleRatio)
|
||||
|
||||
onOpened: {
|
||||
MediaService.autoSwitchingPaused = true
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
MediaService.autoSwitchingPaused = false
|
||||
}
|
||||
|
||||
panelContent: Item {
|
||||
id: content
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@ NIconButtonHot {
|
||||
enabled: Settings.data.wallpaper.enabled
|
||||
icon: "wallpaper-selector"
|
||||
tooltipText: I18n.tr("quickSettings.wallpaperSelector.tooltip.action")
|
||||
onClicked: PanelService.getPanel("wallpaperPanel")?.toggle(this)
|
||||
onClicked: PanelService.getPanel("wallpaperPanel")?.toggle()
|
||||
onRightClicked: WallpaperService.setRandomWallpaper()
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ Variants {
|
||||
|
||||
// PEEK WINDOW - Always visible when auto-hide is enabled
|
||||
Loader {
|
||||
active: (barIsReady || !hasBar) && modelData && Settings.data.dock.monitors.includes(modelData.name) && autoHide
|
||||
active: Settings.data.dock.enabled && (barIsReady || !hasBar) && modelData && (Settings.data.dock.monitors.length === 0 || Settings.data.dock.monitors.includes(modelData.name)) && autoHide
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
id: peekWindow
|
||||
@@ -226,7 +226,7 @@ Variants {
|
||||
|
||||
// DOCK WINDOW
|
||||
Loader {
|
||||
active: (barIsReady || !hasBar) && modelData && Settings.data.dock.monitors.includes(modelData.name) && dockLoaded && ToplevelManager && (dockApps.length > 0)
|
||||
active: Settings.data.dock.enabled && (barIsReady || !hasBar) && modelData && (Settings.data.dock.monitors.length === 0 || Settings.data.dock.monitors.includes(modelData.name)) && dockLoaded && ToplevelManager && (dockApps.length > 0)
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
id: dockWindow
|
||||
|
||||
@@ -12,6 +12,7 @@ import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Audio
|
||||
import qs.Modules.Bar.Calendar
|
||||
|
||||
Loader {
|
||||
id: lockScreen
|
||||
@@ -341,7 +342,7 @@ Loader {
|
||||
// Date below
|
||||
NText {
|
||||
text: {
|
||||
var lang = Qt.locale().name.split("_")[0]
|
||||
var lang = I18n.locale.name.split("_")[0]
|
||||
var formats = {
|
||||
"de": "dddd, d. MMMM",
|
||||
"es": "dddd, d 'de' MMMM",
|
||||
@@ -349,7 +350,7 @@ Loader {
|
||||
"pt": "dddd, d 'de' MMMM",
|
||||
"zh": "yyyy年M月d日 dddd"
|
||||
}
|
||||
return Qt.locale().toString(Time.date, formats[lang] || "dddd, MMMM d")
|
||||
return I18n.locale.toString(Time.date, formats[lang] || "dddd, MMMM d")
|
||||
}
|
||||
pointSize: Style.fontSizeXL
|
||||
font.weight: Font.Medium
|
||||
@@ -363,80 +364,15 @@ Loader {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Item {
|
||||
// Clock
|
||||
ClockLoader {
|
||||
now: Time.date
|
||||
Layout.preferredWidth: 70
|
||||
Layout.preferredHeight: 70
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
// Seconds circular progress
|
||||
Canvas {
|
||||
id: secondsProgress
|
||||
anchors.fill: parent
|
||||
|
||||
property real progress: Time.date.getSeconds() / 60
|
||||
onProgressChanged: requestPaint()
|
||||
|
||||
Connections {
|
||||
target: Time
|
||||
function onDateChanged() {
|
||||
const total = Time.date.getSeconds() * 1000 + Time.date.getMilliseconds()
|
||||
secondsProgress.progress = total / 60000
|
||||
}
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d")
|
||||
var centerX = width / 2
|
||||
var centerY = height / 2
|
||||
var radius = Math.min(width, height) / 2 - 3
|
||||
|
||||
ctx.reset()
|
||||
|
||||
// Background circle
|
||||
ctx.beginPath()
|
||||
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI)
|
||||
ctx.lineWidth = 2.5
|
||||
ctx.strokeStyle = Qt.alpha(Color.mOnSurface, 0.15)
|
||||
ctx.stroke()
|
||||
|
||||
// Progress arc
|
||||
ctx.beginPath()
|
||||
ctx.arc(centerX, centerY, radius, -Math.PI / 2, -Math.PI / 2 + progress * 2 * Math.PI)
|
||||
ctx.lineWidth = 2.5
|
||||
ctx.strokeStyle = Color.mPrimary
|
||||
ctx.lineCap = "round"
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
// Digital clock
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: 0
|
||||
|
||||
NText {
|
||||
text: {
|
||||
var t = Settings.data.location.use12hourFormat ? Qt.locale().toString(Time.date, "hh AP") : Qt.locale().toString(Time.date, "HH")
|
||||
return t
|
||||
}
|
||||
pointSize: Style.fontSizeM
|
||||
font.weight: Style.fontWeightBold
|
||||
family: Settings.data.ui.fontFixed
|
||||
color: Color.mOnSurface
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: Qt.formatTime(Time.date, "mm")
|
||||
pointSize: Style.fontSizeM
|
||||
font.weight: Style.fontWeightBold
|
||||
family: Settings.data.ui.fontFixed
|
||||
color: Color.mOnSurfaceVariant
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
backgroundColor: Color.mSurface
|
||||
clockColor: Color.mOnSurface
|
||||
secondHandColor: Color.mPrimary
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -830,7 +766,7 @@ Loader {
|
||||
NText {
|
||||
text: {
|
||||
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"))
|
||||
return Qt.locale().toString(weatherDate, "ddd")
|
||||
return I18n.locale.toString(weatherDate, "ddd")
|
||||
}
|
||||
pointSize: Style.fontSizeM
|
||||
color: Color.mOnSurfaceVariant
|
||||
|
||||
@@ -30,52 +30,55 @@ NPanel {
|
||||
spacing: Style.marginM
|
||||
|
||||
// Header section
|
||||
RowLayout {
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
implicitHeight: headerRow.implicitHeight + (Style.marginM * 2)
|
||||
|
||||
NIcon {
|
||||
icon: "bell"
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: Color.mPrimary
|
||||
}
|
||||
RowLayout {
|
||||
id: headerRow
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginM
|
||||
|
||||
NText {
|
||||
text: I18n.tr("notifications.panel.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
NIcon {
|
||||
icon: "bell"
|
||||
pointSize: Style.fontSizeXXL
|
||||
color: Color.mPrimary
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell"
|
||||
tooltipText: Settings.data.notifications.doNotDisturb ? I18n.tr("tooltips.do-not-disturb-enabled") : I18n.tr("tooltips.do-not-disturb-disabled")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
|
||||
}
|
||||
NText {
|
||||
text: I18n.tr("notifications.panel.title")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "trash"
|
||||
tooltipText: I18n.tr("tooltips.clear-history")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
NotificationService.clearHistory()
|
||||
// Close panel as there is nothing more to see.
|
||||
root.close()
|
||||
NIconButton {
|
||||
icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell"
|
||||
tooltipText: Settings.data.notifications.doNotDisturb ? I18n.tr("tooltips.do-not-disturb-enabled") : I18n.tr("tooltips.do-not-disturb-disabled")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "trash"
|
||||
tooltipText: I18n.tr("tooltips.clear-history")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
NotificationService.clearHistory()
|
||||
// Close panel as there is nothing more to see.
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: root.close()
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: root.close()
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Empty state when no notifications
|
||||
|
||||
@@ -17,14 +17,11 @@ Popup {
|
||||
|
||||
signal updateWidgetSettings(string section, int index, var settings)
|
||||
|
||||
// Center popup in parent
|
||||
x: (parent.width - width) * 0.5
|
||||
y: (parent.height - height) * 0.5
|
||||
|
||||
width: Math.max(content.implicitWidth + padding * 2, 500)
|
||||
height: content.implicitHeight + padding * 2
|
||||
padding: Style.marginXL
|
||||
modal: true
|
||||
anchors.centerIn: parent
|
||||
|
||||
onOpened: {
|
||||
// Mark this popup has opened in the PanelService
|
||||
@@ -131,6 +128,7 @@ Popup {
|
||||
"ControlCenter": "WidgetSettings/ControlCenterSettings.qml",
|
||||
"CustomButton": "WidgetSettings/CustomButtonSettings.qml",
|
||||
"KeyboardLayout": "WidgetSettings/KeyboardLayoutSettings.qml",
|
||||
"LockKeys": "WidgetSettings/LockKeysSettings.qml",
|
||||
"MediaMini": "WidgetSettings/MediaMiniSettings.qml",
|
||||
"Microphone": "WidgetSettings/MicrophoneSettings.qml",
|
||||
"NotificationHistory": "WidgetSettings/NotificationHistorySettings.qml",
|
||||
|
||||
@@ -13,9 +13,13 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
// Local state
|
||||
property bool valueHideWhenIdle: widgetData.hideWhenIdle !== undefined ? widgetData.hideWhenIdle : (widgetMetadata.hideWhenIdle !== undefined ? widgetMetadata.hideWhenIdle : false)
|
||||
|
||||
function saveSettings() {
|
||||
var settings = Object.assign({}, widgetData || {})
|
||||
settings.width = parseInt(widthInput.text) || widgetMetadata.width
|
||||
settings.hideWhenIdle = valueHideWhenIdle
|
||||
return settings
|
||||
}
|
||||
|
||||
@@ -27,4 +31,11 @@ ColumnLayout {
|
||||
text: widgetData.width || widgetMetadata.width
|
||||
placeholderText: I18n.tr("placeholders.enter-width-pixels")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.widget-settings.audio-visualizer.hide-when-idle.label")
|
||||
description: I18n.tr("bar.widget-settings.audio-visualizer.hide-when-idle.description")
|
||||
checked: valueHideWhenIdle
|
||||
onToggled: checked => valueHideWhenIdle = checked
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ ColumnLayout {
|
||||
// Horizontal
|
||||
Repeater {
|
||||
Layout.topMargin: Style.marginM
|
||||
model: Qt.locale().toString(now, valueFormatHorizontal.trim()).split("\\n")
|
||||
model: I18n.locale.toString(now, valueFormatHorizontal.trim()).split("\\n")
|
||||
delegate: NText {
|
||||
visible: text !== ""
|
||||
text: modelData
|
||||
@@ -231,7 +231,7 @@ ColumnLayout {
|
||||
|
||||
Repeater {
|
||||
Layout.topMargin: Style.marginM
|
||||
model: Qt.locale().toString(now, valueFormatVertical.trim()).split(" ")
|
||||
model: I18n.locale.toString(now, valueFormatVertical.trim()).split(" ")
|
||||
delegate: NText {
|
||||
visible: text !== ""
|
||||
text: modelData
|
||||
|
||||
84
Modules/Settings/Bar/WidgetSettings/LockKeysSettings.qml
Normal file
84
Modules/Settings/Bar/WidgetSettings/LockKeysSettings.qml
Normal file
@@ -0,0 +1,84 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
import qs.Services
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginM
|
||||
|
||||
// Properties to receive data from parent
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
// Local state
|
||||
property string valueIndicatorStyle: widgetData.indicatorStyle !== undefined ? widgetData.indicatorStyle : widgetMetadata.indicatorStyle
|
||||
property bool valueShowCapsLock: widgetData.showCapsLock !== undefined ? widgetData.showCapsLock : widgetMetadata.showCapsLock
|
||||
property bool valueShowNumLock: widgetData.showNumLock !== undefined ? widgetData.showNumLock : widgetMetadata.showNumLock
|
||||
property bool valueShowScrollLock: widgetData.showScrollLock !== undefined ? widgetData.showScrollLock : widgetMetadata.showScrollLock
|
||||
|
||||
function saveSettings() {
|
||||
var settings = Object.assign({}, widgetData || {})
|
||||
settings.indicatorStyle = valueIndicatorStyle
|
||||
settings.showCapsLock = valueShowCapsLock
|
||||
settings.showNumLock = valueShowNumLock
|
||||
settings.showScrollLock = valueShowScrollLock
|
||||
return settings
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.widget-settings.lock-keys.indicator-style.label")
|
||||
description: I18n.tr("bar.widget-settings.lock-keys.indicator-style.description")
|
||||
model: [{
|
||||
"key": "large",
|
||||
"name": I18n.tr("bar.widget-settings.lock-keys.indicator-style.large")
|
||||
}, {
|
||||
"key": "small",
|
||||
"name": I18n.tr("bar.widget-settings.lock-keys.indicator-style.small")
|
||||
}, {
|
||||
"key": "square",
|
||||
"name": I18n.tr("bar.widget-settings.lock-keys.indicator-style.square")
|
||||
}, {
|
||||
"key": "square-round",
|
||||
"name": I18n.tr("bar.widget-settings.lock-keys.indicator-style.square-round")
|
||||
}, {
|
||||
"key": "circle",
|
||||
"name": I18n.tr("bar.widget-settings.lock-keys.indicator-style.circle")
|
||||
}, {
|
||||
"key": "circle-dash",
|
||||
"name": I18n.tr("bar.widget-settings.lock-keys.indicator-style.circle-dash")
|
||||
}, {
|
||||
"key": "circle-dot",
|
||||
"name": I18n.tr("bar.widget-settings.lock-keys.indicator-style.circle-dot")
|
||||
}, {
|
||||
"key": "hex",
|
||||
"name": I18n.tr("bar.widget-settings.lock-keys.indicator-style.hex")
|
||||
}]
|
||||
currentKey: valueIndicatorStyle
|
||||
onSelected: key => valueIndicatorStyle = key
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.widget-settings.lock-keys.show-caps-lock.label")
|
||||
description: I18n.tr("bar.widget-settings.lock-keys.show-caps-lock.description")
|
||||
checked: valueShowCapsLock
|
||||
onToggled: checked => valueShowCapsLock = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.widget-settings.lock-keys.show-num-lock.label")
|
||||
description: I18n.tr("bar.widget-settings.lock-keys.show-num-lock.description")
|
||||
checked: valueShowNumLock
|
||||
onToggled: checked => valueShowNumLock = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.widget-settings.lock-keys.show-scroll-lock.label")
|
||||
description: I18n.tr("bar.widget-settings.lock-keys.show-scroll-lock.description")
|
||||
checked: valueShowScrollLock
|
||||
onToggled: checked => valueShowScrollLock = checked
|
||||
}
|
||||
}
|
||||
@@ -13,17 +13,20 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
property string valueLabelMode: widgetData.labelMode !== undefined ? widgetData.labelMode : widgetMetadata.labelMode
|
||||
property bool valueHideUnoccupied: widgetData.hideUnoccupied !== undefined ? widgetData.hideUnoccupied : widgetMetadata.hideUnoccupied
|
||||
property int valueCharacterCount: widgetData.characterCount !== undefined ? widgetData.characterCount : widgetMetadata.characterCount
|
||||
|
||||
function saveSettings() {
|
||||
var settings = Object.assign({}, widgetData || {})
|
||||
settings.labelMode = labelModeCombo.currentKey
|
||||
settings.hideUnoccupied = hideUnoccupiedToggle.checked
|
||||
settings.characterCount = characterCountSpinBox.value
|
||||
settings.labelMode = valueLabelMode
|
||||
settings.hideUnoccupied = valueHideUnoccupied
|
||||
settings.characterCount = valueCharacterCount
|
||||
return settings
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
id: labelModeCombo
|
||||
|
||||
label: I18n.tr("bar.widget-settings.workspace.label-mode.label")
|
||||
description: I18n.tr("bar.widget-settings.workspace.label-mode.description")
|
||||
model: [{
|
||||
@@ -37,33 +40,24 @@ ColumnLayout {
|
||||
"name": I18n.tr("options.workspace-labels.name")
|
||||
}]
|
||||
currentKey: widgetData.labelMode || widgetMetadata.labelMode
|
||||
onSelected: key => labelModeCombo.currentKey = key
|
||||
onSelected: key => valueLabelMode = key
|
||||
minimumWidth: 200
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: hideUnoccupiedToggle
|
||||
label: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.label")
|
||||
description: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.description")
|
||||
checked: widgetData.hideUnoccupied
|
||||
onToggled: checked => hideUnoccupiedToggle.checked = checked
|
||||
checked: valueHideUnoccupied
|
||||
onToggled: checked => valueHideUnoccupied = checked
|
||||
}
|
||||
|
||||
NSpinBox {
|
||||
id: characterCountSpinBox
|
||||
label: I18n.tr("bar.widget-settings.workspace.character-count.label")
|
||||
description: I18n.tr("bar.widget-settings.workspace.character-count.description")
|
||||
from: 1
|
||||
to: 10
|
||||
value: {
|
||||
if (widgetData && widgetData.characterCount !== undefined) {
|
||||
return widgetData.characterCount
|
||||
}
|
||||
if (widgetMetadata && widgetMetadata.characterCount !== undefined) {
|
||||
return widgetMetadata.characterCount
|
||||
}
|
||||
return 2
|
||||
}
|
||||
visible: labelModeCombo.currentKey === "name"
|
||||
value: valueCharacterCount
|
||||
onValueChanged: valueCharacterCount = value
|
||||
visible: valueLabelMode === "name"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +223,8 @@ NPanel {
|
||||
|
||||
// When the panel opens, choose the appropriate tab
|
||||
onOpened: {
|
||||
// Run program availability checks every time settings opens
|
||||
ProgramCheckerService.checkAllPrograms()
|
||||
updateTabsModel()
|
||||
|
||||
var initialIndex = SettingsPanel.Tab.General
|
||||
|
||||
@@ -697,51 +697,24 @@ ColumnLayout {
|
||||
onToggled: checked => {
|
||||
if (ProgramCheckerService.walkerAvailable) {
|
||||
Settings.data.templates.walker = checked
|
||||
if (checked) {
|
||||
// Update walker config.toml to use noctalia theme
|
||||
var configFile = Quickshell.env("HOME") + "/.config/walker/config.toml"
|
||||
var configDir = Quickshell.env("HOME") + "/.config/walker"
|
||||
var configFileEsc = configFile.replace(/'/g, "'\\''")
|
||||
var configDirEsc = configDir.replace(/'/g, "'\\''")
|
||||
AppThemeService.generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.i("ColorSchemeTab", "Updating walker config:", configFile)
|
||||
Logger.d("ColorSchemeTab", "Config file path:", configFileEsc)
|
||||
Logger.d("ColorSchemeTab", "Config dir path:", configDirEsc)
|
||||
|
||||
// Remove existing theme line and insert new one at the top
|
||||
var script = "echo '[Walker Config] Starting update...' && "
|
||||
script += "mkdir -p '" + configDirEsc + "' && "
|
||||
script += "echo '[Walker Config] Directory created/verified' && "
|
||||
script += "if [ -f '" + configFileEsc + "' ]; then "
|
||||
script += "echo '[Walker Config] File exists, removing old theme line' && "
|
||||
script += "(grep -v '^theme[[:space:]]*=' '" + configFileEsc + "' > '" + configFileEsc + ".tmp' 2>/dev/null || cat '" + configFileEsc + "' > '" + configFileEsc + ".tmp') && "
|
||||
script += "mv '" + configFileEsc + ".tmp' '" + configFileEsc + "' && "
|
||||
script += "echo '[Walker Config] Removed old theme line'; "
|
||||
script += "else echo '[Walker Config] File does not exist, will create'; "
|
||||
script += "fi && "
|
||||
script += "echo 'theme = \"noctalia\"' | cat - '" + configFileEsc + "' > '" + configFileEsc + ".tmp' && "
|
||||
script += "mv '" + configFileEsc + ".tmp' '" + configFileEsc + "' && "
|
||||
script += "echo '[Walker Config] Inserted theme at top' && "
|
||||
script += "FINAL_THEME=$(grep '^theme' '" + configFileEsc + "' | head -1 2>/dev/null) && "
|
||||
script += "echo '[Walker Config] Final theme line: '$FINAL_THEME || echo '[Walker Config] ERROR: Theme line not found after update'"
|
||||
|
||||
Logger.d("ColorSchemeTab", "Executing script:", script)
|
||||
|
||||
// Execute script using execDetached
|
||||
Quickshell.execDetached(["sh", "-c", script])
|
||||
|
||||
// Verify the update after a short delay
|
||||
Qt.callLater(function () {
|
||||
var verifyScript = "grep '^theme' '" + configFileEsc + "' | head -1 2>/dev/null || echo 'NOT_FOUND'"
|
||||
var verifyProcessStr = "import QtQuick; import Quickshell.Io; Process { command: [\"sh\", \"-c\", \"" + verifyScript.replace(/"/g, '\\"') + "\"]; stdout: StdioCollector {} }"
|
||||
var verifyProcess = Qt.createQmlObject(verifyProcessStr, root, "walkerVerify")
|
||||
verifyProcess.exited.connect(function (exitCode) {
|
||||
Logger.i("ColorSchemeTab", "Walker theme verification:", verifyProcess.stdout.text || "NOT FOUND")
|
||||
verifyProcess.destroy()
|
||||
})
|
||||
verifyProcess.running = true
|
||||
})
|
||||
}
|
||||
NCheckbox {
|
||||
label: "Code"
|
||||
description: ProgramCheckerService.codeAvailable ? I18n.tr("settings.color-scheme.templates.programs.code.description", {
|
||||
"filepath": "~/.vscode/extensions/hyprluna.hyprluna-theme-1.0.2/themes/hyprluna.json"
|
||||
}) : I18n.tr("settings.color-scheme.templates.programs.code.description-missing", {
|
||||
"app": "code"
|
||||
})
|
||||
checked: Settings.data.templates.code
|
||||
enabled: ProgramCheckerService.codeAvailable
|
||||
opacity: ProgramCheckerService.codeAvailable ? 1.0 : 0.6
|
||||
onToggled: checked => {
|
||||
if (ProgramCheckerService.codeAvailable) {
|
||||
Settings.data.templates.code = checked
|
||||
AppThemeService.generate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,16 @@ ColumnLayout {
|
||||
description: I18n.tr("settings.dock.appearance.section.description")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.dock.enabled.label")
|
||||
description: I18n.tr("settings.dock.enabled.description")
|
||||
checked: Settings.data.dock.enabled
|
||||
onToggled: checked => Settings.data.dock.enabled = checked
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
visible: Settings.data.dock.enabled
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.dock.appearance.display.label")
|
||||
description: I18n.tr("settings.dock.appearance.display.description")
|
||||
@@ -50,6 +59,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: Settings.data.dock.enabled
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
NLabel {
|
||||
@@ -68,6 +78,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: Settings.data.dock.enabled
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -88,6 +99,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: Settings.data.dock.enabled
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
NLabel {
|
||||
@@ -106,6 +118,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
NToggle {
|
||||
visible: Settings.data.dock.enabled
|
||||
label: I18n.tr("settings.dock.monitors.only-same-output.label")
|
||||
description: I18n.tr("settings.dock.monitors.only-same-output.description")
|
||||
checked: Settings.data.dock.onlySameOutput
|
||||
@@ -113,6 +126,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
NToggle {
|
||||
visible: Settings.data.dock.enabled
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.dock.appearance.colorize-icons.label")
|
||||
description: I18n.tr("settings.dock.appearance.colorize-icons.description")
|
||||
@@ -121,6 +135,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
NDivider {
|
||||
visible: Settings.data.dock.enabled
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginXL
|
||||
Layout.bottomMargin: Style.marginXL
|
||||
@@ -128,6 +143,7 @@ ColumnLayout {
|
||||
|
||||
// Monitor Configuration
|
||||
ColumnLayout {
|
||||
visible: Settings.data.dock.enabled
|
||||
spacing: Style.marginM
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -163,6 +179,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
NDivider {
|
||||
visible: Settings.data.dock.enabled
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginXL
|
||||
Layout.bottomMargin: Style.marginXL
|
||||
|
||||
@@ -84,7 +84,14 @@ ColumnLayout {
|
||||
checked: Settings.data.location.useFahrenheit
|
||||
onToggled: checked => Settings.data.location.useFahrenheit = checked
|
||||
enabled: Settings.data.location.weatherEnabled
|
||||
opacity: Settings.data.location.weatherEnabled ? 1.0 : 0.5
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("settings.location.weather.show-in-calendar.label")
|
||||
description: I18n.tr("settings.location.weather.show-in-calendar.description")
|
||||
checked: Settings.data.location.showCalendarWeather
|
||||
onToggled: checked => Settings.data.location.showCalendarWeather = checked
|
||||
enabled: Settings.data.location.weatherEnabled
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +125,30 @@ ColumnLayout {
|
||||
onToggled: checked => Settings.data.location.showWeekNumberInCalendar = checked
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
label: I18n.tr("settings.location.date-time.first-day-of-week.label")
|
||||
description: I18n.tr("settings.location.date-time.first-day-of-week.description")
|
||||
currentKey: Settings.data.location.firstDayOfWeek.toString()
|
||||
minimumWidth: 260 * Style.uiScaleRatio
|
||||
model: [{
|
||||
"key": "-1",
|
||||
"name": I18n.tr("settings.location.date-time.first-day-of-week.automatic")
|
||||
}, {
|
||||
"key": "6",
|
||||
"name": I18n.locale.dayName(6, Locale.LongFormat)
|
||||
}, // Saturday
|
||||
{
|
||||
"key": "0",
|
||||
"name": I18n.locale.dayName(0, Locale.LongFormat)
|
||||
}, // Sunday
|
||||
{
|
||||
"key": "1",
|
||||
"name": I18n.locale.dayName(1, Locale.LongFormat)
|
||||
} // Monday
|
||||
]
|
||||
onSelected: key => Settings.data.location.firstDayOfWeek = parseInt(key)
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("settings.location.date-time.show-events.label")
|
||||
description: I18n.tr("settings.location.date-time.show-events.description")
|
||||
|
||||
@@ -19,13 +19,6 @@ ColumnLayout {
|
||||
description: I18n.tr("settings.user-interface.section.description")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("settings.user-interface.dim-desktop.label")
|
||||
description: I18n.tr("settings.user-interface.dim-desktop.description")
|
||||
checked: Settings.data.general.dimDesktop
|
||||
onToggled: checked => Settings.data.general.dimDesktop = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("settings.user-interface.tooltips.label")
|
||||
description: I18n.tr("settings.user-interface.tooltips.description")
|
||||
@@ -33,6 +26,13 @@ ColumnLayout {
|
||||
onToggled: checked => Settings.data.ui.tooltipsEnabled = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("settings.user-interface.panels-attached-to-bar.label")
|
||||
description: I18n.tr("settings.user-interface.panels-attached-to-bar.description")
|
||||
checked: Settings.data.ui.panelsAttachedToBar
|
||||
onToggled: checked => Settings.data.ui.panelsAttachedToBar = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("settings.user-interface.panels-overlay.label")
|
||||
description: I18n.tr("settings.user-interface.panels-overlay.description")
|
||||
|
||||
@@ -65,7 +65,7 @@ ColumnLayout {
|
||||
|
||||
Layout.fillWidth: true
|
||||
radius: Style.radiusM
|
||||
color: Color.mSurfaceVariant
|
||||
color: Color.mSurface
|
||||
border.color: Color.mOutline
|
||||
border.width: Style.borderS
|
||||
implicitHeight: contentCol.implicitHeight + Style.marginL * 2
|
||||
|
||||
@@ -11,11 +11,9 @@ ColumnLayout {
|
||||
|
||||
property real selectedScaleRatio: 1.0
|
||||
property string selectedBarPosition: "top"
|
||||
property bool selectedDimDesktop: true
|
||||
|
||||
signal scaleRatioChanged(real ratio)
|
||||
signal barPositionChanged(string position)
|
||||
signal dimDesktopChanged(bool dim)
|
||||
|
||||
spacing: Style.marginM
|
||||
|
||||
@@ -197,61 +195,6 @@ ColumnLayout {
|
||||
Layout.bottomMargin: Style.marginS
|
||||
}
|
||||
|
||||
// Dim Desktop section
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
|
||||
Rectangle {
|
||||
width: 32
|
||||
height: 32
|
||||
radius: Style.radiusM
|
||||
color: Color.mSurface
|
||||
NIcon {
|
||||
icon: "moon"
|
||||
pointSize: Style.fontSizeL
|
||||
color: Color.mPrimary
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
NText {
|
||||
text: I18n.tr("settings.user-interface.dim-desktop.label")
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
}
|
||||
NText {
|
||||
text: I18n.tr("settings.user-interface.dim-desktop.description")
|
||||
pointSize: Style.fontSizeS
|
||||
color: Color.mOnSurfaceVariant
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
checked: selectedDimDesktop
|
||||
onToggled: function (checked) {
|
||||
selectedDimDesktop = checked
|
||||
dimDesktopChanged(checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Divider
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Color.mOutline
|
||||
opacity: 0.2
|
||||
Layout.topMargin: Style.marginS
|
||||
Layout.bottomMargin: Style.marginS
|
||||
}
|
||||
|
||||
// Bar Density section
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
203
Modules/SetupWizard/SetupDockStep.qml
Normal file
203
Modules/SetupWizard/SetupDockStep.qml
Normal file
@@ -0,0 +1,203 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
spacing: Style.marginM
|
||||
|
||||
// Header
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.marginL
|
||||
spacing: Style.marginM
|
||||
|
||||
Rectangle {
|
||||
width: 40
|
||||
height: 40
|
||||
radius: Style.radiusL
|
||||
color: Color.mSurfaceVariant
|
||||
opacity: 0.6
|
||||
|
||||
NIcon {
|
||||
icon: "device-desktop"
|
||||
pointSize: Style.fontSizeL
|
||||
color: Color.mPrimary
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXS
|
||||
|
||||
NText {
|
||||
text: I18n.tr("settings.dock.title") || "Dock"
|
||||
pointSize: Style.fontSizeXL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mPrimary
|
||||
}
|
||||
|
||||
NText {
|
||||
text: I18n.tr("settings.dock.monitors.section.description")
|
||||
pointSize: Style.fontSizeM
|
||||
color: Color.mOnSurfaceVariant
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Options
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginL
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.dock.enabled.label")
|
||||
description: I18n.tr("settings.dock.enabled.description")
|
||||
checked: Settings.data.dock.enabled
|
||||
onToggled: checked => Settings.data.dock.enabled = checked
|
||||
}
|
||||
|
||||
// Display behavior
|
||||
NComboBox {
|
||||
visible: Settings.data.dock.enabled
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.dock.appearance.display.label")
|
||||
description: I18n.tr("settings.dock.appearance.display.description")
|
||||
model: [{
|
||||
"key": "always_visible",
|
||||
"name": I18n.tr("settings.dock.appearance.display.always-visible")
|
||||
}, {
|
||||
"key": "auto_hide",
|
||||
"name": I18n.tr("settings.dock.appearance.display.auto-hide")
|
||||
}, {
|
||||
"key": "exclusive",
|
||||
"name": I18n.tr("settings.dock.appearance.display.exclusive")
|
||||
}]
|
||||
currentKey: Settings.data.dock.displayMode
|
||||
onSelected: key => Settings.data.dock.displayMode = key
|
||||
}
|
||||
|
||||
// Background opacity
|
||||
ColumnLayout {
|
||||
visible: Settings.data.dock.enabled
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
NLabel {
|
||||
label: I18n.tr("settings.dock.appearance.background-opacity.label")
|
||||
description: I18n.tr("settings.dock.appearance.background-opacity.description")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: 1
|
||||
stepSize: 0.01
|
||||
value: Settings.data.dock.backgroundOpacity
|
||||
onMoved: value => Settings.data.dock.backgroundOpacity = value
|
||||
text: Math.floor(Settings.data.dock.backgroundOpacity * 100) + "%"
|
||||
}
|
||||
}
|
||||
|
||||
// Floating distance
|
||||
ColumnLayout {
|
||||
visible: Settings.data.dock.enabled
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
NLabel {
|
||||
label: I18n.tr("settings.dock.appearance.floating-distance.label")
|
||||
description: I18n.tr("settings.dock.appearance.floating-distance.description")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: 4
|
||||
stepSize: 0.01
|
||||
value: Settings.data.dock.floatingRatio
|
||||
onMoved: value => Settings.data.dock.floatingRatio = value
|
||||
text: Math.floor(Settings.data.dock.floatingRatio * 100) + "%"
|
||||
}
|
||||
}
|
||||
|
||||
// Icon size
|
||||
ColumnLayout {
|
||||
visible: Settings.data.dock.enabled
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
NLabel {
|
||||
label: I18n.tr("settings.dock.appearance.icon-size.label")
|
||||
description: I18n.tr("settings.dock.appearance.icon-size.description")
|
||||
}
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: 2
|
||||
stepSize: 0.01
|
||||
value: Settings.data.dock.size
|
||||
onMoved: value => Settings.data.dock.size = value
|
||||
text: Math.floor(Settings.data.dock.size * 100) + "%"
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
visible: Settings.data.dock.enabled
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.dock.monitors.only-same-output.label")
|
||||
description: I18n.tr("settings.dock.monitors.only-same-output.description")
|
||||
checked: Settings.data.dock.onlySameOutput
|
||||
onToggled: checked => Settings.data.dock.onlySameOutput = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
visible: Settings.data.dock.enabled
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.dock.appearance.colorize-icons.label")
|
||||
description: I18n.tr("settings.dock.appearance.colorize-icons.description")
|
||||
checked: Settings.data.dock.colorizeIcons
|
||||
onToggled: checked => Settings.data.dock.colorizeIcons = checked
|
||||
}
|
||||
|
||||
NHeader {
|
||||
visible: Settings.data.dock.enabled
|
||||
label: I18n.tr("settings.dock.monitors.section.label")
|
||||
description: I18n.tr("settings.dock.monitors.section.description")
|
||||
}
|
||||
|
||||
Repeater {
|
||||
visible: Settings.data.dock.enabled
|
||||
model: Quickshell.screens || []
|
||||
delegate: NCheckbox {
|
||||
Layout.fillWidth: true
|
||||
label: modelData.name || "Unknown"
|
||||
visible: Settings.data.dock.enabled
|
||||
description: {
|
||||
const compositorScale = CompositorService.getDisplayScale(modelData.name)
|
||||
I18n.tr("system.monitor-description", {
|
||||
"model": modelData.model,
|
||||
"width": modelData.width * compositorScale,
|
||||
"height": modelData.height * compositorScale,
|
||||
"scale": compositorScale
|
||||
})
|
||||
}
|
||||
checked: (Settings.data.dock.monitors || []).indexOf(modelData.name) !== -1
|
||||
onToggled: checked => {
|
||||
if (checked) {
|
||||
const arr = (Settings.data.dock.monitors || []).slice()
|
||||
if (arr.indexOf(modelData.name) === -1)
|
||||
arr.push(modelData.name)
|
||||
Settings.data.dock.monitors = arr
|
||||
} else {
|
||||
Settings.data.dock.monitors = (Settings.data.dock.monitors || []).filter(function (n) {
|
||||
return n !== modelData.name
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,11 +199,34 @@ ColumnLayout {
|
||||
visible: filteredWallpapers.length > 0
|
||||
|
||||
ScrollView {
|
||||
id: galleryScroll
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
|
||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
|
||||
|
||||
// Enable vertical mouse wheel to scroll the horizontal strip by moving contentX
|
||||
WheelHandler {
|
||||
target: galleryScroll.contentItem
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
onWheel: event => {
|
||||
const flick = galleryScroll.contentItem
|
||||
if (!flick)
|
||||
return
|
||||
const delta = event.pixelDelta.x !== 0 || event.pixelDelta.y !== 0 ? (event.pixelDelta.y !== 0 ? event.pixelDelta.y : event.pixelDelta.x) : (event.angleDelta.y !== 0 ? event.angleDelta.y : event.angleDelta.x)
|
||||
// Move opposite of wheel to scroll content to the right for wheel down
|
||||
const step = -delta
|
||||
const maxX = Math.max(0, flick.contentWidth - flick.width)
|
||||
let newX = flick.contentX + step
|
||||
if (newX < 0)
|
||||
newX = 0
|
||||
if (newX > maxX)
|
||||
newX = maxX
|
||||
flick.contentX = newX
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
height: parent.height
|
||||
|
||||
@@ -23,14 +23,13 @@ NPanel {
|
||||
draggable: false
|
||||
|
||||
property int currentStep: 0
|
||||
property int totalSteps: 4
|
||||
property int totalSteps: 5
|
||||
|
||||
// Setup wizard data
|
||||
property string selectedWallpaperDirectory: Settings.defaultWallpapersDirectory
|
||||
property string selectedWallpaper: ""
|
||||
property real selectedScaleRatio: 1.0
|
||||
property string selectedBarPosition: "top"
|
||||
property bool selectedDimDesktop: true
|
||||
|
||||
panelContent: Component {
|
||||
Item {
|
||||
@@ -199,7 +198,6 @@ NPanel {
|
||||
id: step2
|
||||
selectedScaleRatio: root.selectedScaleRatio
|
||||
selectedBarPosition: root.selectedBarPosition
|
||||
selectedDimDesktop: root.selectedDimDesktop
|
||||
onScaleRatioChanged: function (ratio) {
|
||||
root.selectedScaleRatio = ratio
|
||||
root.applyUISettings()
|
||||
@@ -208,13 +206,14 @@ NPanel {
|
||||
root.selectedBarPosition = position
|
||||
root.applyUISettings()
|
||||
}
|
||||
onDimDesktopChanged: function (dim) {
|
||||
root.selectedDimDesktop = dim
|
||||
root.applyUISettings()
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Appearance - Dark mode and color source
|
||||
// Step 3: Dock Setup
|
||||
SetupDockStep {
|
||||
id: stepDock
|
||||
}
|
||||
|
||||
// Step 4: Appearance - Dark mode and color source
|
||||
SetupAppearanceStep {
|
||||
id: step3
|
||||
}
|
||||
@@ -248,6 +247,9 @@ NPanel {
|
||||
}, {
|
||||
"icon": "settings",
|
||||
"label": "Customize"
|
||||
}, {
|
||||
"icon": "device-desktop",
|
||||
"label": "Dock"
|
||||
}, {
|
||||
"icon": "palette",
|
||||
"label": "Appearance"
|
||||
@@ -376,7 +378,6 @@ NPanel {
|
||||
|
||||
Settings.data.general.scaleRatio = selectedScaleRatio
|
||||
Settings.data.bar.position = selectedBarPosition
|
||||
Settings.data.general.dimDesktop = selectedDimDesktop
|
||||
Settings.data.setupCompleted = true
|
||||
|
||||
Settings.saveImmediate()
|
||||
@@ -398,7 +399,6 @@ NPanel {
|
||||
function applyUISettings() {
|
||||
Settings.data.general.scaleRatio = selectedScaleRatio
|
||||
Settings.data.bar.position = selectedBarPosition
|
||||
Settings.data.general.dimDesktop = selectedDimDesktop
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
@@ -407,7 +407,6 @@ NPanel {
|
||||
if (Settings && Settings.data) {
|
||||
selectedScaleRatio = Settings.data.general.scaleRatio
|
||||
selectedBarPosition = Settings.data.bar.position
|
||||
selectedDimDesktop = Settings.data.general.dimDesktop
|
||||
selectedWallpaperDirectory = Settings.data.wallpaper.directory || Settings.defaultWallpapersDirectory
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,9 +292,6 @@ NPanel {
|
||||
}
|
||||
wallpapersList = WallpaperService.getWallpapersList(targetScreen.name)
|
||||
Logger.i("WallpaperPanel", "Got", wallpapersList.length, "wallpapers for screen", targetScreen.name)
|
||||
if (wallpapersList.length > 0) {
|
||||
Logger.d("WallpaperPanel", "First 5 wallpapers:", wallpapersList.slice(0, 5))
|
||||
}
|
||||
|
||||
// Pre-compute basenames once for better performance
|
||||
wallpapersWithNames = wallpapersList.map(function (p) {
|
||||
|
||||
@@ -115,7 +115,14 @@ Singleton {
|
||||
"outputs": [{
|
||||
"path": "~/.config/walker/themes/noctalia/style.css"
|
||||
}],
|
||||
"postProcess": () => `${colorsApplyScript} walker\n`,
|
||||
"strict": true
|
||||
},
|
||||
"code": {
|
||||
"input": "code.json",
|
||||
"outputs": [{
|
||||
"path": "~/.vscode/extensions/hyprluna.hyprluna-theme-1.0.2/themes/hyprluna.json"
|
||||
}]
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ Singleton {
|
||||
"DarkMode": darkMode,
|
||||
"KeepAwake": keepAwakeComponent,
|
||||
"KeyboardLayout": keyboardLayoutComponent,
|
||||
"LockKeys": lockKeysComponent,
|
||||
"MediaMini": mediaMiniComponent,
|
||||
"Microphone": microphoneComponent,
|
||||
"NightLight": nightLightComponent,
|
||||
@@ -52,7 +53,8 @@ Singleton {
|
||||
},
|
||||
"AudioVisualizer": {
|
||||
"allowUserSettings": true,
|
||||
"width": 200
|
||||
"width": 200,
|
||||
"hideWhenIdle": false
|
||||
},
|
||||
"Battery": {
|
||||
"allowUserSettings": true,
|
||||
@@ -97,6 +99,13 @@ Singleton {
|
||||
"allowUserSettings": true,
|
||||
"displayMode": "onhover"
|
||||
},
|
||||
"LockKeys": {
|
||||
"allowUserSettings": true,
|
||||
"indicatorStyle": "large",
|
||||
"showCapsLock": true,
|
||||
"showNumLock": true,
|
||||
"showScrollLock": true
|
||||
},
|
||||
"MediaMini": {
|
||||
"allowUserSettings": true,
|
||||
"hideMode": "hidden",
|
||||
@@ -192,6 +201,9 @@ Singleton {
|
||||
property Component keepAwakeComponent: Component {
|
||||
KeepAwake {}
|
||||
}
|
||||
property Component lockKeysComponent: Component {
|
||||
LockKeys {}
|
||||
}
|
||||
property Component mediaMiniComponent: Component {
|
||||
MediaMini {}
|
||||
}
|
||||
|
||||
@@ -68,16 +68,16 @@ Singleton {
|
||||
function loadFromCache() {
|
||||
if (cacheAdapter.cachedEvents && cacheAdapter.cachedEvents.length > 0) {
|
||||
root.events = cacheAdapter.cachedEvents
|
||||
Logger.i("Calendar", `Loaded ${cacheAdapter.cachedEvents.length} cached event(s)`)
|
||||
Logger.d("Calendar", `Loaded ${cacheAdapter.cachedEvents.length} cached event(s)`)
|
||||
}
|
||||
|
||||
if (cacheAdapter.cachedCalendars && cacheAdapter.cachedCalendars.length > 0) {
|
||||
root.calendars = cacheAdapter.cachedCalendars
|
||||
Logger.i("Calendar", `Loaded ${cacheAdapter.cachedCalendars.length} cached calendar(s)`)
|
||||
Logger.d("Calendar", `Loaded ${cacheAdapter.cachedCalendars.length} cached calendar(s)`)
|
||||
}
|
||||
|
||||
if (cacheAdapter.lastUpdate) {
|
||||
Logger.i("Calendar", `Cache last updated: ${cacheAdapter.lastUpdate}`)
|
||||
Logger.d("Calendar", `Cache last updated: ${cacheAdapter.lastUpdate}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ Singleton {
|
||||
loadEventsProcess.endTime = Math.floor(endDate.getTime() / 1000)
|
||||
loadEventsProcess.running = true
|
||||
|
||||
Logger.i("Calendar", `Loading events (${daysBehind} days behind, ${daysAhead} days ahead): ${startDate.toLocaleDateString()} to ${endDate.toLocaleDateString()}`)
|
||||
Logger.d("Calendar", `Loading events (${daysBehind} days behind, ${daysAhead} days ahead): ${startDate.toLocaleDateString()} to ${endDate.toLocaleDateString()}`)
|
||||
}
|
||||
|
||||
// Helper to format date/time
|
||||
@@ -178,7 +178,7 @@ Singleton {
|
||||
cacheAdapter.cachedCalendars = result
|
||||
saveCache()
|
||||
|
||||
Logger.i("Calendar", `Found ${result.length} calendar(s)`)
|
||||
Logger.d("Calendar", `Found ${result.length} calendar(s)`)
|
||||
|
||||
// Auto-load events after discovering calendars
|
||||
// Only load if we have calendars and no cached events
|
||||
@@ -225,7 +225,7 @@ Singleton {
|
||||
cacheAdapter.lastUpdate = new Date().toISOString()
|
||||
saveCache()
|
||||
|
||||
Logger.i("Calendar", `Loaded ${result.length} event(s)`)
|
||||
Logger.d("Calendar", `Loaded ${result.length} event(s)`)
|
||||
} catch (e) {
|
||||
Logger.d("Calendar", "Failed to parse events: " + e)
|
||||
root.lastError = "Failed to parse events"
|
||||
@@ -233,7 +233,7 @@ Singleton {
|
||||
// Fall back to cached events if available
|
||||
if (cacheAdapter.cachedEvents.length > 0) {
|
||||
root.events = cacheAdapter.cachedEvents
|
||||
Logger.i("Calendar", "Using cached events")
|
||||
Logger.d("Calendar", "Using cached events")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -250,7 +250,7 @@ Singleton {
|
||||
// Fall back to cached events if available
|
||||
if (cacheAdapter.cachedEvents.length > 0) {
|
||||
root.events = cacheAdapter.cachedEvents
|
||||
Logger.i("Calendar", "Using cached events due to error")
|
||||
Logger.d("Calendar", "Using cached events due to error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,31 @@ Singleton {
|
||||
schemeReader.path = filePath
|
||||
}
|
||||
|
||||
function setPredefinedScheme(schemeName) {
|
||||
Logger.i("ColorScheme", "Attempting to set predefined scheme to:", schemeName)
|
||||
|
||||
var resolvedPath = resolveSchemePath(schemeName)
|
||||
var basename = getBasename(schemeName)
|
||||
|
||||
// Check if the scheme actually exists in the loaded schemes list
|
||||
var schemeExists = false
|
||||
for (var i = 0; i < schemes.length; i++) {
|
||||
if (getBasename(schemes[i]) === basename) {
|
||||
schemeExists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (schemeExists) {
|
||||
Settings.data.colorSchemes.predefinedScheme = basename
|
||||
applyScheme(schemeName)
|
||||
ToastService.showNotice("Color Scheme", `Set to ${basename}`)
|
||||
} else {
|
||||
Logger.e("ColorScheme", "Scheme not found:", schemeName)
|
||||
ToastService.showError("Color Scheme", `Scheme '${basename}' not found!`)
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: findProcess
|
||||
running: false
|
||||
@@ -162,7 +187,7 @@ Singleton {
|
||||
// Check if any templates are enabled
|
||||
function hasEnabledTemplates() {
|
||||
return Settings.data.templates.gtk || Settings.data.templates.qt || Settings.data.templates.kitty || Settings.data.templates.ghostty || Settings.data.templates.foot || Settings.data.templates.fuzzel || Settings.data.templates.discord || Settings.data.templates.discord_vesktop || Settings.data.templates.discord_webcord
|
||||
|| Settings.data.templates.discord_armcord || Settings.data.templates.discord_equibop || Settings.data.templates.discord_lightcord || Settings.data.templates.discord_dorion || Settings.data.templates.pywalfox
|
||||
|| Settings.data.templates.discord_armcord || Settings.data.templates.discord_equibop || Settings.data.templates.discord_lightcord || Settings.data.templates.discord_dorion || Settings.data.templates.pywalfox || Settings.data.templates.vicinae || Settings.data.templates.walker
|
||||
}
|
||||
|
||||
// Writer to colors.json using a JsonAdapter for safety
|
||||
|
||||
@@ -126,6 +126,13 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "colorScheme"
|
||||
function set(schemeName: string) {
|
||||
ColorSchemeService.setPredefinedScheme(schemeName)
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "volume"
|
||||
function increase() {
|
||||
|
||||
85
Services/LockKeysService.qml
Normal file
85
Services/LockKeysService.qml
Normal file
@@ -0,0 +1,85 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property bool capsLockOn: false
|
||||
property bool numLockOn: false
|
||||
property bool scrollLockOn: false
|
||||
|
||||
signal capsLockChanged(bool active)
|
||||
signal numLockChanged(bool active)
|
||||
signal scrollLockChanged(bool active)
|
||||
|
||||
Process {
|
||||
id: stateCheckProcess
|
||||
|
||||
property string checkCommand: " \
|
||||
caps=0; cat /sys/class/leds/input*::capslock/brightness 2>/dev/null | grep -q 1 && caps=1; echo \"caps:${caps}\"; \
|
||||
num=0; cat /sys/class/leds/input*::numlock/brightness 2>/dev/null | grep -q 1 && num=1; echo \"num:${num}\"; \
|
||||
scroll=0; cat /sys/class/leds/input*::scrolllock/brightness 2>/dev/null | grep -q 1 && scroll=1; echo \"scroll:${scroll}\"; \
|
||||
"
|
||||
command: ["sh", "-c", stateCheckProcess.checkCommand]
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
var lines = this.text.trim().split('\n')
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var parts = lines[i].split(':')
|
||||
if (parts.length === 2) {
|
||||
var key = parts[0]
|
||||
var newState = (parts[1] === '1')
|
||||
|
||||
if (key === "caps") {
|
||||
if (root.capsLockOn !== newState) {
|
||||
root.capsLockOn = newState
|
||||
root.capsLockChanged(newState)
|
||||
Logger.i("LockKeysService", "Caps Lock:", capsLockOn)
|
||||
}
|
||||
} else if (key === "num") {
|
||||
if (root.numLockOn !== newState) {
|
||||
root.numLockOn = newState
|
||||
root.numLockChanged(newState)
|
||||
Logger.i("LockKeysService", "Num Lock:", numLockOn)
|
||||
}
|
||||
} else if (key === "scroll") {
|
||||
if (root.scrollLockOn !== newState) {
|
||||
root.scrollLockOn = newState
|
||||
root.scrollLockChanged(newState)
|
||||
Logger.i("LockKeysService", "Scroll Lock:", scrollLockOn)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (this.text.trim().length > 0)
|
||||
Logger.i("LockKeysService", "Error running state check:", this.text.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: pollTimer
|
||||
interval: 200
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (!stateCheckProcess.running) {
|
||||
stateCheckProcess.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Logger.i("LockKeysService", "Service started, performing initial state check.")
|
||||
stateCheckProcess.running = true
|
||||
}
|
||||
}
|
||||
@@ -225,6 +225,13 @@ Singleton {
|
||||
}],
|
||||
"input": "vesktop.css",
|
||||
"requiresThemesFolder": true
|
||||
}, {
|
||||
"name": "code",
|
||||
"templates": [{
|
||||
"version": "code",
|
||||
"output": "~/.vscode/extensions/hyprluna.hyprluna-theme-1.0.2/themes/hyprluna.json"
|
||||
}],
|
||||
"input": "code.json"
|
||||
}]
|
||||
|
||||
// --------------------------------
|
||||
|
||||
@@ -171,6 +171,21 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
property bool autoSwitchingPaused: false
|
||||
|
||||
function switchToPlayer(index) {
|
||||
let availablePlayers = getAvailablePlayers()
|
||||
if (index >= 0 && index < availablePlayers.length) {
|
||||
let newPlayer = availablePlayers[index]
|
||||
if (newPlayer !== currentPlayer) {
|
||||
currentPlayer = newPlayer
|
||||
selectedPlayerIndex = index
|
||||
currentPosition = currentPlayer ? currentPlayer.position : 0
|
||||
Logger.d("Media", "Manually switched to player " + currentPlayer.identity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Switch to the most recently active player
|
||||
function updateCurrentPlayer() {
|
||||
let newPlayer = findActivePlayer()
|
||||
@@ -289,6 +304,9 @@ Singleton {
|
||||
repeat: true
|
||||
running: true
|
||||
onTriggered: {
|
||||
Logger.d("MediaService", "playerStateMonitor triggered. autoSwitchingPaused: " + root.autoSwitchingPaused)
|
||||
if (autoSwitchingPaused)
|
||||
return
|
||||
// Only update if we don't have a playing player or if current player is paused
|
||||
if (!currentPlayer || !currentPlayer.isPlaying || currentPlayer.playbackState !== MprisPlaybackState.Playing) {
|
||||
updateCurrentPlayer()
|
||||
|
||||
@@ -21,6 +21,7 @@ Singleton {
|
||||
property bool gpuScreenRecorderAvailable: false
|
||||
property bool wlsunsetAvailable: false
|
||||
property bool app2unitAvailable: false
|
||||
property bool codeAvailable: false
|
||||
|
||||
// Discord client auto-detection
|
||||
property var availableDiscordClients: []
|
||||
@@ -99,11 +100,12 @@ Singleton {
|
||||
"ghosttyAvailable": ["which", "ghostty"],
|
||||
"footAvailable": ["which", "foot"],
|
||||
"fuzzelAvailable": ["which", "fuzzel"],
|
||||
"vicinaeAvailable": ["which", "vicinae"],
|
||||
"vicinaeAvailable": ["sh", "-c", "command -v vicinae >/dev/null 2>&1 || (IFS=:; find $PATH -maxdepth 1 -iname 'vicinae*.appimage' -type f -executable 2>/dev/null | grep -q .)"],
|
||||
"walkerAvailable": ["which", "walker"],
|
||||
"app2unitAvailable": ["which", "app2unit"],
|
||||
"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"]
|
||||
"wlsunsetAvailable": ["which", "wlsunset"],
|
||||
"codeAvailable": ["which", "code"]
|
||||
})
|
||||
|
||||
// Internal tracking
|
||||
|
||||
@@ -8,7 +8,7 @@ Singleton {
|
||||
id: root
|
||||
|
||||
// Public properties
|
||||
property string baseVersion: "2.20.0"
|
||||
property string baseVersion: "2.21.1"
|
||||
property bool isDevelopment: false
|
||||
|
||||
property string currentVersion: `v${!isDevelopment ? baseVersion : baseVersion + "-dev"}`
|
||||
|
||||
@@ -372,12 +372,20 @@ Singleton {
|
||||
}
|
||||
} else {
|
||||
// Use FolderListModel (non-recursive)
|
||||
// Force refresh by toggling each scanner's currentDirectory
|
||||
for (var i = 0; i < wallpaperScanners.count; i++) {
|
||||
var scanner = wallpaperScanners.objectAt(i)
|
||||
if (scanner) {
|
||||
var currentFolder = scanner.folder
|
||||
scanner.folder = ""
|
||||
scanner.folder = currentFolder
|
||||
// Capture scanner in closure
|
||||
(function (s) {
|
||||
var directory = root.getMonitorDirectory(s.screenName)
|
||||
// Trigger a change by setting to /tmp (always exists) then back to the actual directory
|
||||
// Note: This causes harmless Qt warnings (QTBUG-52262) but is necessary to force FolderListModel to re-scan
|
||||
s.currentDirectory = "/tmp"
|
||||
Qt.callLater(function () {
|
||||
s.currentDirectory = directory
|
||||
})
|
||||
})(scanner)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,6 +403,15 @@ Singleton {
|
||||
return
|
||||
}
|
||||
|
||||
// Cancel any existing scan for this screen
|
||||
if (recursiveProcesses[screenName]) {
|
||||
Logger.d("Wallpaper", "Cancelling existing scan for", screenName)
|
||||
recursiveProcesses[screenName].running = false
|
||||
recursiveProcesses[screenName].destroy()
|
||||
delete recursiveProcesses[screenName]
|
||||
scanningCount--
|
||||
}
|
||||
|
||||
scanningCount++
|
||||
Logger.i("Wallpaper", "Starting recursive scan for", screenName, "in", directory)
|
||||
|
||||
@@ -434,7 +451,7 @@ Singleton {
|
||||
Logger.i("Wallpaper", "Recursive scan completed for", screenName, "found", files.length, "files")
|
||||
wallpaperListChanged(screenName, files.length)
|
||||
} else {
|
||||
Logger.e("Wallpaper", "Recursive scan failed for", screenName, "exit code:", exitCode, "stderr:", processObject.stderr.text)
|
||||
Logger.w("Wallpaper", "Recursive scan failed for", screenName, "exit code:", exitCode, "(directory might not exist)")
|
||||
wallpaperLists[screenName] = []
|
||||
wallpaperListChanged(screenName, 0)
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@ import qs.Services
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
implicitWidth: childrenRect.width
|
||||
implicitHeight: childrenRect.height
|
||||
|
||||
color: Color.mSurfaceVariant
|
||||
radius: Style.radiusM
|
||||
border.color: Color.mOutline
|
||||
|
||||
@@ -5,16 +5,16 @@ import qs.Commons
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property date sampleDate: new Date() // Dec 25, 2023, 2:30:45.123 PM
|
||||
|
||||
signal tokenClicked(string token)
|
||||
|
||||
color: Color.mSurface
|
||||
border.color: Color.mOutline
|
||||
border.width: Style.borderS
|
||||
radius: Style.radiusM
|
||||
|
||||
property date sampleDate: new Date() // Dec 25, 2023, 2:30:45.123 PM
|
||||
|
||||
// Signal emitted when a token is clicked
|
||||
signal tokenClicked(string token)
|
||||
|
||||
ColumnLayout {
|
||||
id: column
|
||||
anchors.fill: parent
|
||||
@@ -312,7 +312,7 @@ Rectangle {
|
||||
|
||||
NText {
|
||||
anchors.centerIn: parent
|
||||
text: Qt.locale().toString(root.sampleDate, modelData.token)
|
||||
text: I18n.locale.toString(root.sampleDate, modelData.token)
|
||||
color: tokenMouseArea.containsMouse ? Color.mOnPrimary : Color.mSurfaceVariant
|
||||
pointSize: Style.fontSizeS
|
||||
|
||||
|
||||
@@ -9,9 +9,16 @@ Loader {
|
||||
|
||||
property ShellScreen screen
|
||||
|
||||
readonly property real opacityThreshold: 0.33
|
||||
property bool attachedToBar: (Settings.data.ui.panelsAttachedToBar && Settings.data.bar.backgroundOpacity > opacityThreshold)
|
||||
property bool useOverlay: Settings.data.ui.panelsOverlayLayer
|
||||
|
||||
property Component panelContent: null
|
||||
|
||||
// Panel size properties. Can be set directly on NPanel, or dynamically by the content.
|
||||
// For dynamic sizing, the content should expose contentPreferredWidth, contentPreferredHeight,
|
||||
// contentPreferredWidthRatio, or contentPreferredHeightRatio properties.
|
||||
// Changes to these properties will be animated smoothly (except during panel dragging).
|
||||
property real preferredWidth: 700
|
||||
property real preferredHeight: 900
|
||||
property real preferredWidthRatio
|
||||
@@ -39,10 +46,20 @@ Loader {
|
||||
property bool backgroundClickEnabled: true
|
||||
|
||||
// Animation properties
|
||||
readonly property real originalScale: 0.0
|
||||
property real scaleValue: originalScale
|
||||
property real panelBackgroundOpacity: 0
|
||||
property real panelContentOpacity: 0
|
||||
property real dimmingOpacity: 0
|
||||
|
||||
readonly property string barPosition: Settings.data.bar.position
|
||||
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real verticalBarWidth: Style.barHeight
|
||||
|
||||
// Effective anchor properties - combines explicit anchors with implicit anchoring from useButtonPosition
|
||||
readonly property bool effectivePanelAnchorTop: panelAnchorTop || (useButtonPosition && barPosition === "top")
|
||||
readonly property bool effectivePanelAnchorBottom: panelAnchorBottom || (useButtonPosition && barPosition === "bottom")
|
||||
readonly property bool effectivePanelAnchorLeft: panelAnchorLeft || (useButtonPosition && barPosition === "left")
|
||||
readonly property bool effectivePanelAnchorRight: panelAnchorRight || (useButtonPosition && barPosition === "right")
|
||||
|
||||
signal opened
|
||||
signal closed
|
||||
|
||||
@@ -97,7 +114,8 @@ Loader {
|
||||
// -----------------------------------------
|
||||
function close() {
|
||||
dimmingOpacity = 0
|
||||
scaleValue = originalScale
|
||||
panelBackgroundOpacity = 0
|
||||
panelContentOpacity = 0
|
||||
root.closed()
|
||||
active = false
|
||||
useButtonPosition = false
|
||||
@@ -132,10 +150,7 @@ Loader {
|
||||
PanelWindow {
|
||||
id: panelWindow
|
||||
|
||||
readonly property string barPosition: Settings.data.bar.position
|
||||
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property bool barIsVisible: (screen !== null) && (Settings.data.bar.monitors.includes(screen.name) || (Settings.data.bar.monitors.length === 0))
|
||||
readonly property real verticalBarWidth: Style.barHeight
|
||||
|
||||
Component.onCompleted: {
|
||||
Logger.d("NPanel", "Opened", root.objectName, "on", screen.name)
|
||||
@@ -155,8 +170,7 @@ Loader {
|
||||
}
|
||||
}
|
||||
|
||||
visible: true
|
||||
color: Settings.data.general.dimDesktop ? Qt.alpha(Color.mShadow, dimmingOpacity) : Color.transparent
|
||||
color: Color.transparent
|
||||
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.namespace: "noctalia-panel"
|
||||
@@ -195,12 +209,77 @@ Loader {
|
||||
}
|
||||
|
||||
// The actual panel's content
|
||||
Rectangle {
|
||||
NShapedRectangle {
|
||||
id: panelBackground
|
||||
color: panelBackgroundColor
|
||||
radius: Style.radiusL
|
||||
border.color: panelBorderColor
|
||||
border.width: Style.borderS
|
||||
|
||||
backgroundColor: (attachedToBar && (topLeftInverted || topRightInverted || bottomLeftInverted || bottomRightInverted)) ? Qt.alpha(panelBackgroundColor, Settings.data.bar.backgroundOpacity) : panelBackgroundColor
|
||||
|
||||
topLeftRadius: Style.radiusL
|
||||
topRightRadius: Style.radiusL
|
||||
bottomLeftRadius: Style.radiusL
|
||||
bottomRightRadius: Style.radiusL
|
||||
|
||||
// Set inverted corners based on panel anchors and bar position
|
||||
|
||||
// Top-left corner
|
||||
topLeftInverted: {
|
||||
if (!attachedToBar)
|
||||
return false
|
||||
|
||||
// Inverted if panel is anchored to top edge (bar is at top)
|
||||
if (effectivePanelAnchorTop)
|
||||
return true
|
||||
// Or if panel is anchored to left edge (bar is at left)
|
||||
if (effectivePanelAnchorLeft)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
topLeftInvertedDirection: effectivePanelAnchorTop ? "horizontal" : "vertical"
|
||||
|
||||
// Top-right corner
|
||||
topRightInverted: {
|
||||
if (!attachedToBar)
|
||||
return false
|
||||
|
||||
// Inverted if panel is anchored to top edge (bar is at top)
|
||||
if (effectivePanelAnchorTop)
|
||||
return true
|
||||
// Or if panel is anchored to right edge (bar is at right)
|
||||
if (effectivePanelAnchorRight)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
topRightInvertedDirection: effectivePanelAnchorTop ? "horizontal" : "vertical"
|
||||
|
||||
// Bottom-left corner
|
||||
bottomLeftInverted: {
|
||||
if (!attachedToBar)
|
||||
return false
|
||||
|
||||
// Inverted if panel is anchored to bottom edge (bar is at bottom)
|
||||
if (effectivePanelAnchorBottom)
|
||||
return true
|
||||
// Or if panel is anchored to left edge (bar is at left)
|
||||
if (effectivePanelAnchorLeft)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
bottomLeftInvertedDirection: effectivePanelAnchorBottom ? "horizontal" : "vertical"
|
||||
|
||||
// Bottom-right corner
|
||||
bottomRightInverted: {
|
||||
if (!attachedToBar)
|
||||
return false
|
||||
|
||||
// Inverted if panel is anchored to bottom edge (bar is at bottom)
|
||||
if (effectivePanelAnchorBottom)
|
||||
return true
|
||||
// Or if panel is anchored to right edge (bar is at right)
|
||||
if (effectivePanelAnchorRight)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
bottomRightInvertedDirection: effectivePanelAnchorBottom ? "horizontal" : "vertical"
|
||||
|
||||
// Dragging support
|
||||
property bool draggable: root.draggable
|
||||
@@ -209,30 +288,47 @@ Loader {
|
||||
property real manualY: 0
|
||||
width: {
|
||||
var w
|
||||
if (preferredWidthRatio !== undefined) {
|
||||
w = Math.round(Math.max(screen?.width * preferredWidthRatio, preferredWidth))
|
||||
if (root.preferredWidthRatio !== undefined) {
|
||||
w = Math.round(Math.max(screen?.width * root.preferredWidthRatio, root.preferredWidth))
|
||||
} else {
|
||||
w = preferredWidth
|
||||
w = root.preferredWidth
|
||||
}
|
||||
// Clamp width so it is never bigger than the screen
|
||||
return Math.min(w, screen?.width - Style.marginL * 2)
|
||||
}
|
||||
height: {
|
||||
var h
|
||||
if (preferredHeightRatio !== undefined) {
|
||||
h = Math.round(Math.max(screen?.height * preferredHeightRatio, preferredHeight))
|
||||
if (root.preferredHeightRatio !== undefined) {
|
||||
h = Math.round(Math.max(screen?.height * root.preferredHeightRatio, root.preferredHeight))
|
||||
} else {
|
||||
h = preferredHeight
|
||||
h = root.preferredHeight
|
||||
}
|
||||
|
||||
// Clamp width so it is never bigger than the screen
|
||||
// Clamp height so it is never bigger than the screen
|
||||
return Math.min(h, screen?.height - Style.barHeight - Style.marginL * 2)
|
||||
}
|
||||
|
||||
scale: root.scaleValue
|
||||
opacity: root.panelBackgroundOpacity
|
||||
x: isDragged ? manualX : calculatedX
|
||||
y: isDragged ? manualY : calculatedY
|
||||
|
||||
// Animate width and height changes smoothly
|
||||
Behavior on width {
|
||||
enabled: !panelBackground.isDragged
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
enabled: !panelBackground.isDragged
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// Does not account for corners are they are negligible and helps keep the code clean.
|
||||
// ---------------------------------------------
|
||||
@@ -240,11 +336,12 @@ Loader {
|
||||
if (!barIsVisible) {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch (barPosition) {
|
||||
case "top":
|
||||
return (Style.barHeight + Style.marginS) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0)
|
||||
return (Style.barHeight + (attachedToBar ? 0 : Style.marginS)) + (Settings.data.bar.floating ? Math.round(Settings.data.bar.marginVertical * Style.marginXL) : 0)
|
||||
default:
|
||||
return Style.marginS
|
||||
return attachedToBar ? 0 : Style.marginS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,9 +351,9 @@ Loader {
|
||||
}
|
||||
switch (barPosition) {
|
||||
case "bottom":
|
||||
return (Style.barHeight + Style.marginS) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0)
|
||||
return (Style.barHeight + (attachedToBar ? 0 : Style.marginS)) + (Settings.data.bar.floating ? Math.round(Settings.data.bar.marginVertical * Style.marginXL) : 0)
|
||||
default:
|
||||
return Style.marginS
|
||||
return attachedToBar ? 0 : Style.marginS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,9 +363,9 @@ Loader {
|
||||
}
|
||||
switch (barPosition) {
|
||||
case "left":
|
||||
return (Style.barHeight + Style.marginS) + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0)
|
||||
return (Style.barHeight + (attachedToBar ? 0 : Style.marginS)) + (Settings.data.bar.floating ? Math.round(Settings.data.bar.marginHorizontal * Style.marginXL) : 0)
|
||||
default:
|
||||
return Style.marginS
|
||||
return attachedToBar ? 0 : Style.marginS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,9 +375,9 @@ Loader {
|
||||
}
|
||||
switch (barPosition) {
|
||||
case "right":
|
||||
return (Style.barHeight + Style.marginS) + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0)
|
||||
return (Style.barHeight + (attachedToBar ? 0 : Style.marginS)) + (Settings.data.bar.floating ? Math.round(Settings.data.bar.marginHorizontal * Style.marginXL) : 0)
|
||||
default:
|
||||
return Style.marginS
|
||||
return attachedToBar ? 0 : Style.marginS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +397,7 @@ Loader {
|
||||
}
|
||||
|
||||
// No fixed anchoring
|
||||
if (isVertical) {
|
||||
if (barIsVertical) {
|
||||
// Vertical bar
|
||||
if (barPosition === "right") {
|
||||
// To the left of the right bar
|
||||
@@ -317,6 +414,11 @@ Loader {
|
||||
// Keep panel within screen bounds
|
||||
var maxX = panelWindow.width - panelBackground.width - marginRight
|
||||
var minX = marginLeft
|
||||
|
||||
if (Settings.data.bar.floating) {
|
||||
maxX -= Settings.data.bar.marginHorizontal * Style.marginXL * 10
|
||||
minX += Settings.data.bar.marginHorizontal * Style.marginXL * 10
|
||||
}
|
||||
return Math.round(Math.max(minX, Math.min(targetX, maxX)))
|
||||
} else {
|
||||
// Fallback to center horizontally
|
||||
@@ -341,7 +443,7 @@ Loader {
|
||||
}
|
||||
|
||||
// No fixed anchoring
|
||||
if (isVertical) {
|
||||
if (barIsVertical) {
|
||||
// Vertical bar
|
||||
if (useButtonPosition) {
|
||||
// Position panel relative to button
|
||||
@@ -349,6 +451,12 @@ Loader {
|
||||
// Keep panel within screen bounds
|
||||
var maxY = panelWindow.height - panelBackground.height - marginBottom
|
||||
var minY = marginTop
|
||||
|
||||
if (Settings.data.bar.floating) {
|
||||
maxY -= Settings.data.bar.marginHorizontal * Style.marginXL * 10
|
||||
minY += Settings.data.bar.marginHorizontal * Style.marginXL * 10
|
||||
}
|
||||
|
||||
return Math.round(Math.max(minY, Math.min(targetY, maxY)))
|
||||
} else {
|
||||
// Fallback to center vertically
|
||||
@@ -368,7 +476,28 @@ Loader {
|
||||
|
||||
// Animate in when component is completed
|
||||
Component.onCompleted: {
|
||||
root.scaleValue = 1.0
|
||||
// Start invisible
|
||||
// Use a timer to delay the animation start, allowing QML to properly set up initial state
|
||||
fadeInTimer.start()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: fadeInTimer
|
||||
interval: 1
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
// Fade in background
|
||||
root.panelBackgroundOpacity = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
// Timer to fade in content after slide animation completes
|
||||
Timer {
|
||||
id: contentFadeInTimer
|
||||
interval: Style.animationFast
|
||||
repeat: false
|
||||
running: true
|
||||
onTriggered: root.panelContentOpacity = 1.0
|
||||
}
|
||||
|
||||
// Reset drag position when panel closes
|
||||
@@ -384,17 +513,10 @@ Loader {
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
// Animation behaviors
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutExpo
|
||||
}
|
||||
}
|
||||
|
||||
// Animation behavior
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
@@ -403,6 +525,33 @@ Loader {
|
||||
id: panelContentLoader
|
||||
anchors.fill: parent
|
||||
sourceComponent: root.panelContent
|
||||
opacity: root.panelContentOpacity
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
|
||||
// Allow content to dynamically resize the panel
|
||||
onItemChanged: {
|
||||
if (item) {
|
||||
// Bind to content's preferredWidth/Height if they exist
|
||||
if (item.hasOwnProperty('contentPreferredWidth')) {
|
||||
root.preferredWidth = Qt.binding(() => item.contentPreferredWidth)
|
||||
}
|
||||
if (item.hasOwnProperty('contentPreferredHeight')) {
|
||||
root.preferredHeight = Qt.binding(() => item.contentPreferredHeight)
|
||||
}
|
||||
if (item.hasOwnProperty('contentPreferredWidthRatio')) {
|
||||
root.preferredWidthRatio = Qt.binding(() => item.contentPreferredWidthRatio)
|
||||
}
|
||||
if (item.hasOwnProperty('contentPreferredHeightRatio')) {
|
||||
root.preferredHeightRatio = Qt.binding(() => item.contentPreferredHeightRatio)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle drag move on the whole panel area
|
||||
@@ -459,9 +608,9 @@ Loader {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 0
|
||||
color: Color.transparent
|
||||
border.color: Color.mPrimary
|
||||
border.width: Style.borderL
|
||||
radius: parent.radius
|
||||
border.color: Color.mTertiary
|
||||
border.width: Style.borderM
|
||||
radius: Style.radiusL
|
||||
visible: panelBackground.isDragged && dragHandler.active
|
||||
opacity: 0.8
|
||||
z: 3000
|
||||
@@ -471,9 +620,9 @@ Loader {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 0
|
||||
color: Color.transparent
|
||||
border.color: Color.mPrimary
|
||||
border.color: Color.mTertiary
|
||||
border.width: Style.borderS
|
||||
radius: parent.radius
|
||||
radius: Style.radiusL
|
||||
opacity: 0.3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,12 +236,9 @@ RowLayout {
|
||||
Repeater {
|
||||
model: typeof badgeLocations !== 'undefined' ? badgeLocations : []
|
||||
|
||||
delegate: NBox {
|
||||
delegate: Item {
|
||||
width: Style.baseWidgetSize * 0.7
|
||||
height: Style.baseWidgetSize * 0.7
|
||||
color: "transparent"
|
||||
radius: Style.radiusS
|
||||
border.width: 0
|
||||
|
||||
NText {
|
||||
anchors.centerIn: parent
|
||||
|
||||
@@ -233,7 +233,7 @@ NBox {
|
||||
acceptedButtons: Qt.RightButton
|
||||
z: -1 // Below the buttons but above background
|
||||
|
||||
onClicked: mouse => {
|
||||
onPressed: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
// Check if click is not on the buttons area
|
||||
const localX = mouse.x
|
||||
|
||||
189
Widgets/NShapedRectangle.qml
Normal file
189
Widgets/NShapedRectangle.qml
Normal file
@@ -0,0 +1,189 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Corner radius properties
|
||||
property real topLeftRadius: 0
|
||||
property real topRightRadius: 0
|
||||
property real bottomLeftRadius: 0
|
||||
property real bottomRightRadius: 0
|
||||
|
||||
// Inverted corner properties (concave instead of convex)
|
||||
property bool topLeftInverted: false
|
||||
property bool topRightInverted: false
|
||||
property bool bottomLeftInverted: false
|
||||
property bool bottomRightInverted: false
|
||||
|
||||
// Direction for inverted corners: "horizontal" or "vertical"
|
||||
// horizontal: curves left/right (extends beyond left/right edges)
|
||||
// vertical: curves up/down (extends beyond top/bottom edges)
|
||||
property string topLeftInvertedDirection: "horizontal" // default: curves left
|
||||
property string topRightInvertedDirection: "horizontal" // default: curves right
|
||||
property string bottomLeftInvertedDirection: "horizontal" // default: curves left
|
||||
property string bottomRightInvertedDirection: "horizontal" // default: curves right
|
||||
|
||||
// Background color
|
||||
property color backgroundColor: "white"
|
||||
|
||||
// Check if any corner is inverted
|
||||
readonly property bool hasInvertedCorners: topLeftInverted || topRightInverted || bottomLeftInverted || bottomRightInverted
|
||||
|
||||
// Calculate padding needed for inverted corners based on their direction
|
||||
readonly property real topPadding: Math.max((topLeftInverted && topLeftInvertedDirection === "vertical") ? topLeftRadius : 0, (topRightInverted && topRightInvertedDirection === "vertical") ? topRightRadius : 0)
|
||||
readonly property real bottomPadding: Math.max((bottomLeftInverted && bottomLeftInvertedDirection === "vertical") ? bottomLeftRadius : 0, (bottomRightInverted && bottomRightInvertedDirection === "vertical") ? bottomRightRadius : 0)
|
||||
readonly property real leftPadding: Math.max((topLeftInverted && topLeftInvertedDirection === "horizontal") ? topLeftRadius : 0, (bottomLeftInverted && bottomLeftInvertedDirection === "horizontal") ? bottomLeftRadius : 0)
|
||||
readonly property real rightPadding: Math.max((topRightInverted && topRightInvertedDirection === "horizontal") ? topRightRadius : 0, (bottomRightInverted && bottomRightInvertedDirection === "horizontal") ? bottomRightRadius : 0)
|
||||
|
||||
// Simple rectangle for non-inverted corners (better performance)
|
||||
Rectangle {
|
||||
id: simpleBackground
|
||||
anchors.fill: parent
|
||||
color: root.backgroundColor
|
||||
radius: topLeftRadius // Use topLeftRadius as default
|
||||
border.width: Style.borderS
|
||||
border.color: Color.mOutline
|
||||
visible: !root.hasInvertedCorners
|
||||
|
||||
topLeftRadius: root.topLeftRadius
|
||||
topRightRadius: root.topRightRadius
|
||||
bottomLeftRadius: root.bottomLeftRadius
|
||||
bottomRightRadius: root.bottomRightRadius
|
||||
}
|
||||
|
||||
// Background with custom corners (for inverted corners)
|
||||
Canvas {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: -root.topPadding
|
||||
anchors.bottomMargin: -root.bottomPadding
|
||||
anchors.leftMargin: -root.leftPadding
|
||||
anchors.rightMargin: -root.rightPadding
|
||||
visible: root.hasInvertedCorners
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d")
|
||||
ctx.reset()
|
||||
|
||||
// Adjust coordinates to account for inverted corner padding
|
||||
var x = root.leftPadding
|
||||
var y = root.topPadding
|
||||
var w = width - root.leftPadding - root.rightPadding
|
||||
var h = height - root.topPadding - root.bottomPadding
|
||||
|
||||
ctx.fillStyle = root.backgroundColor
|
||||
ctx.beginPath()
|
||||
|
||||
// Start from top left
|
||||
if (topLeftInverted) {
|
||||
if (topLeftInvertedDirection === "vertical") {
|
||||
ctx.moveTo(x, y)
|
||||
} else {
|
||||
ctx.moveTo(x + topLeftRadius, y)
|
||||
}
|
||||
} else {
|
||||
ctx.moveTo(x + topLeftRadius, y)
|
||||
}
|
||||
|
||||
// Top edge and top right corner
|
||||
if (topRightInverted) {
|
||||
if (topRightInvertedDirection === "horizontal") {
|
||||
// Curves to the right
|
||||
ctx.lineTo(x + w, y)
|
||||
ctx.lineTo(x + w + topRightRadius, y)
|
||||
ctx.quadraticCurveTo(x + w, y, x + w, y + topRightRadius)
|
||||
} else {
|
||||
// Curves upward
|
||||
ctx.lineTo(x + w, y)
|
||||
ctx.lineTo(x + w, y - topRightRadius)
|
||||
ctx.quadraticCurveTo(x + w, y, x + w - topRightRadius, y)
|
||||
ctx.lineTo(x + w, y)
|
||||
ctx.lineTo(x + w, y + topRightRadius)
|
||||
}
|
||||
} else {
|
||||
ctx.lineTo(x + w - topRightRadius, y)
|
||||
ctx.arcTo(x + w, y, x + w, y + topRightRadius, topRightRadius)
|
||||
}
|
||||
|
||||
// Right edge and bottom right corner
|
||||
if (bottomRightInverted) {
|
||||
if (bottomRightInvertedDirection === "horizontal") {
|
||||
// Curves to the right
|
||||
ctx.lineTo(x + w, y + h - bottomRightRadius)
|
||||
ctx.quadraticCurveTo(x + w, y + h, x + w + bottomRightRadius, y + h)
|
||||
ctx.lineTo(x + w, y + h)
|
||||
ctx.lineTo(x + w - bottomRightRadius, y + h)
|
||||
} else {
|
||||
// Curves downward
|
||||
ctx.lineTo(x + w, y + h)
|
||||
ctx.lineTo(x + w, y + h + bottomRightRadius)
|
||||
ctx.quadraticCurveTo(x + w, y + h, x + w - bottomRightRadius, y + h)
|
||||
}
|
||||
} else {
|
||||
ctx.lineTo(x + w, y + h - bottomRightRadius)
|
||||
ctx.arcTo(x + w, y + h, x + w - bottomRightRadius, y + h, bottomRightRadius)
|
||||
}
|
||||
|
||||
// Bottom edge and bottom left corner
|
||||
if (bottomLeftInverted) {
|
||||
if (bottomLeftInvertedDirection === "horizontal") {
|
||||
// Curves to the left
|
||||
ctx.lineTo(x + bottomLeftRadius, y + h)
|
||||
ctx.lineTo(x - bottomLeftRadius, y + h)
|
||||
ctx.quadraticCurveTo(x, y + h, x, y + h - bottomLeftRadius)
|
||||
} else {
|
||||
// Curves downward
|
||||
ctx.lineTo(x, y + h)
|
||||
ctx.lineTo(x, y + h + bottomLeftRadius)
|
||||
ctx.quadraticCurveTo(x, y + h, x + bottomLeftRadius, y + h)
|
||||
ctx.lineTo(x, y + h)
|
||||
ctx.lineTo(x, y + h - bottomLeftRadius)
|
||||
}
|
||||
} else {
|
||||
ctx.lineTo(x + bottomLeftRadius, y + h)
|
||||
ctx.arcTo(x, y + h, x, y + h - bottomLeftRadius, bottomLeftRadius)
|
||||
}
|
||||
|
||||
// Left edge and back to top left corner
|
||||
if (topLeftInverted) {
|
||||
if (topLeftInvertedDirection === "horizontal") {
|
||||
// Curves to the left
|
||||
ctx.lineTo(x, y + topLeftRadius)
|
||||
ctx.quadraticCurveTo(x, y, x - topLeftRadius, y)
|
||||
ctx.lineTo(x, y)
|
||||
ctx.lineTo(x + topLeftRadius, y)
|
||||
} else {
|
||||
// Curves upward
|
||||
ctx.lineTo(x, y + topLeftRadius)
|
||||
ctx.lineTo(x, y)
|
||||
ctx.lineTo(x, y - topLeftRadius)
|
||||
ctx.quadraticCurveTo(x, y, x + topLeftRadius, y)
|
||||
}
|
||||
} else {
|
||||
ctx.lineTo(x, y + topLeftRadius)
|
||||
ctx.arcTo(x, y, x + topLeftRadius, y, topLeftRadius)
|
||||
}
|
||||
|
||||
ctx.closePath()
|
||||
ctx.fill()
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger repaint when properties change
|
||||
onTopLeftRadiusChanged: background.requestPaint()
|
||||
onTopRightRadiusChanged: background.requestPaint()
|
||||
onBottomLeftRadiusChanged: background.requestPaint()
|
||||
onBottomRightRadiusChanged: background.requestPaint()
|
||||
onTopLeftInvertedChanged: background.requestPaint()
|
||||
onTopRightInvertedChanged: background.requestPaint()
|
||||
onBottomLeftInvertedChanged: background.requestPaint()
|
||||
onBottomRightInvertedChanged: background.requestPaint()
|
||||
onTopLeftInvertedDirectionChanged: background.requestPaint()
|
||||
onTopRightInvertedDirectionChanged: background.requestPaint()
|
||||
onBottomLeftInvertedDirectionChanged: background.requestPaint()
|
||||
onBottomRightInvertedDirectionChanged: background.requestPaint()
|
||||
onBackgroundColorChanged: background.requestPaint()
|
||||
onWidthChanged: background.requestPaint()
|
||||
onHeightChanged: background.requestPaint()
|
||||
}
|
||||
@@ -69,6 +69,7 @@ RowLayout {
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
enabled: root.enabled
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
|
||||
14
flake.lock
generated
14
flake.lock
generated
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1756125398,
|
||||
"narHash": "sha256-XexyKZpf46cMiO5Vbj+dWSAXOnr285GHsMch8FBoHbc=",
|
||||
"lastModified": 1761672384,
|
||||
"narHash": "sha256-o9KF3DJL7g7iYMZq9SWgfS1BFlNbsm6xplRjVlOCkXI=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3b9f00d7a7bf68acd4c4abb9d43695afb04e03a5",
|
||||
"rev": "08dacfca559e1d7da38f3cf05f1f45ee9bfd213c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -23,11 +23,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1753595452,
|
||||
"narHash": "sha256-vqkSDvh7hWhPvNjMjEDV4KbSCv2jyl2Arh73ZXe274k=",
|
||||
"lastModified": 1761821581,
|
||||
"narHash": "sha256-nLuc6jA7z+H/6bHPEBSOYPbz7RtvNCZiTKmYItJuBmM=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "a5431dd02dc23d9ef1680e67777fed00fe5f7cda",
|
||||
"revCount": 665,
|
||||
"rev": "db1777c20b936a86528c1095cbcb1ebd92801402",
|
||||
"revCount": 699,
|
||||
"type": "git",
|
||||
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user