Merge branch 'main' into battery-charging-treshold

This commit is contained in:
Damian D'Souza
2025-10-15 02:11:14 +02:00
committed by GitHub
212 changed files with 8630 additions and 4172 deletions
+1
View File
@@ -0,0 +1 @@
ko_fi: lysec
-13
View File
@@ -1,13 +0,0 @@
{
"languages": {
"QML": {
"format_on_save": "on",
"formatter": {
"external": {
"command": "qmlfmt",
"arguments": ["-e", "-b", "360", "-t", "2", "-i", "2"]
}
}
}
}
}
@@ -1,6 +1,3 @@
[cursor]
color=1f2430 ffcc66
[colors]
foreground=cccac2
background=1f2430
@@ -21,4 +18,5 @@ bright5=dfbfff
bright6=95e6cb
bright7=ffffff
selection-foreground=1f2430
selection-background=409fff
selection-background=409fff
cursor=1f2430 ffcc66
@@ -1,6 +1,3 @@
[cursor]
color=f8f9fa ffaa33
[colors]
foreground=5c6166
background=f8f9fa
@@ -22,3 +19,4 @@ bright6=4cbf99
bright7=d1d1d1
selection-foreground=f8f9fa
selection-background=035bd6
cursor=f8f9fa ffaa33
@@ -1,6 +1,3 @@
[cursor]
color=1e1e2e f5e0dc
[colors]
foreground=cdd6f4
background=1e1e2e
@@ -22,3 +19,4 @@ bright6=6bd7ca
bright7=bac2de
selection-foreground=cdd6f4
selection-background=585b70
cursor=1e1e2e f5e0dc
@@ -1,6 +1,3 @@
[cursor]
color=303446 f2d5cf
[colors]
foreground=c6d0f5
background=303446
@@ -22,3 +19,4 @@ bright6=5abfb5
bright7=b5bfe2
selection-foreground=c6d0f5
selection-background=626880
cursor=303446 f2d5cf
@@ -1,6 +1,3 @@
[cursor]
color=282a36 f8f8f2
[colors]
foreground=f8f8f2
background=282a36
@@ -21,4 +18,5 @@ bright5=ff92df
bright6=a4ffff
bright7=ffffff
selection-foreground=ffffff
selection-background=44475a
selection-background=44475a
cursor=282a36 f8f8f2
@@ -1,6 +1,3 @@
[cursor]
color=ffffff 282a36
[colors]
foreground=282a36
background=ffffff
@@ -22,3 +19,4 @@ bright6=a4ffff
bright7=000000
selection-foreground=ffffff
selection-background=6272a4
cursor=ffffff 282a36
@@ -1,6 +1,3 @@
[cursor]
color=4c3743 e69875
[colors]
foreground=d3c6aa
background=1e2326
@@ -21,4 +18,5 @@ bright5=df69ba
bright6=35a77c
bright7=fffbef
selection-foreground=d3c6aa
selection-background=4c3743
selection-background=4c3743
cursor=4c3743 e69875
@@ -1,6 +1,3 @@
[cursor]
color=eaedc8 f57d26
[colors]
foreground=5c6a72
background=efebd4
@@ -21,4 +18,5 @@ bright5=df69ba
bright6=35a77c
bright7=fffbef
selection-foreground=5c6a72
selection-background=eaedc8
selection-background=eaedc8
cursor=eaedc8 f57d26
@@ -1,7 +1,4 @@
[cursor]
color=282828 ebdbb2
[colors]
foreground=ebdbb2
background=282828
@@ -22,4 +19,5 @@ bright5=d3869b
bright6=8ec07c
bright7=ebdbb2
selection-foreground=ebdbb2
selection-background=665c54
selection-background=665c54
cursor=282828 ebdbb2
@@ -1,7 +1,4 @@
[cursor]
color=625e5c 3c3836
[colors]
foreground=3c3836
background=fbf1c7
@@ -22,4 +19,5 @@ bright5=8f3f71
bright6=427b58
bright7=3c3836
selection-foreground=fbf1c7
selection-background=3c3836
selection-background=3c3836
cursor=625e5c 3c3836
@@ -1,6 +1,3 @@
[cursor]
color=1f1f28 e6e0c2
[colors]
foreground=ddd8bb
background=1f1f28
@@ -21,4 +18,5 @@ bright5=a98fd2
bright6=7bc2df
bright7=a8a48d
selection-foreground=ddd8bb
selection-background=49473e
selection-background=49473e
cursor=1f1f28 e6e0c2
@@ -1,6 +1,3 @@
[cursor]
color=f2ecbc 43436c
[colors]
foreground=545464
background=f2ecbc
@@ -22,3 +19,4 @@ bright6=5e857a
bright7=43436c
selection-foreground=f2ecbc
selection-background=c9cbd1
cursor=f2ecbc 43436c
@@ -1,6 +1,3 @@
[cursor]
color=111111 aaaaaa
[colors]
foreground=828282
background=111111
@@ -22,3 +19,4 @@ bright6=cccccc
bright7=ffffff
selection-foreground=111111
selection-background=828282
cursor=111111 aaaaaa
@@ -1,6 +1,3 @@
[cursor]
color=d4d4d4 555555
[colors]
foreground=696969
background=d4d4d4
@@ -22,3 +19,4 @@ bright6=333333
bright7=000000
selection-foreground=d4d4d4
selection-background=696969
cursor=d4d4d4 555555
@@ -1,6 +1,3 @@
[cursor]
color=070722 fff59b
[colors]
foreground=f3edf7
background=070722
@@ -22,3 +19,4 @@ bright6=9BFECE
bright7=ffffff
selection-foreground=070722
selection-background=f3edf7
cursor=070722 fff59b
@@ -1,6 +1,3 @@
[cursor]
color=e6e8fa 5d65f5
[colors]
foreground=4b55c8
background=e6e8fa
@@ -22,3 +19,4 @@ bright6=0e0e43
bright7=0e0e43
selection-foreground=e6e8fa
selection-background=4b55c8
cursor=e6e8fa 5d65f5
@@ -1,6 +1,3 @@
[cursor]
color=1c1822 c7a1d8
[colors]
foreground=e9e4f0
background=1c1822
@@ -22,3 +19,4 @@ bright6=e0b7c9
bright7=ffffff
selection-foreground=1c1822
selection-background=e9e4f0
cursor=1c1822 c7a1d8
@@ -1,6 +1,3 @@
[cursor]
color=f5f1fa 9b59ba
[colors]
foreground=1c1822
background=f5f1fa
@@ -22,3 +19,4 @@ bright6=c17093
bright7=1c1822
selection-foreground=f5f1fa
selection-background=1c1822
cursor=f5f1fa 9b59ba
@@ -1,7 +1,4 @@
[cursor]
color=282828 eceff4
[colors]
foreground=d8dee9
background=2e3440
@@ -23,3 +20,4 @@ bright6=8fbcbb
bright7=eceff4
selection-foreground=4c566a
selection-background=eceff4
cursor=282828 eceff4
@@ -1,7 +1,4 @@
[cursor]
color=3b4252 7bb3c3
[colors]
foreground=414858
background=e5e9f0
@@ -23,3 +20,4 @@ bright6=82afae
bright7=eceff4
selection-foreground=4c556a
selection-background=d8dee9
cursor=3b4252 7bb3c3
@@ -1,7 +1,4 @@
[cursor]
color=191724 e0def4
[colors]
foreground=e0def4
background=191724
@@ -23,3 +20,4 @@ bright6=ebbcba
bright7=e0def4
selection-foreground=e0def4
selection-background=403d52
cursor=191724 e0def4
@@ -1,7 +1,4 @@
[cursor]
color=faf4ed 575279
[colors]
foreground=575279
background=faf4ed
@@ -23,3 +20,4 @@ bright6=d7827e
bright7=575279
selection-foreground=575279
selection-background=dfdad9
cursor=faf4ed 575279
@@ -1,6 +1,3 @@
[cursor]
color=073642 839496
[colors]
foreground=839496
background=002b36
@@ -21,4 +18,5 @@ bright5=6c71c4
bright6=93a1a1
bright7=fdf6e3
selection-foreground=93a1a1
selection-background=073642
selection-background=073642
cursor=073642 839496
@@ -1,7 +1,4 @@
[cursor]
color=eee8d5 657b83
[colors]
foreground=657b83
background=fdf6e3
@@ -22,4 +19,5 @@ bright5=6c71c4
bright6=93a1a1
bright7=fdf6e3
selection-foreground=586e75
selection-background=eee8d5
selection-background=eee8d5
cursor=eee8d5 657b83
@@ -1,6 +1,3 @@
[cursor]
color=1a1b26 c0caf5
[colors]
foreground=c0caf5
background=1a1b26
@@ -21,4 +18,5 @@ bright5=bb9af7
bright6=7dcfff
bright7=c0caf5
selection-foreground=c0caf5
selection-background=283457
selection-background=283457
cursor=1a1b26 c0caf5
@@ -1,6 +1,3 @@
[cursor]
color=e1e2e7 3760bf
[colors]
foreground=3760bf
background=e1e2e7
@@ -21,4 +18,5 @@ bright5=9854f1
bright6=007197
bright7=3760bf
selection-foreground=3760bf
selection-background=99a7df
selection-background=99a7df
cursor=e1e2e7 3760bf
+146
View File
@@ -0,0 +1,146 @@
[KDE]
contrast=4
[General]
ColorScheme=Matugen
Name=noctalia
[ColorEffects:Disabled]
Color={{colors.surface_dim.default.hex}}
ColorAmount=0
ColorEffect=0
ContrastAmount=0.65
ContrastEffect=1
IntensityAmount=0.1
IntensityEffect=2
[ColorEffects:Inactive]
ChangeSelectionColor=true
Color={{colors.surface_variant.default.hex}}
ColorAmount=0.025
ColorEffect=2
ContrastAmount=0.1
ContrastEffect=2
Enable=false
IntensityAmount=0
IntensityEffect=0
[Colors:Button]
BackgroundAlternate={{colors.surface_container_low.default.hex}}
BackgroundNormal={{colors.surface_container_high.default.hex}}
DecorationFocus={{colors.primary.default.hex}}
DecorationHover={{colors.primary.default.hex}}
ForegroundActive={{colors.primary.default.hex}}
ForegroundInactive={{colors.on_surface_variant.default.hex}}
ForegroundLink={{colors.secondary.default.hex}}
ForegroundNegative={{colors.error.default.hex}}
ForegroundNeutral={{colors.tertiary.default.hex}}
ForegroundNormal={{colors.on_surface.default.hex}}
ForegroundPositive={{colors.tertiary_fixed.default.hex}}
ForegroundVisited={{colors.on_secondary_container.default.hex}}
[Colors:Complementary]
BackgroundAlternate={{colors.surface_container_low.default.hex}}
BackgroundNormal={{colors.surface.default.hex}}
DecorationFocus={{colors.primary.default.hex}}
DecorationHover={{colors.primary.default.hex}}
ForegroundActive={{colors.primary.default.hex}}
ForegroundInactive={{colors.on_surface_variant.default.hex}}
ForegroundLink={{colors.secondary.default.hex}}
ForegroundNegative={{colors.error.default.hex}}
ForegroundNeutral={{colors.tertiary.default.hex}}
ForegroundNormal={{colors.on_primary_container.default.hex}}
ForegroundPositive={{colors.tertiary_fixed.default.hex}}
ForegroundVisited={{colors.on_secondary_container.default.hex}}
[Colors:Header]
BackgroundAlternate={{colors.surface.default.hex}}
BackgroundNormal={{colors.surface_container.default.hex}}
DecorationFocus={{colors.primary.default.hex}}
DecorationHover={{colors.primary.default.hex}}
ForegroundActive={{colors.primary.default.hex}}
ForegroundInactive={{colors.on_surface_variant.default.hex}}
ForegroundLink={{colors.secondary.default.hex}}
ForegroundNegative={{colors.error.default.hex}}
ForegroundNeutral={{colors.tertiary.default.hex}}
ForegroundNormal={{colors.on_surface.default.hex}}
ForegroundPositive={{colors.tertiary_fixed.default.hex}}
ForegroundVisited={{colors.on_secondary_container.default.hex}}
[Colors:Header][Inactive]
BackgroundAlternate={{colors.surface_container.default.hex}}
BackgroundNormal={{colors.surface.default.hex}}
DecorationFocus={{colors.primary.default.hex}}
DecorationHover={{colors.primary.default.hex}}
ForegroundActive={{colors.primary.default.hex}}
ForegroundInactive={{colors.on_surface_variant.default.hex}}
ForegroundLink={{colors.secondary.default.hex}}
ForegroundNegative={{colors.error.default.hex}}
ForegroundNeutral={{colors.tertiary.default.hex}}
ForegroundNormal={{colors.on_surface.default.hex}}
ForegroundPositive={{colors.tertiary_fixed.default.hex}}
ForegroundVisited={{colors.on_secondary_container.default.hex}}
[Colors:Selection]
BackgroundAlternate={{colors.surface_container_low.default.hex}}
BackgroundNormal={{colors.primary.default.hex}}
DecorationFocus={{colors.primary.default.hex}}
DecorationHover={{colors.primary.default.hex}}
ForegroundActive={{colors.on_primary.default.hex}}
ForegroundInactive={{colors.on_surface_variant.default.hex}}
ForegroundLink={{colors.secondary_fixed.default.hex}}
ForegroundNegative={{colors.error_container.default.hex}}
ForegroundNeutral={{colors.tertiary_fixed_dim.default.hex}}
ForegroundNormal={{colors.on_primary.default.hex}}
ForegroundPositive={{colors.tertiary_container.default.hex}}
ForegroundVisited={{colors.on_secondary_container.default.hex}}
[Colors:Tooltip]
BackgroundAlternate={{colors.surface.default.hex}}
BackgroundNormal={{colors.surface_container.default.hex}}
DecorationFocus={{colors.primary.default.hex}}
DecorationHover={{colors.primary.default.hex}}
ForegroundActive={{colors.primary.default.hex}}
ForegroundInactive={{colors.on_surface_variant.default.hex}}
ForegroundLink={{colors.secondary.default.hex}}
ForegroundNegative={{colors.error.default.hex}}
ForegroundNeutral={{colors.tertiary.default.hex}}
ForegroundNormal={{colors.on_background.default.hex}}
ForegroundPositive={{colors.tertiary_fixed.default.hex}}
ForegroundVisited={{colors.on_secondary_container.default.hex}}
[Colors:View]
BackgroundAlternate={{colors.surface_container.default.hex}}
BackgroundNormal={{colors.background.default.hex}}
DecorationFocus={{colors.on_primary_container.default.hex}}
DecorationHover={{colors.on_primary.default.hex}}
ForegroundActive={{colors.primary.default.hex}}
ForegroundInactive={{colors.on_surface_variant.default.hex}}
ForegroundLink={{colors.secondary.default.hex}}
ForegroundNegative={{colors.error.default.hex}}
ForegroundNeutral={{colors.tertiary.default.hex}}
ForegroundNormal={{colors.on_background.default.hex}}
ForegroundPositive={{colors.tertiary_fixed.default.hex}}
ForegroundVisited={{colors.on_secondary_container.default.hex}}
[Colors:Window]
BackgroundAlternate={{colors.primary_container.default.hex}}
BackgroundNormal={{colors.surface_container.default.hex}}
DecorationFocus={{colors.primary.default.hex}}
DecorationHover={{colors.primary.default.hex}}
ForegroundActive={{colors.primary.default.hex}}
ForegroundInactive={{colors.on_surface_variant.default.hex}}
ForegroundLink={{colors.secondary.default.hex}}
ForegroundNegative={{colors.error.default.hex}}
ForegroundNeutral={{colors.tertiary.default.hex}}
ForegroundNormal={{colors.on_background.default.hex}}
ForegroundPositive={{colors.tertiary_fixed.default.hex}}
ForegroundVisited={{colors.on_secondary_container.default.hex}}
[WM]
activeBackground={{colors.primary_container.default.hex}}
activeBlend={{colors.on_primary_container.default.hex}}
activeForeground={{colors.on_primary_container.default.hex}}
inactiveBackground={{colors.surface.default.hex}}
inactiveBlend={{colors.on_surface_variant.default.hex}}
inactiveForeground={{colors.on_surface_variant.default.hex}}
+204 -59
View File
@@ -13,32 +13,6 @@
},
"select-avatar": "Avatar-Bild auswählen"
},
"ui": {
"section": {
"label": "Benutzeroberfläche",
"description": "Passen Sie das Aussehen, die Haptik und das Verhalten der Oberfläche an."
},
"tooltips": {
"label": "Tooltips anzeigen",
"description": "Tooltips in der gesamten Benutzeroberfläche aktivieren oder deaktivieren."
},
"dim-desktop": {
"label": "Desktop abdunkeln",
"description": "Desktop abdunkeln, wenn Panels oder Menüs geöffnet sind."
},
"border-radius": {
"label": "Eckenradius",
"description": "Steuert die Rundung der Ecken von Fenstern, Buttons und anderen Elementen."
},
"animation-speed": {
"label": "Animationsgeschwindigkeit",
"description": "Globale Animationsgeschwindigkeit anpassen."
},
"animation-disable": {
"label": "UI-Animationen deaktivieren",
"description": "Alle Animationen für eine schnellere, reaktionsschnellere Erfahrung deaktivieren."
}
},
"screen-corners": {
"section": {
"label": "Bildschirmecken",
@@ -54,7 +28,8 @@
},
"radius": {
"label": "Bildschirmecken-Radius",
"description": "Rundung der Bildschirmecken anpassen."
"description": "Rundung der Bildschirmecken anpassen.",
"reset": "Eckenradius des Bildschirms zurücksetzen"
}
},
"fonts": {
@@ -83,16 +58,6 @@
}
},
"reset-scaling": "Skalierung zurücksetzen"
},
"control-center": {
"section": {
"label": "Kontrollzentrum",
"description": "Konfigurieren Sie die Positionierung und das Verhalten des Kontrollzentrum-Panels."
},
"position": {
"label": "Position",
"description": "Wählen Sie, wo das Kontrollzentrum-Panel beim Öffnen erscheint."
}
}
},
"audio": {
@@ -179,11 +144,9 @@
"monitors": {
"section": {
"label": "Monitor-spezifische Einstellungen",
"description": "Skalierung und Helligkeit für jeden Bildschirm anpassen."
"description": "Helligkeitseinstellungen für jedes Display anpassen."
},
"scale": "Skalierung",
"brightness": "Helligkeit",
"reset-scaling": "Skalierung zurücksetzen",
"brightness-step": {
"label": "Helligkeits-Schrittgröße",
"description": "Schrittgröße für Helligkeitsänderungen anpassen (Mausrad und Tastenkombinationen)."
@@ -259,17 +222,20 @@
"widgets": {
"section": {
"label": "Widget-Positionierung",
"description": "Widgets per Drag & Drop innerhalb jeder Sektion neu anordnen oder Add/Remove-Buttons zum Verwalten verwenden."
"description": "Widgets per Drag & Drop neu anordnen. Abzeichen zeigen die Verwendung an: [L]inks, [M]itte, [R]echts."
}
},
"monitors": {
"section": {
"label": "Monitor-Anzeige",
"description": "Statusleiste auf bestimmten Monitoren anzeigen. Standard ist alle, wenn keine ausgewählt sind."
},
"only-same-output": {
"label": "Nur Apps vom gleichen Bildschirm",
"description": "Zeige nur Apps vom dem Bildschirm an, wo sich das Dock befindet."
}
},
"tray": {
"blacklist": {
"label": "Ausschlussliste",
"description": "Füge Ausschlussregeln für die Tray-Symbolleiste hinzu, unterstützt Platzhalter (*).",
"placeholder": "z.B., nm-applet, Fcitx*"
}
}
},
@@ -294,6 +260,10 @@
"floating-distance": {
"label": "Dock-Schwebeabstand",
"description": "Schwebeabstand vom Bildschirmrand anpassen."
},
"colorize-icons": {
"label": "Symbole einfärben",
"description": "Theme-Farben auf Dock-App-Symbole anwenden (nur nicht fokussierte Apps)."
}
},
"monitors": {
@@ -406,6 +376,10 @@
"label": "Bildschirmanzeige aktivieren",
"description": "Lautstärke- und Helligkeitsänderungen in Echtzeit anzeigen."
},
"always-on-top": {
"label": "Immer im Vordergrund",
"description": "Bildschirmanzeige über Vollbildfenstern und anderen Ebenen anzeigen."
},
"location": {
"label": "Position",
"description": "Wo Bildschirmanzeigen erscheinen."
@@ -533,6 +507,9 @@
},
"qt": {
"description": "Schreibt {filepath}"
},
"kcolorscheme": {
"description": "Schreibt {filepath}"
}
},
"terminal": {
@@ -558,9 +535,9 @@
"description": "Schreibt {filepath} und lädt neu",
"description-missing": "Erfordert fuzzel Starter"
},
"vesktop": {
"description": "Schreibt {filepath}",
"description-missing": "Erfordert vesktop Discord-Client"
"discord": {
"description": "Schreibt {filepath} für {client}",
"description-missing": "Kein Discord-Client erkannt. Installieren Sie vesktop, webcord, armcord, equibop, lightcord oder dorion."
},
"pywalfox": {
"description": "Schreibt {filepath} und führt pywalfox update aus",
@@ -707,7 +684,8 @@
"description": "Ein Dankeschön an unseren {count} <b>großartigen</b> Mitwirkenden!",
"description_plural": "Ein Dankeschön an unsere {count} <b>großartigen</b> Mitwirkenden!"
}
}
},
"support": "Unterstützen Sie uns"
},
"hooks": {
"title": "Hooks",
@@ -741,6 +719,69 @@
"description": "• Hintergrundbild-Hook: $1 = Hintergrundbild-Pfad, $2 = Bildschirmname\n• Theme-Wechsel-Hook: $1 = true/false (Dunkelmodus-Status)"
}
}
},
"control-center": {
"position": {
"description": "Wählen Sie aus, wo das Kontrollzentrum angezeigt wird, wenn es geöffnet wird.",
"label": "Position"
},
"section": {
"description": "Konfigurieren Sie die Positionierung und das Verhalten des Control Center-Panels.",
"label": "Aussehen"
},
"title": "Kontrollzentrum",
"cards": {
"section": {
"description": "Passen Sie an, welche Steuerelemente im Kontrollzentrum angezeigt werden und in welcher Reihenfolge.",
"label": "Karten"
}
},
"shortcuts": {
"section": {
"description": "Konfigurieren und verwalten Sie die Verknüpfungs-Widgets.",
"label": "Widgets für Kurzbefehle"
},
"sectionLeft": "Links",
"sectionRight": "Richtig"
}
},
"user-interface": {
"animation-disable": {
"description": "Deaktivieren Sie alle Animationen für eine schnellere und reaktionsfreudigere Erfahrung.",
"label": "UI-Animationen deaktivieren"
},
"animation-speed": {
"description": "Globale Animationsgeschwindigkeit anpassen.",
"label": "Animationsgeschwindigkeit",
"reset": "Animationsgeschwindigkeit zurücksetzen"
},
"border-radius": {
"description": "Steuert die Eckenrundung von Fenstern, Schaltflächen und anderen Elementen.",
"label": "Eckenradius",
"reset": "Rahmenradius zurücksetzen"
},
"compact-lockscreen": {
"description": "Zeige nur die Login-Eingabe und Systemsteuerung, blende Wetter- und Medien-Widgets aus.",
"label": "Kompakter Sperrbildschirm"
},
"dim-desktop": {
"description": "Den Desktop abdunkeln, wenn Bedienfelder oder Menüs geöffnet sind.",
"label": "Dim Desktop"
},
"scaling": {
"description": "Ändert die Größe der allgemeinen Benutzeroberfläche, mit Ausnahme der Leiste.",
"label": "Oberflächenskalierung",
"reset-scaling": "Schnittstellenskalierung zurücksetzen"
},
"section": {
"description": "Passen Sie das Aussehen, die Haptik und das Verhalten der Benutzeroberfläche an.",
"label": "Aussehen"
},
"title": "Benutzeroberfläche",
"tooltips": {
"description": "Tooltips in der gesamten Benutzeroberfläche aktivieren oder deaktivieren.",
"label": "Tooltips anzeigen"
}
}
},
"general": {
@@ -766,7 +807,11 @@
},
"file-picker": {
"select-folder": "Ordner auswählen",
"select-file": "Datei auswählen"
"select-file": "Datei auswählen",
"cancel": "Abbrechen",
"search-placeholder": "Dateien und Ordner suchen...",
"select-current": "Aktuelle auswählen",
"title": "Dateiauswahl"
},
"datetime-tokens": {
"common": {
@@ -857,9 +902,9 @@
"search-placeholder": "Widgets suchen..."
},
"active-window": {
"auto-hide": {
"label": "Automatisch ausblenden",
"description": "Widget automatisch ausblenden, wenn kein Fenster aktiv ist."
"hide-mode": {
"label": "Ausblendmodus",
"description": "Steuert das Verhalten des Widgets, wenn kein Fenster aktiv ist."
},
"show-app-icon": {
"label": "App-Symbol anzeigen",
@@ -872,6 +917,10 @@
"width": {
"description": "Steuert die horizontale Größe des Widgets.",
"label": "Widget-Breite"
},
"colorize-icons": {
"label": "Symbole einfärben",
"description": "Theme-Farben auf das aktive Fenster-Symbol anwenden."
}
},
"system-monitor": {
@@ -1002,9 +1051,9 @@
}
},
"media-mini": {
"auto-hide": {
"label": "Automatisch ausblenden",
"description": "Widget automatisch ausblenden, wenn keine Medien abgespielt werden."
"hide-mode": {
"label": "Ausblendmodus",
"description": "Steuert das Verhalten des Widgets, wenn keine Medien abgespielt werden."
},
"show-album-art": {
"label": "Albumcover anzeigen",
@@ -1065,6 +1114,16 @@
"only-same-output": {
"label": "Nur vom gleichen Bildschirm",
"description": "Zeige nur Apps vom dem Bildschirm an, wo sich die Taskbar befindet."
},
"colorize-icons": {
"label": "Symbole einfärben",
"description": "Theme-Farben auf Taskbar-Symbole anwenden."
}
},
"tray": {
"colorize-icons": {
"label": "Symbole einfärben",
"description": "Theme-Farben auf Tray-Symbole anwenden."
}
}
}
@@ -1234,7 +1293,8 @@
"density": {
"compact": "Kompakt",
"default": "Standard",
"comfortable": "Bequem"
"comfortable": "Bequem",
"mini": "Mini"
}
},
"launcher": {
@@ -1259,6 +1319,11 @@
"bottom_right": "Unten rechts",
"bottom_center": "Unten mittig",
"top_center": "Oben mittig"
},
"quickSettingsStyle": {
"modern": "Modern",
"classic": "Klassisch",
"compact": "Kompakt"
}
},
"osd": {
@@ -1318,6 +1383,11 @@
"microphone-input": "Mikrofon-Eingabe",
"both": "System-Ausgabe + Mikrofon-Eingabe"
}
},
"hide-modes": {
"hidden": "Ausblenden, wenn leer",
"transparent": "Transparent, wenn leer",
"visible": "Immer sichtbar"
}
},
"session-menu": {
@@ -1355,9 +1425,9 @@
"calculator-error": "Fehler"
},
"system": {
"uptime": "System-Laufzeit: {uptime}",
"uptime": "Laufzeit: {uptime}",
"welcome-back": "Willkommen zurück,",
"monitor-description": "{model} ({width}x{height})",
"monitor-description": "{model} ({width}x{height} @ {scale}x)",
"scaling-percentage": "{percentage}%",
"location-display": "{name} ({coordinates})",
"signal-strength": "{signal}%",
@@ -1398,6 +1468,78 @@
"restart": "Neu starten",
"suspend": "Ruhezustand"
},
"quickSettings": {
"notifications": {
"label": {
"enabled": "Benachrichtigungen",
"disabled": "Nicht stören"
},
"tooltip": {
"action": "Linksklick: Benachrichtigungsverlauf öffnen\nRechtsklick: Nicht stören umschalten"
}
},
"screenRecorder": {
"label": {
"recording": "Stopp",
"stopped": "Aufnehmen"
},
"tooltip": {
"action": "Klicken zum Starten/Stoppen der Bildschirmaufnahme"
}
},
"powerProfile": {
"label": {
"unavailable": "Energieprofil"
},
"tooltip": {
"action": "Klicken zum Wechseln des Energieprofils"
}
},
"wifi": {
"label": {
"ethernet": "Ethernet",
"wifi": "Wi-Fi",
"disconnected": "Wi-Fi getrennt"
},
"tooltip": {
"action": "Klicken zum Verwalten der Wi-Fi-Verbindungen"
}
},
"bluetooth": {
"label": {
"enabled": "Bluetooth",
"disabled": "Bluetooth"
},
"tooltip": {
"action": "Klicken zum Verwalten der Bluetooth-Geräte"
}
},
"nightLight": {
"label": {
"enabled": "Nachtlicht",
"forced": "Nachtlicht",
"disabled": "Nachtlicht"
},
"tooltip": {
"action": "Klicken zum Wechseln des Nachtlicht-Modus\nRechtsklick: Einstellungen öffnen"
}
},
"wallpaperSelector": {
"label": "Hintergrundbild",
"tooltip": {
"action": "Linksklick: Hintergrundbildauswahl öffnen\nRechtsklick: Zufälliges Hintergrundbild setzen"
}
},
"keepAwake": {
"label": {
"enabled": "Wach halten",
"disabled": "Wach halten"
},
"tooltip": {
"action": "Klicken zum Umschalten des Wach-halten-Modus"
}
}
},
"toast": {
"night-light": {
"enabled": "Aktiviert",
@@ -1445,6 +1587,9 @@
"enabled": "Aktiviert",
"disabled": "Deaktiviert"
},
"kofi": {
"opened": "Ko-fi-Seite in Ihrem Browser geöffnet"
},
"do-not-disturb": {
"enabled": "'Nicht stören' aktiviert",
"disabled": "'Nicht stören' deaktiviert",
+204 -54
View File
@@ -13,32 +13,6 @@
},
"select-avatar": "Select avatar image"
},
"ui": {
"section": {
"label": "User interface",
"description": "Customize the look, feel, and behavior of the interface."
},
"tooltips": {
"label": "Show tooltips",
"description": "Enable or disable tooltips throughout the interface."
},
"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."
},
"animation-speed": {
"label": "Animation speed",
"description": "Adjust global animation speed."
},
"animation-disable": {
"label": "Disable UI Animations",
"description": "Disable all animations for a faster, more responsive experience."
}
},
"screen-corners": {
"section": {
"label": "Screen corners",
@@ -54,7 +28,8 @@
},
"radius": {
"label": "Screen corners radius",
"description": "Adjust the rounded corners of the screen."
"description": "Adjust the rounded corners of the screen.",
"reset": "Reset screen corners radius"
}
},
"fonts": {
@@ -83,17 +58,8 @@
"description": "Increase or decrease the size of the monospaced text."
}
}
},
"control-center": {
"section": {
"label": "Control Center",
"description": "Configure the Control Center panel positioning and behavior."
},
"position": {
"label": "Position",
"description": "Choose where the Control Center panel appears when opened."
}
}
},
"audio": {
"title": "Audio",
@@ -179,11 +145,9 @@
"monitors": {
"section": {
"label": "Per-monitor settings",
"description": "Adjust scaling and brightness for each display."
"description": "Adjust settings brightness for each display."
},
"scale": "Scale",
"brightness": "Brightness",
"reset-scaling": "Reset scaling",
"brightness-step": {
"label": "Brightness step size",
"description": "Adjust the step size for brightness changes (scroll wheel and keyboard shortcuts)."
@@ -259,7 +223,7 @@
"widgets": {
"section": {
"label": "Widgets positioning",
"description": "Drag and drop widgets to reorder them within each section, or use the add/remove buttons to manage widgets."
"description": "Drag and drop widgets to reorder them. Badges indicate usage: [L]eft, [C]enter, [R]ight."
}
},
"monitors": {
@@ -267,6 +231,13 @@
"label": "Monitors display",
"description": "Show bar on specific monitors. Defaults to all if none are chosen."
}
},
"tray": {
"blacklist": {
"label": "Blacklist",
"description": "Add tray exclusion rules, supports wildcards (*).",
"placeholder": "e.g., nm-applet, Fcitx*"
}
}
},
"dock": {
@@ -290,6 +261,10 @@
"floating-distance": {
"label": "Dock floating distance",
"description": "Adjust the floating distance from the screen edge."
},
"colorize-icons": {
"label": "Colorize Icons",
"description": "Apply theme colors to dock app icons (non-focused apps only)."
}
},
"monitors": {
@@ -402,6 +377,10 @@
"label": "Enable on screen display",
"description": "Show volume and brightness changes in real-time."
},
"always-on-top": {
"label": "Always on top",
"description": "Display OSD above fullscreen windows and other layers."
},
"location": {
"label": "Location",
"description": "Where on-screen displays appear."
@@ -533,6 +512,9 @@
},
"qt": {
"description": "Write {filepath}"
},
"kcolorscheme": {
"description": "Write {filepath}"
}
},
"terminal": {
@@ -558,9 +540,9 @@
"description": "Write {filepath} and reload",
"description-missing": "Requires {app} to be installed"
},
"vesktop": {
"description": "Write {filepath}",
"description-missing": "Requires {app} to be installed"
"discord": {
"description": "Write {filepath} for {client}",
"description-missing": "No Discord client detected. Install vesktop, webcord, armcord, equibop, lightcord, or dorion."
},
"pywalfox": {
"description": "Write {filepath} and run pywalfox update",
@@ -703,7 +685,8 @@
"description": "Shout-out to our {count} <b>awesome</b> contributor!",
"description_plural": "Shout-out to our {count} <b>awesome</b> contributors!"
}
}
},
"support": "Support us"
},
"hooks": {
"title": "Hooks",
@@ -737,6 +720,69 @@
"description": "• Wallpaper Hook: $1 = wallpaper path, $2 = screen name\n• Theme Toggle Hook: $1 = true/false (dark mode state)"
}
}
},
"control-center": {
"title": "Control Center",
"section": {
"label": "Appearance",
"description": "Configure the Control Center panel positioning and behavior."
},
"position": {
"label": "Position",
"description": "Choose where the Control Center panel appears when opened."
},
"cards": {
"section": {
"label": "Cards",
"description": "Customize which controls appear in the Control Center and in what order."
}
},
"shortcuts": {
"section": {
"label": "Shortcuts widgets",
"description": "Configure and manage the shortcuts widgets."
},
"sectionLeft": "Left",
"sectionRight": "Right"
}
},
"user-interface": {
"title": "User interface",
"section": {
"label": "Appearance",
"description": "Customize the look, feel, and behavior of the interface."
},
"tooltips": {
"label": "Show tooltips",
"description": "Enable or disable tooltips throughout the interface."
},
"scaling": {
"label": "Interface scaling",
"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."
},
"compact-lockscreen": {
"label": "Compact lock screen",
"description": "Show only the login input and system controls, hiding weather and media widgets."
},
"border-radius": {
"label": "Border radius",
"description": "Controls the corner roundness of windows, buttons, and other elements.",
"reset": "Reset border radius"
},
"animation-speed": {
"label": "Animation speed",
"description": "Adjust global animation speed.",
"reset": "Reset animation speed"
},
"animation-disable": {
"label": "Disable UI Animations",
"description": "Disable all animations for a faster, more responsive experience."
}
}
},
"widgets": {
@@ -744,8 +790,12 @@
"placeholder": "Placeholder"
},
"file-picker": {
"title": "File Picker",
"select-folder": "Select Folder",
"select-file": "Select File"
"select-file": "Select File",
"search-placeholder": "Search files and folders...",
"select-current": "Select Current",
"cancel": "Cancel"
},
"datetime-tokens": {
"common": {
@@ -836,9 +886,9 @@
"search-placeholder": "Search widget..."
},
"active-window": {
"auto-hide": {
"label": "Hide automatically",
"description": "Automatically hide the widget when no window is active."
"hide-mode": {
"label": "Hiding mode",
"description": "Controls how the widget behaves when no window is active."
},
"show-app-icon": {
"label": "Show app icon",
@@ -851,6 +901,10 @@
"width": {
"label": "Widget Width",
"description": "Controls the horizontal size of the widget."
},
"colorize-icons": {
"label": "Colorize Icons",
"description": "Apply theme colors to active window icon."
}
},
"system-monitor": {
@@ -981,9 +1035,9 @@
}
},
"media-mini": {
"auto-hide": {
"label": "Hide automatically",
"description": "Automatically hide the widget when no media is playing."
"hide-mode": {
"label": "Hiding mode",
"description": "Controls how the widget behaves when no media is playing."
},
"show-album-art": {
"label": "Show album art",
@@ -1044,6 +1098,16 @@
"only-same-output": {
"label": "Only from same output",
"description": "Show only apps from the output where the bar is located."
},
"colorize-icons": {
"label": "Colorize Icons",
"description": "Apply theme colors to taskbar icons."
}
},
"tray": {
"colorize-icons": {
"label": "Colorize Icons",
"description": "Apply theme colors to tray icons."
}
}
}
@@ -1211,6 +1275,7 @@
"right": "Right"
},
"density": {
"mini": "Mini",
"compact": "Compact",
"default": "Default",
"comfortable": "Comfortable"
@@ -1238,6 +1303,11 @@
"bottom_right": "Bottom right",
"bottom_center": "Bottom center",
"top_center": "Top center"
},
"quickSettingsStyle": {
"modern": "Modern",
"classic": "Classic",
"compact": "Compact"
}
},
"osd": {
@@ -1274,6 +1344,11 @@
"hover": "Scroll On Hover",
"never": "Never Scroll"
},
"hide-modes": {
"visible": "Always Visible",
"hidden": "Hide When Empty",
"transparent": "Transparent When Empty"
},
"frame-rates": {
"fps": "{fps} FPS"
},
@@ -1334,9 +1409,9 @@
"calculator-error": "Error"
},
"system": {
"uptime": "System uptime: {uptime}",
"uptime": "Uptime: {uptime}",
"welcome-back": "Welcome back,",
"monitor-description": "{model} ({width}x{height})",
"monitor-description": "{model} ({width}x{height} @ {scale}x)",
"scaling-percentage": "{percentage}%",
"location-display": "{name} ({coordinates})",
"signal-strength": "{signal}%",
@@ -1359,6 +1434,78 @@
"restart": "Restart",
"suspend": "Suspend"
},
"quickSettings": {
"notifications": {
"label": {
"enabled": "Notifications",
"disabled": "Do Not Disturb"
},
"tooltip": {
"action": "Left click: Open notification history\nRight click: Toggle Do Not Disturb"
}
},
"screenRecorder": {
"label": {
"recording": "Stop",
"stopped": "Record"
},
"tooltip": {
"action": "Click to start/stop screen recording"
}
},
"powerProfile": {
"label": {
"unavailable": "Power Profile"
},
"tooltip": {
"action": "Click to cycle power profile"
}
},
"wifi": {
"label": {
"ethernet": "Ethernet",
"wifi": "Wi-Fi",
"disconnected": "Wi-Fi Disconnected"
},
"tooltip": {
"action": "Click to manage Wi-Fi connections"
}
},
"bluetooth": {
"label": {
"enabled": "Bluetooth",
"disabled": "Bluetooth"
},
"tooltip": {
"action": "Click to manage Bluetooth devices"
}
},
"nightLight": {
"label": {
"enabled": "Night Light",
"forced": "Night Light",
"disabled": "Night Light"
},
"tooltip": {
"action": "Click to cycle Night Light mode\nRight click: Open settings"
}
},
"wallpaperSelector": {
"label": "Wallpaper",
"tooltip": {
"action": "Left click: Open wallpaper selector\nRight click: Set random wallpaper"
}
},
"keepAwake": {
"label": {
"enabled": "Keep Awake",
"disabled": "Keep Awake"
},
"tooltip": {
"action": "Click to toggle keep awake mode"
}
}
},
"toast": {
"night-light": {
"enabled": "Enabled",
@@ -1406,6 +1553,9 @@
"enabled": "Enabled",
"disabled": "Disabled"
},
"kofi": {
"opened": "Ko-fi page opened in your browser"
},
"do-not-disturb": {
"enabled": "'Do not disturb' enabled",
"disabled": "'Do not disturb' disabled",
+204 -55
View File
@@ -13,32 +13,6 @@
},
"select-avatar": "Seleccionar imagen de avatar"
},
"ui": {
"section": {
"label": "Interfaz de usuario",
"description": "Personaliza la apariencia, sensación y comportamiento de la interfaz."
},
"tooltips": {
"label": "Mostrar tooltips",
"description": "Activar o desactivar tooltips en toda la interfaz."
},
"dim-desktop": {
"label": "Atenuar escritorio",
"description": "Atenúa el escritorio cuando los paneles o menús están abiertos."
},
"border-radius": {
"label": "Radio del borde",
"description": "Controla la redondez de las esquinas de ventanas, botones y otros elementos."
},
"animation-speed": {
"label": "Velocidad de la animación",
"description": "Ajusta la velocidad de la animación global."
},
"animation-disable": {
"label": "Desactivar animaciones de UI",
"description": "Desactivar todas las animaciones para una experiencia más rápida y responsiva."
}
},
"screen-corners": {
"section": {
"label": "Esquinas de la pantalla",
@@ -54,7 +28,8 @@
},
"radius": {
"label": "Radio de las esquinas de la pantalla",
"description": "Ajusta las esquinas redondeadas de la pantalla."
"description": "Ajusta las esquinas redondeadas de la pantalla.",
"reset": "Restablecer el radio de las esquinas de la pantalla"
}
},
"fonts": {
@@ -83,16 +58,6 @@
}
},
"reset-scaling": "Restablecer la escala"
},
"control-center": {
"section": {
"label": "Centro de control",
"description": "Configurar el posicionamiento y comportamiento del panel del centro de control."
},
"position": {
"label": "Posición",
"description": "Elige dónde aparece el panel del centro de control cuando se abre."
}
}
},
"audio": {
@@ -179,11 +144,9 @@
"monitors": {
"section": {
"label": "Configuración por monitor",
"description": "Ajusta la escala y el brillo para cada pantalla."
"description": "Ajustar el brillo de la configuración para cada pantalla."
},
"scale": "Escala",
"brightness": "Brillo",
"reset-scaling": "Restablecer escala",
"brightness-step": {
"label": "Tamaño del paso de brillo",
"description": "Ajusta el tamaño del paso para los cambios de brillo (rueda de desplazamiento y atajos de teclado)."
@@ -259,7 +222,7 @@
"widgets": {
"section": {
"label": "Posicionamiento de widgets",
"description": "Arrastra y suelta widgets para reordenarlos dentro de cada sección, o usa los botones de añadir/eliminar para gestionar los widgets."
"description": "Arrastra y suelta widgets para reordenarlos. Las insignias indican el uso: [I]zquierda, [C]entro, [D]erecha."
}
},
"monitors": {
@@ -267,6 +230,13 @@
"label": "Visualización en monitores",
"description": "Muestra la barra en monitores específicos. Por defecto, se muestra en todos si no se elige ninguno."
}
},
"tray": {
"blacklist": {
"label": "Lista negra",
"description": "Agregar reglas de exclusión de la bandeja, admite comodines (*).",
"placeholder": "ej., nm-applet, Fcitx*"
}
}
},
"dock": {
@@ -290,6 +260,10 @@
"floating-distance": {
"label": "Distancia de flotación del dock",
"description": "Ajusta la distancia de flotación desde el borde de la pantalla."
},
"colorize-icons": {
"label": "Colorear iconos",
"description": "Aplicar colores del tema a los iconos de aplicaciones del dock (solo aplicaciones no enfocadas)."
}
},
"monitors": {
@@ -402,6 +376,10 @@
"label": "Activar visualización en pantalla",
"description": "Mostrar cambios de volumen y brillo en tiempo real."
},
"always-on-top": {
"label": "Siempre encima",
"description": "Mostrar OSD por encima de ventanas de pantalla completa y otras capas."
},
"location": {
"label": "Ubicación",
"description": "Dónde aparece la visualización en pantalla."
@@ -529,6 +507,9 @@
},
"qt": {
"description": "Escribir {filepath}"
},
"kcolorscheme": {
"description": "Escribir {filepath}"
}
},
"terminal": {
@@ -554,9 +535,9 @@
"description": "Escribir {filepath} y recargar",
"description-missing": "Requiere que {app} esté instalado"
},
"vesktop": {
"description": "Escribir {filepath}",
"description-missing": "Requiere que {app} esté instalado"
"discord": {
"description": "Escribir {filepath} para {client}",
"description-missing": "No se detectó cliente de Discord. Instala vesktop, webcord, armcord, equibop, lightcord o dorion."
},
"pywalfox": {
"description": "Escribir {filepath} y ejecutar pywalfox update",
@@ -703,7 +684,8 @@
"description": "¡Un saludo a nuestro <b>increíble</b> colaborador número {count}!",
"description_plural": "¡Un saludo a nuestros {count} <b>increíbles</b> colaboradores!"
}
}
},
"support": "Apóyanos"
},
"hooks": {
"title": "Hooks",
@@ -737,6 +719,69 @@
"description": "• Hook de fondo de pantalla: $1 = ruta del fondo de pantalla, $2 = nombre de la pantalla\n• Hook de cambio de tema: $1 = true/false (estado del modo oscuro)"
}
}
},
"control-center": {
"position": {
"description": "Elige dónde aparece el panel del Centro de control cuando se abre.",
"label": "Posición"
},
"section": {
"description": "Configurar el posicionamiento y el comportamiento del panel del Centro de control.",
"label": "Apariencia"
},
"title": "Centro de control",
"cards": {
"section": {
"description": "Personaliza qué controles aparecen en el Centro de control y en qué orden.",
"label": "Tarjetas"
}
},
"shortcuts": {
"section": {
"description": "Configurar y administrar los widgets de accesos directos.",
"label": "Widgets de accesos directos"
},
"sectionLeft": "Izquierda",
"sectionRight": "Derecha"
}
},
"user-interface": {
"animation-disable": {
"description": "Desactiva todas las animaciones para una experiencia más rápida y con mayor capacidad de respuesta.",
"label": "Desactivar animaciones de la interfaz de usuario"
},
"animation-speed": {
"description": "Ajustar la velocidad global de la animación.",
"label": "Velocidad de animación",
"reset": "Restablecer la velocidad de la animación"
},
"border-radius": {
"description": "Controla la redondez de las esquinas de las ventanas, los botones y otros elementos.",
"label": "Radio de borde",
"reset": "Restablecer el radio del borde"
},
"compact-lockscreen": {
"description": "Mostrar solo el campo de inicio de sesión y los controles del sistema, ocultando los widgets del clima y multimedia.",
"label": "Pantalla de bloqueo compacta"
},
"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",
"reset-scaling": "Restablecer el escalado de la interfaz"
},
"section": {
"description": "Personaliza la apariencia, el ambiente y el comportamiento de la interfaz.",
"label": "Apariencia"
},
"title": "Interfaz de usuario",
"tooltips": {
"description": "Activar o desactivar los avisos emergentes en toda la interfaz.",
"label": "Mostrar sugerencias"
}
}
},
"widgets": {
@@ -745,7 +790,11 @@
},
"file-picker": {
"select-folder": "Seleccionar carpeta",
"select-file": "Seleccionar archivo"
"select-file": "Seleccionar archivo",
"cancel": "Cancelar",
"search-placeholder": "Buscar archivos y carpetas...",
"select-current": "Seleccionar actual",
"title": "Selector de archivos"
},
"datetime-tokens": {
"common": {
@@ -836,9 +885,9 @@
"search-placeholder": "Buscar widgets..."
},
"active-window": {
"auto-hide": {
"label": "Ocultar automáticamente",
"description": "Ocultar automáticamente el widget cuando no hay ventana activa."
"hide-mode": {
"label": "Modo de ocultación",
"description": "Controla el comportamiento del widget cuando no hay ventana activa."
},
"show-app-icon": {
"label": "Mostrar icono de la aplicación",
@@ -851,6 +900,10 @@
"width": {
"description": "Controla el tamaño horizontal del widget.",
"label": "Ancho del widget"
},
"colorize-icons": {
"label": "Colorear iconos",
"description": "Aplicar colores del tema al icono de la ventana activa."
}
},
"system-monitor": {
@@ -981,9 +1034,9 @@
}
},
"media-mini": {
"auto-hide": {
"label": "Ocultar automáticamente",
"description": "Ocultar automáticamente el widget cuando no se está reproduciendo ningún medio."
"hide-mode": {
"label": "Modo de ocultación",
"description": "Controla el comportamiento del widget cuando no se está reproduciendo ningún medio."
},
"show-album-art": {
"label": "Mostrar arte del álbum",
@@ -1044,6 +1097,16 @@
"only-same-output": {
"description": "Muestra solo las aplicaciones del resultado donde se encuentra la barra.",
"label": "Solo de la misma salida"
},
"colorize-icons": {
"label": "Colorear iconos",
"description": "Aplicar colores del tema a los iconos de la barra de tareas."
}
},
"tray": {
"colorize-icons": {
"label": "Colorear iconos",
"description": "Aplicar colores del tema a los iconos de la bandeja del sistema."
}
}
}
@@ -1213,7 +1276,8 @@
"density": {
"compact": "Compacta",
"default": "Predeterminada",
"comfortable": "Cómoda"
"comfortable": "Cómoda",
"mini": "Mini"
}
},
"launcher": {
@@ -1238,6 +1302,11 @@
"bottom_right": "Inferior derecha",
"bottom_center": "Inferior central",
"top_center": "Superior central"
},
"quickSettingsStyle": {
"modern": "Moderno",
"classic": "Clásico",
"compact": "Compacto"
}
},
"osd": {
@@ -1297,6 +1366,11 @@
"microphone-input": "Entrada del micrófono",
"both": "Salida del sistema + entrada del micrófono"
}
},
"hide-modes": {
"hidden": "Ocultar cuando esté vacío",
"transparent": "Transparente cuando está vacío",
"visible": "Siempre visible"
}
},
"session-menu": {
@@ -1334,9 +1408,9 @@
"calculator-error": "Error"
},
"system": {
"uptime": "Tiempo de actividad: {uptime}",
"uptime": "Actividad: {uptime}",
"welcome-back": "¡Bienvenido de nuevo,",
"monitor-description": "{model} ({width}x{height})",
"monitor-description": "{model} ({width}x{height} @ {scale}x)",
"scaling-percentage": "{percentage}%",
"location-display": "{name} ({coordinates})",
"signal-strength": "{signal}%",
@@ -1359,6 +1433,78 @@
"restart": "Reiniciar",
"suspend": "Suspender"
},
"quickSettings": {
"notifications": {
"label": {
"enabled": "Notificaciones",
"disabled": "No molestar"
},
"tooltip": {
"action": "Clic izquierdo: Abrir historial de notificaciones\nClic derecho: Alternar No molestar"
}
},
"screenRecorder": {
"label": {
"recording": "Detener",
"stopped": "Grabar"
},
"tooltip": {
"action": "Hacer clic para iniciar/detener la grabación de pantalla"
}
},
"powerProfile": {
"label": {
"unavailable": "Perfil de energía"
},
"tooltip": {
"action": "Hacer clic para cambiar el perfil de energía"
}
},
"wifi": {
"label": {
"ethernet": "Ethernet",
"wifi": "Wi-Fi",
"disconnected": "Wi-Fi desconectado"
},
"tooltip": {
"action": "Hacer clic para gestionar las conexiones Wi-Fi"
}
},
"bluetooth": {
"label": {
"enabled": "Bluetooth",
"disabled": "Bluetooth"
},
"tooltip": {
"action": "Hacer clic para gestionar los dispositivos Bluetooth"
}
},
"nightLight": {
"label": {
"enabled": "Luz nocturna",
"forced": "Luz nocturna",
"disabled": "Luz nocturna"
},
"tooltip": {
"action": "Hacer clic para alternar el modo Luz nocturna\nClic derecho: Abrir configuración"
}
},
"wallpaperSelector": {
"label": "Fondo de pantalla",
"tooltip": {
"action": "Clic izquierdo: Abrir selector de fondo de pantalla\nClic derecho: Establecer fondo de pantalla aleatorio"
}
},
"keepAwake": {
"label": {
"enabled": "Mantener despierto",
"disabled": "Mantener despierto"
},
"tooltip": {
"action": "Hacer clic para alternar el modo Mantener despierto"
}
}
},
"toast": {
"night-light": {
"enabled": "Activada",
@@ -1406,6 +1552,9 @@
"enabled": "Activado",
"disabled": "Desactivado"
},
"kofi": {
"opened": "Página de Ko-fi abierta en tu navegador"
},
"do-not-disturb": {
"enabled": "'No molestar' activado",
"disabled": "'No molestar' desactivado",
+206 -57
View File
@@ -13,32 +13,6 @@
},
"select-avatar": "Sélectionner une image d'avatar"
},
"ui": {
"section": {
"label": "Interface utilisateur",
"description": "Personnalisez l'apparence, l'ergonomie et le comportement de l'interface."
},
"tooltips": {
"label": "Afficher les tooltips",
"description": "Activer ou désactiver les tooltips dans toute l'interface."
},
"dim-desktop": {
"label": "Assombrir le bureau",
"description": "Assombrir le bureau lorsque des panneaux ou des menus sont ouverts."
},
"border-radius": {
"label": "Rayon de bordure",
"description": "Contrôle l'arrondi des coins des fenêtres, des boutons et d'autres éléments."
},
"animation-speed": {
"label": "Vitesse d'animation",
"description": "Ajustez la vitesse globale des animations."
},
"animation-disable": {
"label": "Désactiver les animations de l'interface",
"description": "Désactiver toutes les animations pour une expérience plus rapide et réactive."
}
},
"screen-corners": {
"section": {
"label": "Coins de l'écran",
@@ -54,7 +28,8 @@
},
"radius": {
"label": "Rayon des coins de l'écran",
"description": "Ajustez l'arrondi des coins de l'écran."
"description": "Ajustez l'arrondi des coins de l'écran.",
"reset": "Réinitialiser le rayon des coins de l'écran"
}
},
"fonts": {
@@ -83,16 +58,6 @@
}
},
"reset-scaling": "Réinitialiser l'échelle"
},
"control-center": {
"section": {
"label": "Centre de contrôle",
"description": "Configurer le positionnement et le comportement du panneau du centre de contrôle."
},
"position": {
"label": "Position",
"description": "Choisissez où apparaît le panneau du centre de contrôle lors de l'ouverture."
}
}
},
"audio": {
@@ -179,11 +144,9 @@
"monitors": {
"section": {
"label": "Paramètres par moniteur",
"description": "Ajustez la mise à l'échelle et la luminosité pour chaque écran."
"description": "Ajustez la luminosité pour chaque écran."
},
"scale": "Mise à l'échelle",
"brightness": "Luminosité",
"reset-scaling": "Réinitialiser la mise à l'échelle",
"brightness-step": {
"label": "Incrément de luminosité",
"description": "Ajustez l'incrément pour les changements de luminosité (molette de la souris et raccourcis clavier)."
@@ -259,14 +222,21 @@
"widgets": {
"section": {
"label": "Positionnement des widgets",
"description": "Glissez-déposez les widgets pour les réorganiser dans chaque section, ou utilisez les boutons ajouter/supprimer pour gérer les widgets."
"description": "Faites glisser et déposez les widgets pour les réorganiser. Les badges indiquent l'utilisation : [G]auche, [C]entre, [D]roite."
}
},
"monitors": {
"section": {
"label": "Affichage sur les moniteur",
"label": "Affichage sur les moniteurs",
"description": "Afficher la barre sur des moniteurs spécifiques. Par défaut, sur tous si aucun n'est choisi."
}
},
"tray": {
"blacklist": {
"label": "Liste noire",
"description": "Ajouter des règles d'exclusion pour la boîte à miniatures, prend en charge les caractères génériques (*).",
"placeholder": "ex: nm-applet, Fcitx*"
}
}
},
"dock": {
@@ -290,6 +260,10 @@
"floating-distance": {
"label": "Distance de flottaison du dock",
"description": "Ajustez la distance de flottaison par rapport au bord de l'écran."
},
"colorize-icons": {
"label": "Coloriser les icônes",
"description": "Appliquer les couleurs du thème aux icônes d'applications du dock (applications non focalisées uniquement)."
}
},
"monitors": {
@@ -402,6 +376,10 @@
"label": "Activer l'affichage à l'écran",
"description": "Afficher en temps réel les changements de volume et de luminosité."
},
"always-on-top": {
"label": "Toujours au premier plan",
"description": "Afficher l'OSD au-dessus des fenêtres plein écran et autres couches."
},
"location": {
"label": "Emplacement",
"description": "Emplacement des affichages à l'écran."
@@ -529,6 +507,9 @@
},
"qt": {
"description": "Écrire {filepath}"
},
"kcolorscheme": {
"description": "Écrire {filepath}"
}
},
"terminal": {
@@ -554,9 +535,9 @@
"description": "Écrire ~/.config/fuzzel/themes/noctalia et recharger",
"description-missing": "Nécessite que le lanceur fuzzel soit installé"
},
"vesktop": {
"description": "Écrire ~/.config/vesktop/themes/noctalia.theme.css",
"description-missing": "Nécessite que le client Discord vesktop soit installé"
"discord": {
"description": "Écrire {filepath} pour {client}",
"description-missing": "Aucun client Discord détecté. Installez vesktop, webcord, armcord, equibop, lightcord ou dorion."
},
"pywalfox": {
"description": "Écrire ~/.cache/wal/colors.json et exécuter pywalfox update",
@@ -703,7 +684,8 @@
"description": "Un grand merci à notre {count} <b>super</b> contributeur !",
"description_plural": "Un grand merci à nos {count} <b>super</b> contributeurs !"
}
}
},
"support": "Soutenez-nous"
},
"hooks": {
"title": "Hooks",
@@ -737,6 +719,69 @@
"description": "• Hook Fond d'écran : $1 = chemin du fond d'écran, $2 = nom de l'écran\n• Hook de bascule de thème : $1 = true/false (état du mode sombre)"
}
}
},
"control-center": {
"position": {
"description": "Choisissez où le panneau du Centre de contrôle apparaît lorsqu'il est ouvert.",
"label": "Position"
},
"section": {
"description": "Configurer le positionnement et le comportement du panneau du Centre de contrôle.",
"label": "Apparence"
},
"title": "Centre de contrôle",
"cards": {
"section": {
"description": "Personnalisez les commandes qui apparaissent dans le Centre de contrôle et leur ordre d'affichage.",
"label": "Cartes"
}
},
"shortcuts": {
"section": {
"description": "Configurer et gérer les widgets de raccourcis.",
"label": "Widgets de raccourcis"
},
"sectionLeft": "Gauche",
"sectionRight": "Droite"
}
},
"user-interface": {
"animation-disable": {
"description": "Désactiver toutes les animations pour une expérience plus rapide et plus réactive.",
"label": "Désactiver les animations de l'interface utilisateur"
},
"animation-speed": {
"description": "Ajuster la vitesse globale de l'animation.",
"label": "Vitesse d'animation",
"reset": "Réinitialiser la vitesse de l'animation"
},
"border-radius": {
"description": "Contrôle l'arrondi des angles des fenêtres, des boutons et d'autres éléments.",
"label": "Rayon de bordure",
"reset": "Réinitialiser le rayon de la bordure"
},
"compact-lockscreen": {
"description": "Afficher uniquement le champ de saisie de connexion et les commandes système, en masquant les widgets météo et multimédia.",
"label": "Écran de verrouillage compact"
},
"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",
"reset-scaling": "Réinitialiser l'échelle de l'interface"
},
"section": {
"description": "Personnaliser l'apparence, l'ergonomie et le comportement de l'interface.",
"label": "Apparence"
},
"title": "Interface utilisateur",
"tooltips": {
"description": "Activer ou désactiver les info-bulles dans toute l'interface.",
"label": "Afficher les infobulles"
}
}
},
"widgets": {
@@ -745,7 +790,11 @@
},
"file-picker": {
"select-folder": "Sélectionner un dossier",
"select-file": "Sélectionner un fichier"
"select-file": "Sélectionner un fichier",
"cancel": "Annuler",
"search-placeholder": "Rechercher des fichiers et des dossiers...",
"select-current": "Sélectionner Actuel",
"title": "Sélecteur de fichiers"
},
"datetime-tokens": {
"common": {
@@ -844,13 +893,17 @@
"label": "Mode de défilement",
"description": "Contrôler quand le défilement de texte est activé pour les titres de fenêtre longs."
},
"auto-hide": {
"label": "Masquer automatiquement",
"description": "Masquer automatiquement le widget quand aucune fenêtre n'est active."
"hide-mode": {
"label": "Mode de masquage",
"description": "Contrôle le comportement du widget lorsqu'aucune fenêtre n'est active."
},
"width": {
"description": "Contrôle la taille horizontale du widget.",
"label": "Largeur du widget"
},
"colorize-icons": {
"label": "Coloriser les icônes",
"description": "Appliquer les couleurs du thème à l'icône de la fenêtre active."
}
},
"system-monitor": {
@@ -997,9 +1050,9 @@
"label": "Mode de défilement",
"description": "Contrôler quand le défilement de texte est activé pour les titres de piste longs."
},
"auto-hide": {
"label": "Masquer automatiquement",
"description": "Masquer automatiquement le widget quand aucun média n'est en cours de lecture."
"hide-mode": {
"label": "Mode de masquage",
"description": "Contrôle le comportement du widget lorsqu'aucun média n'est en cours de lecture."
},
"no-active-player": "Aucun lecteur actif"
},
@@ -1044,6 +1097,16 @@
"only-same-output": {
"description": "Afficher uniquement les applications de la sortie où la barre est située.",
"label": "Seulement à partir de la même sortie"
},
"colorize-icons": {
"label": "Coloriser les icônes",
"description": "Appliquer les couleurs du thème aux icônes de la barre des tâches."
}
},
"tray": {
"colorize-icons": {
"label": "Coloriser les icônes",
"description": "Appliquer les couleurs du thème aux icônes de la barre système."
}
}
}
@@ -1213,7 +1276,8 @@
"density": {
"compact": "Compact",
"default": "Défaut",
"comfortable": "Confortable"
"comfortable": "Confortable",
"mini": "Mini"
}
},
"launcher": {
@@ -1238,6 +1302,11 @@
"bottom_right": "En bas à droite",
"bottom_center": "En bas au centre",
"top_center": "En haut au centre"
},
"quickSettingsStyle": {
"modern": "Moderne",
"classic": "Classique",
"compact": "Compact"
}
},
"osd": {
@@ -1297,6 +1366,11 @@
"microphone-input": "Entrée microphone",
"both": "Sortie système + entrée microphone"
}
},
"hide-modes": {
"hidden": "Masquer si vide",
"transparent": "Transparent quand vide",
"visible": "Toujours visible"
}
},
"session-menu": {
@@ -1334,9 +1408,8 @@
"calculator-error": "Erreur"
},
"system": {
"uptime": "Temps d'activité : {uptime}",
"welcome-back": "Bon retour,",
"monitor-description": "{model} ({width}x{height})",
"monitor-description": "{model} ({width}x{height} @ {scale}x)",
"scaling-percentage": "{percentage}%",
"location-display": "{name} ({coordinates})",
"signal-strength": "{signal}%",
@@ -1348,7 +1421,8 @@
"user-requested": "Demandé par l'utilisateur",
"unknown": "Inconnu",
"unknown-version": "Inconnue",
"unknown-layout": "Inconnue"
"unknown-layout": "Inconnue",
"uptime": "Activité : {uptime}"
},
"lock-screen": {
"password": "Entrez votre mot de passe...",
@@ -1359,6 +1433,78 @@
"restart": "Redémarrer",
"suspend": "Mettre en veille"
},
"quickSettings": {
"notifications": {
"label": {
"enabled": "Notifications",
"disabled": "Ne pas déranger"
},
"tooltip": {
"action": "Clic gauche : Ouvrir l'historique des notifications\nClic droit : Basculer Ne pas déranger"
}
},
"screenRecorder": {
"label": {
"recording": "Arrêter",
"stopped": "Enregistrer"
},
"tooltip": {
"action": "Cliquer pour démarrer/arrêter l'enregistrement d'écran"
}
},
"powerProfile": {
"label": {
"unavailable": "Profil d'alimentation"
},
"tooltip": {
"action": "Cliquer pour changer de profil d'alimentation"
}
},
"wifi": {
"label": {
"ethernet": "Ethernet",
"wifi": "Wi-Fi",
"disconnected": "Wi-Fi déconnecté"
},
"tooltip": {
"action": "Cliquer pour gérer les connexions Wi-Fi"
}
},
"bluetooth": {
"label": {
"enabled": "Bluetooth",
"disabled": "Bluetooth"
},
"tooltip": {
"action": "Cliquer pour gérer les appareils Bluetooth"
}
},
"nightLight": {
"label": {
"enabled": "Lumière nocturne",
"forced": "Lumière nocturne",
"disabled": "Lumière nocturne"
},
"tooltip": {
"action": "Cliquer pour basculer le mode Lumière nocturne\nClic droit : Ouvrir les paramètres"
}
},
"wallpaperSelector": {
"label": "Fond d'écran",
"tooltip": {
"action": "Clic gauche : Ouvrir le sélecteur de fond d'écran\nClic droit : Définir un fond d'écran aléatoire"
}
},
"keepAwake": {
"label": {
"enabled": "Rester éveillé",
"disabled": "Rester éveillé"
},
"tooltip": {
"action": "Cliquer pour basculer le mode Rester éveillé"
}
}
},
"toast": {
"night-light": {
"enabled": "Activé",
@@ -1406,6 +1552,9 @@
"enabled": "Activé",
"disabled": "Désactivé"
},
"kofi": {
"opened": "Page Ko-fi ouverte dans votre navigateur"
},
"do-not-disturb": {
"enabled": "'Ne pas déranger' activé",
"disabled": "'Ne pas déranger' désactivé",
+204 -55
View File
@@ -13,32 +13,6 @@
},
"select-avatar": "Selecionar imagem de avatar"
},
"ui": {
"section": {
"label": "Interface do usuário",
"description": "Personalize a aparência, a sensação e o comportamento da interface."
},
"tooltips": {
"label": "Mostrar tooltips",
"description": "Ativar ou desativar tooltips em toda a interface."
},
"dim-desktop": {
"label": "Escurecer área de trabalho",
"description": "Escurece a área de trabalho quando painéis ou menus estão abertos."
},
"border-radius": {
"label": "Raio da borda",
"description": "Controla o arredondamento dos cantos de janelas, botões e outros elementos."
},
"animation-speed": {
"label": "Velocidade da animação",
"description": "Ajuste a velocidade global da animação."
},
"animation-disable": {
"label": "Desativar animações da interface",
"description": "Desativar todas as animações para uma experiência mais rápida e responsiva."
}
},
"screen-corners": {
"section": {
"label": "Cantos da tela",
@@ -54,7 +28,8 @@
},
"radius": {
"label": "Raio dos cantos da tela",
"description": "Ajuste os cantos arredondados da tela."
"description": "Ajuste os cantos arredondados da tela.",
"reset": "Redefinir raio dos cantos da tela"
}
},
"fonts": {
@@ -83,16 +58,6 @@
}
},
"reset-scaling": "Redefinir escala"
},
"control-center": {
"section": {
"label": "Centro de controle",
"description": "Configurar o posicionamento e comportamento do painel do centro de controle."
},
"position": {
"label": "Posição",
"description": "Escolha onde o painel do centro de controle aparece quando aberto."
}
}
},
"audio": {
@@ -179,11 +144,9 @@
"monitors": {
"section": {
"label": "Configurações por monitor",
"description": "Ajuste a escala e o brilho para cada tela."
"description": "Ajustar o brilho das configurações para cada tela."
},
"scale": "Escala",
"brightness": "Brilho",
"reset-scaling": "Redefinir escala",
"brightness-step": {
"label": "Tamanho do passo do brilho",
"description": "Ajuste o tamanho do passo para alterações de brilho (roda do mouse e atalhos de teclado)."
@@ -259,7 +222,7 @@
"widgets": {
"section": {
"label": "Posicionamento dos widgets",
"description": "Arraste e solte os widgets para reordená-los em cada seção, ou use os botões de adicionar/remover para gerenciar os widgets."
"description": "Arraste e solte widgets para reordená-los. Os emblemas indicam o uso: [E]squerda, [C]entro, [D]ireita."
}
},
"monitors": {
@@ -267,6 +230,13 @@
"label": "Exibição nos monitores",
"description": "Mostra a barra em monitores específicos. O padrão é todos, se nenhum for escolhido."
}
},
"tray": {
"blacklist": {
"label": "Lista Negra",
"description": "Adicione regras de exclusão para a bandeja do sistema, suporta curingas (*).",
"placeholder": "ex: nm-applet, Fcitx*"
}
}
},
"dock": {
@@ -290,6 +260,10 @@
"floating-distance": {
"label": "Distância de flutuação da dock",
"description": "Ajuste a distância de flutuação da borda da tela."
},
"colorize-icons": {
"label": "Colorir ícones",
"description": "Aplicar cores do tema aos ícones de aplicativos da dock (apenas aplicativos não focados)."
}
},
"monitors": {
@@ -495,6 +469,9 @@
},
"qt": {
"description": "Escrever {filepath}"
},
"kcolorscheme": {
"description": "Escrever {filepath}"
}
},
"terminal": {
@@ -520,9 +497,9 @@
"description": "Escrever {filepath} e recarregar",
"description-missing": "Requer que o {app} esteja instalado"
},
"vesktop": {
"description": "Escrever {filepath}",
"description-missing": "Requer que o {app} esteja instalado"
"discord": {
"description": "Escrever {filepath} para {client}",
"description-missing": "Nenhum cliente Discord detectado. Instale vesktop, webcord, armcord, equibop, lightcord ou dorion."
},
"pywalfox": {
"description": "Escrever {filepath} e executar pywalfox update",
@@ -669,7 +646,8 @@
"description": "Agradecimentos ao nosso <b>incrível</b> colaborador!",
"description_plural": "Agradecimentos aos nossos {count} <b>incríveis</b> colaboradores!"
}
}
},
"support": "Apoie-nos"
},
"hooks": {
"title": "Hooks",
@@ -717,6 +695,10 @@
"label": "Ativar exibição na tela",
"description": "Mostrar alterações de volume e brilho em tempo real."
},
"always-on-top": {
"label": "Sempre no topo",
"description": "Exibir OSD acima de janelas em tela cheia e outras camadas."
},
"location": {
"label": "Localização",
"description": "Onde a exibição na tela aparece."
@@ -737,6 +719,69 @@
"description": "Mostrar a OSD em monitores específicos. Padrão é todos se nenhum for escolhido."
}
}
},
"control-center": {
"position": {
"description": "Escolha onde o painel da Central de Controle aparece quando aberto.",
"label": "Posição"
},
"section": {
"description": "Configurar o posicionamento e o comportamento do painel da Central de Controle.",
"label": "Aparência"
},
"title": "Central de Controle",
"cards": {
"section": {
"description": "Personalize quais controles aparecem na Central de Controle e em que ordem.",
"label": "Cartas"
}
},
"shortcuts": {
"section": {
"description": "Configure e gerencie os widgets de atalhos.",
"label": "Widgets de atalhos"
},
"sectionLeft": "Esquerda",
"sectionRight": "Direito/Certo/À direita"
}
},
"user-interface": {
"animation-disable": {
"description": "Desative todas as animações para uma experiência mais rápida e responsiva.",
"label": "Desativar animações da interface do usuário"
},
"animation-speed": {
"description": "Ajustar a velocidade global da animação.",
"label": "Velocidade da animação",
"reset": "Redefinir velocidade da animação"
},
"border-radius": {
"description": "Controla o arredondamento dos cantos de janelas, botões e outros elementos.",
"label": "Raio da borda",
"reset": "Redefinir raio da borda"
},
"compact-lockscreen": {
"description": "Mostrar apenas a entrada de login e os controles do sistema, ocultando widgets de clima e mídia.",
"label": "Tela de bloqueio compacta"
},
"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",
"reset-scaling": "Redefinir escala da interface"
},
"section": {
"description": "Personalize a aparência, a sensação e o comportamento da interface.",
"label": "Aparência"
},
"title": "Interface do usuário",
"tooltips": {
"description": "Ativar ou desativar dicas de ferramentas em toda a interface.",
"label": "Mostrar dicas de ferramenta"
}
}
},
"widgets": {
@@ -745,7 +790,11 @@
},
"file-picker": {
"select-folder": "Selecionar Pasta",
"select-file": "Selecionar Arquivo"
"select-file": "Selecionar Arquivo",
"cancel": "Cancelar",
"search-placeholder": "Pesquisar arquivos e pastas...",
"select-current": "Selecionar Atual",
"title": "Seletor de Arquivos"
},
"datetime-tokens": {
"common": {
@@ -836,9 +885,9 @@
"search-placeholder": "Pesquisar widgets..."
},
"active-window": {
"auto-hide": {
"label": "Ocultar automaticamente",
"description": "Ocultar automaticamente o widget quando nenhuma janela está ativa."
"hide-mode": {
"label": "Modo de ocultação",
"description": "Controla o comportamento do widget quando nenhuma janela está ativa."
},
"show-app-icon": {
"label": "Mostrar ícone do aplicativo",
@@ -851,6 +900,10 @@
"width": {
"description": "Controla o tamanho horizontal do widget.",
"label": "Largura do Widget"
},
"colorize-icons": {
"label": "Colorir ícones",
"description": "Aplicar cores do tema ao ícone da janela ativa."
}
},
"system-monitor": {
@@ -981,9 +1034,9 @@
}
},
"media-mini": {
"auto-hide": {
"label": "Ocultar automaticamente",
"description": "Ocultar automaticamente o widget quando nenhuma mídia está sendo reproduzida."
"hide-mode": {
"label": "Modo de ocultação",
"description": "Controla o comportamento do widget quando nenhuma mídia está sendo reproduzida."
},
"show-album-art": {
"label": "Mostrar arte do álbum",
@@ -1044,6 +1097,16 @@
"only-same-output": {
"description": "Mostrar apenas os aplicativos da saída onde a barra está localizada.",
"label": "Apenas da mesma saída"
},
"colorize-icons": {
"label": "Colorir ícones",
"description": "Aplicar cores do tema aos ícones da barra de tarefas."
}
},
"tray": {
"colorize-icons": {
"label": "Colorir ícones",
"description": "Aplicar cores do tema aos ícones da bandeja do sistema."
}
}
}
@@ -1237,6 +1300,11 @@
"bottom_right": "Inferior direito",
"bottom_center": "Centro inferior",
"top_center": "Centro superior"
},
"quickSettingsStyle": {
"modern": "Moderno",
"classic": "Clássico",
"compact": "Compacto"
}
},
"bar": {
@@ -1249,7 +1317,8 @@
"density": {
"compact": "Compacta",
"default": "Padrão",
"comfortable": "Confortável"
"comfortable": "Confortável",
"mini": "Mini"
}
},
"display-mode": {
@@ -1297,6 +1366,11 @@
"microphone-input": "Entrada do microfone",
"both": "Saída do sistema + entrada do microfone"
}
},
"hide-modes": {
"hidden": "Ocultar Quando Vazio",
"transparent": "Transparente quando vazio",
"visible": "Sempre Visível"
}
},
"session-menu": {
@@ -1334,9 +1408,9 @@
"calculator-error": "Erro"
},
"system": {
"uptime": "Sistema ativo há: {uptime}",
"uptime": "Atividade: {uptime}",
"welcome-back": "Bem-vindo(a) de volta, {user}!",
"monitor-description": "{model} ({width}x{height})",
"monitor-description": "{model} ({width}x{height} @ {scale}x)",
"scaling-percentage": "{percentage}%",
"location-display": "{name} ({coordinates})",
"signal-strength": "{signal}%",
@@ -1359,6 +1433,78 @@
"restart": "Reiniciar",
"suspend": "Suspender"
},
"quickSettings": {
"notifications": {
"label": {
"enabled": "Notificações",
"disabled": "Não perturbar"
},
"tooltip": {
"action": "Clique esquerdo: Abrir histórico de notificações\nClique direito: Alternar Não perturbar"
}
},
"screenRecorder": {
"label": {
"recording": "Parar",
"stopped": "Gravar"
},
"tooltip": {
"action": "Clique para iniciar/parar a gravação da tela"
}
},
"powerProfile": {
"label": {
"unavailable": "Perfil de energia"
},
"tooltip": {
"action": "Clique para alternar o perfil de energia"
}
},
"wifi": {
"label": {
"ethernet": "Ethernet",
"wifi": "Wi-Fi",
"disconnected": "Wi-Fi desconectado"
},
"tooltip": {
"action": "Clique para gerenciar conexões Wi-Fi"
}
},
"bluetooth": {
"label": {
"enabled": "Bluetooth",
"disabled": "Bluetooth"
},
"tooltip": {
"action": "Clique para gerenciar dispositivos Bluetooth"
}
},
"nightLight": {
"label": {
"enabled": "Luz noturna",
"forced": "Luz noturna",
"disabled": "Luz noturna"
},
"tooltip": {
"action": "Clique para alternar o modo Luz noturna\nClique direito: Abrir configurações"
}
},
"wallpaperSelector": {
"label": "Papel de parede",
"tooltip": {
"action": "Clique esquerdo: Abrir seletor de papel de parede\nClique direito: Definir papel de parede aleatório"
}
},
"keepAwake": {
"label": {
"enabled": "Manter acordado",
"disabled": "Manter acordado"
},
"tooltip": {
"action": "Clique para alternar o modo Manter acordado"
}
}
},
"toast": {
"night-light": {
"enabled": "Ativada",
@@ -1406,6 +1552,9 @@
"enabled": "Ativado",
"disabled": "Desativado"
},
"kofi": {
"opened": "Página do Ko-fi aberta no seu navegador"
},
"do-not-disturb": {
"enabled": "'Não perturbe' ativado",
"disabled": "'Não perturbe' desativado",
+203 -54
View File
@@ -13,32 +13,6 @@
},
"select-avatar": "选择头像图片"
},
"ui": {
"section": {
"label": "用户界面",
"description": "自定义界面的外观、风格和行为。"
},
"tooltips": {
"label": "显示工具提示",
"description": "在整个界面中启用或禁用工具提示。"
},
"dim-desktop": {
"label": "调暗桌面",
"description": "当面板或菜单打开时调暗桌面。"
},
"border-radius": {
"label": "边框圆角",
"description": "控制窗口、按钮及其他元素的边角圆度。"
},
"animation-speed": {
"label": "动画速度",
"description": "调整全局动画速度。"
},
"animation-disable": {
"label": "关闭动画",
"description": "禁用所有动画效果,以获得更快速、更灵敏的体验。"
}
},
"screen-corners": {
"section": {
"label": "屏幕边角",
@@ -54,7 +28,8 @@
},
"radius": {
"label": "屏幕边角半径",
"description": "调整屏幕圆角的弧度。"
"description": "调整屏幕圆角的弧度。",
"reset": "重置屏幕圆角半径"
}
},
"fonts": {
@@ -83,16 +58,6 @@
"description": "增大或减小等宽文本的尺寸"
}
}
},
"control-center": {
"section": {
"label": "控制中心",
"description": "配置控制中心面板的定位和行为。"
},
"position": {
"label": "位置",
"description": "选择控制中心面板打开时出现的位置。"
}
}
},
"audio": {
@@ -179,11 +144,9 @@
"monitors": {
"section": {
"label": "显示器设置",
"description": "调整每个显示器的缩放比例和亮度。"
"description": "调整每个显示器的亮度设置。"
},
"scale": "缩放比例",
"brightness": "亮度",
"reset-scaling": "重置缩放",
"brightness-step": {
"label": "亮度步长",
"description": "调整亮度变化的步长(滚轮和键盘快捷键)。"
@@ -259,7 +222,7 @@
"widgets": {
"section": {
"label": "小部件定位",
"description": "拖放小部件以在每个部分内重新排序,或使用添加/删除按钮管理小部件。"
"description": "拖放小部件以重新排序。徽章表示使用情况:[L]左、[C]中、[R]右。"
}
},
"monitors": {
@@ -267,6 +230,13 @@
"label": "显示器显示",
"description": "在特定显示器上显示状态栏。如果未选择,则默认为全部。"
}
},
"tray": {
"blacklist": {
"label": "黑名单",
"description": "添加托盘排除规则,支持通配符 (*)。",
"placeholder": "例如:nm-applet, Fcitx*"
}
}
},
"dock": {
@@ -290,6 +260,10 @@
"floating-distance": {
"label": "Dock 浮动距离",
"description": "调整距离屏幕边缘的浮动距离。"
},
"colorize-icons": {
"label": "着色图标",
"description": "将主题颜色应用到 Dock 应用图标(仅限非聚焦应用)。"
}
},
"monitors": {
@@ -402,6 +376,10 @@
"label": "启用屏幕显示",
"description": "实时显示音量与亮度变化。"
},
"always-on-top": {
"label": "始终置顶",
"description": "在全屏窗口和其他图层之上显示OSD。"
},
"location": {
"label": "位置",
"description": "屏幕显示出现的位置。"
@@ -529,6 +507,9 @@
},
"qt": {
"description": "写入 {filepath}"
},
"kcolorscheme": {
"description": "写入 {filepath}"
}
},
"terminal": {
@@ -554,9 +535,9 @@
"description": "写入 {filepath} 并重新加载",
"description-missing": "需要安装 {app}"
},
"vesktop": {
"description": "写入 {filepath}",
"description-missing": "需要安装 {app}"
"discord": {
"description": "为 {client} 写入 {filepath}",
"description-missing": "未检测到 Discord 客户端。请安装 vesktop、webcord、armcord、equibop、lightcord 或 dorion。"
},
"pywalfox": {
"description": "写入 {filepath} 并运行 pywalfox update",
@@ -703,7 +684,8 @@
"description": "向我们 {count} 位<b>超棒的</b>贡献者致敬!",
"description_plural": "向我们 {count} 位<b>超棒的</b>贡献者致敬!"
}
}
},
"support": "支持我们"
},
"hooks": {
"title": "钩子",
@@ -737,6 +719,69 @@
"description": "• 壁纸钩子: $1 = 壁纸路径, $2 = 屏幕名称\n• 主题切换钩子: $1 = true/false (深色模式状态)"
}
}
},
"control-center": {
"position": {
"description": "选择打开控制中心时面板出现的位置。",
"label": "位置"
},
"section": {
"description": "配置控制中心面板的位置和行为。",
"label": "外观"
},
"title": "控制中心",
"cards": {
"section": {
"description": "自定义在控制中心显示的控制项及其顺序。",
"label": "卡片"
}
},
"shortcuts": {
"section": {
"description": "配置和管理快捷方式小部件。",
"label": "快捷方式小部件"
},
"sectionLeft": "左",
"sectionRight": "右"
}
},
"user-interface": {
"animation-disable": {
"description": "禁用所有动画以获得更快、更流畅的体验。",
"label": "禁用 UI 动画"
},
"animation-speed": {
"description": "调整全局动画速度。",
"label": "动画速度",
"reset": "重置动画速度"
},
"border-radius": {
"description": "控制窗口、按钮和其他元素的圆角程度。",
"label": "边框半径",
"reset": "重置边框半径"
},
"compact-lockscreen": {
"description": "仅显示登录输入和系统控制,隐藏天气和媒体小部件。",
"label": "紧凑型锁屏"
},
"dim-desktop": {
"description": "当面板或菜单打开时,桌面变暗。",
"label": "昏暗的桌面"
},
"scaling": {
"description": "更改通用用户界面大小,不包括栏。",
"label": "界面缩放",
"reset-scaling": "重置界面缩放"
},
"section": {
"description": "自定义界面的外观、感觉和行为。",
"label": "外观"
},
"title": "用户界面",
"tooltips": {
"description": "启用或禁用整个界面的工具提示。",
"label": "显示工具提示"
}
}
},
"widgets": {
@@ -745,7 +790,11 @@
},
"file-picker": {
"select-folder": "选择文件夹",
"select-file": "选择文件"
"select-file": "选择文件",
"cancel": "取消",
"search-placeholder": "搜索文件和文件夹...",
"select-current": "选择当前",
"title": "文件选择器"
},
"datetime-tokens": {
"common": {
@@ -836,9 +885,9 @@
"search-placeholder": "搜索小部件..."
},
"active-window": {
"auto-hide": {
"label": "自动隐藏",
"description": "当没有活动窗口时自动隐藏小部件。"
"hide-mode": {
"label": "隐藏模式",
"description": "控制当没有活动窗口时小部件的行为。"
},
"show-app-icon": {
"label": "显示应用图标",
@@ -851,6 +900,10 @@
"width": {
"description": "控制小部件的水平尺寸。",
"label": "小部件宽度"
},
"colorize-icons": {
"label": "着色图标",
"description": "将主题颜色应用到活动窗口图标。"
}
},
"system-monitor": {
@@ -981,9 +1034,9 @@
}
},
"media-mini": {
"auto-hide": {
"label": "自动隐藏",
"description": "当没有媒体播放时自动隐藏小部件。"
"hide-mode": {
"label": "隐藏模式",
"description": "控制当没有媒体播放时小部件的行为。"
},
"show-album-art": {
"label": "显示专辑封面",
@@ -1044,6 +1097,16 @@
"only-same-output": {
"label": "仅显示同屏幕",
"description": "仅显示任务栏所在屏幕上的应用程序"
},
"colorize-icons": {
"label": "着色图标",
"description": "将主题颜色应用到任务栏图标。"
}
},
"tray": {
"colorize-icons": {
"label": "着色图标",
"description": "将主题颜色应用到系统托盘图标。"
}
}
}
@@ -1213,7 +1276,8 @@
"density": {
"compact": "紧凑",
"default": "默认",
"comfortable": "舒适"
"comfortable": "舒适",
"mini": "迷你"
}
},
"launcher": {
@@ -1238,6 +1302,11 @@
"bottom_right": "右下角",
"bottom_center": "底部居中",
"top_center": "顶部居中"
},
"quickSettingsStyle": {
"modern": "现代",
"classic": "经典",
"compact": "紧凑"
}
},
"osd": {
@@ -1297,6 +1366,11 @@
"microphone-input": "麦克风输入",
"both": "系统输出 + 麦克风输入"
}
},
"hide-modes": {
"hidden": "当为空时隐藏",
"transparent": "空时透明",
"visible": "始终可见"
}
},
"session-menu": {
@@ -1336,7 +1410,7 @@
"system": {
"uptime": "系统运行时间:{uptime}",
"welcome-back": "欢迎回来,",
"monitor-description": "{model} ({width}x{height})",
"monitor-description": "{model} ({width}x{height} @ {scale}x)",
"scaling-percentage": "{percentage}%",
"location-display": "{name} ({coordinates})",
"signal-strength": "{signal}%",
@@ -1359,6 +1433,78 @@
"restart": "重启",
"suspend": "挂起"
},
"quickSettings": {
"notifications": {
"label": {
"enabled": "通知",
"disabled": "勿扰模式"
},
"tooltip": {
"action": "左键:打开通知历史\n右键:切换勿扰模式"
}
},
"screenRecorder": {
"label": {
"recording": "停止",
"stopped": "录制"
},
"tooltip": {
"action": "点击开始/停止屏幕录制"
}
},
"powerProfile": {
"label": {
"unavailable": "电源模式"
},
"tooltip": {
"action": "点击切换电源模式"
}
},
"wifi": {
"label": {
"ethernet": "以太网",
"wifi": "Wi-Fi",
"disconnected": "Wi-Fi 已断开"
},
"tooltip": {
"action": "点击管理 Wi-Fi 连接"
}
},
"bluetooth": {
"label": {
"enabled": "蓝牙",
"disabled": "蓝牙"
},
"tooltip": {
"action": "点击管理蓝牙设备"
}
},
"nightLight": {
"label": {
"enabled": "夜间模式",
"forced": "夜间模式",
"disabled": "夜间模式"
},
"tooltip": {
"action": "点击切换夜间模式\n右键:打开设置"
}
},
"wallpaperSelector": {
"label": "壁纸",
"tooltip": {
"action": "左键:打开壁纸选择器\n右键:设置随机壁纸"
}
},
"keepAwake": {
"label": {
"enabled": "保持唤醒",
"disabled": "保持唤醒"
},
"tooltip": {
"action": "点击切换保持唤醒模式"
}
}
},
"toast": {
"night-light": {
"enabled": "已启用",
@@ -1406,6 +1552,9 @@
"enabled": "已启用",
"disabled": "已禁用"
},
"kofi": {
"opened": "Ko-fi页面已在您的浏览器中打开"
},
"do-not-disturb": {
"enabled": "'勿扰模式'已启用",
"disabled": "'勿扰模式'已禁用",
+68 -12
View File
@@ -36,12 +36,6 @@
{
"id": "NotificationHistory"
},
{
"id": "WiFi"
},
{
"id": "Bluetooth"
},
{
"id": "Battery"
},
@@ -65,10 +59,12 @@
"dimDesktop": true,
"showScreenCorners": false,
"forceBlackScreenCorners": false,
"scaleRatio": 1,
"radiusRatio": 1,
"screenRadiusRatio": 1,
"animationSpeed": 1,
"animationDisabled": false
"animationDisabled": false,
"compactLockScreen": false
},
"location": {
"name": "Tokyo",
@@ -112,7 +108,59 @@
"terminalCommand": "xterm -e"
},
"controlCenter": {
"position": "close_to_bar_button"
"position": "close_to_bar_button",
"shortcuts": {
"left": [
{
"id": "WiFi"
},
{
"id": "Bluetooth"
},
{
"id": "ScreenRecorder"
},
{
"id": "WallpaperSelector"
}
],
"right": [
{
"id": "Notifications"
},
{
"id": "PowerProfile"
},
{
"id": "KeepAwake"
},
{
"id": "NightLight"
}
]
},
"cards": [
{
"enabled": true,
"id": "profile-card"
},
{
"enabled": true,
"id": "shortcuts-card"
},
{
"enabled": true,
"id": "audio-card"
},
{
"enabled": true,
"id": "weather-card"
},
{
"enabled": true,
"id": "media-sysmon-card"
}
]
},
"dock": {
"displayMode": "always_visible",
@@ -120,7 +168,8 @@
"floatingRatio": 1,
"onlySameOutput": true,
"monitors": [],
"pinnedApps": []
"pinnedApps": [],
"colorizeIcons": false
},
"network": {
"wifiEnabled": true
@@ -140,7 +189,8 @@
"enabled": true,
"location": "top_right",
"monitors": [],
"autoHideMs": 2000
"autoHideMs": 2000,
"alwaysOnTop": false
},
"audio": {
"volumeStep": 5,
@@ -155,7 +205,6 @@
"fontFixed": "DejaVu Sans Mono",
"fontDefaultScale": 1,
"fontFixedScale": 1,
"monitorsScaling": [],
"idleInhibitorEnabled": false,
"tooltipsEnabled": true
},
@@ -172,11 +221,18 @@
"templates": {
"gtk": false,
"qt": false,
"kcolorscheme": false,
"kitty": false,
"ghostty": false,
"foot": false,
"fuzzel": false,
"vesktop": false,
"discord": false,
"discord_vesktop": false,
"discord_webcord": false,
"discord_armcord": false,
"discord_equibop": false,
"discord_lightcord": false,
"discord_dorion": false,
"pywalfox": false,
"enableUserTemplates": false
},
+202 -7
View File
@@ -123,13 +123,13 @@ EOF
# Make API call to Gemini
local api_url="https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${api_key}"
print_color $BLUE " API URL: $api_url" >&2
# print_color $BLUE " API URL: $api_url" >&2
local response=$(curl -s -X POST "$api_url" \
-H "Content-Type: application/json" \
-d "$request_body" 2>/dev/null)
print_color $BLUE " API Response: $response" >&2
# print_color $BLUE " API Response: $response" >&2
# Extract the translation from response - try multiple parsing approaches
local translation=$(echo "$response" | jq -r '.candidates[0].content.parts[0].text // .text // empty' 2>/dev/null | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
@@ -181,6 +181,40 @@ inject_translation() {
fi
}
# Function to remove a key from JSON file using jq
remove_json_key() {
local json_file=$1
local key_path=$2
# Split key path into array
local -a path_parts
IFS='.' read -ra path_parts <<< "$key_path"
# Build jq path array
local jq_path="["
for i in "${!path_parts[@]}"; do
if [[ $i -gt 0 ]]; then
jq_path+=","
fi
jq_path+="\"${path_parts[$i]}\""
done
jq_path+="]"
# Create a temporary file
local temp_file=$(mktemp)
# Use jq to delete the path
jq --argjson path "$jq_path" 'delpaths([$path])' "$json_file" > "$temp_file"
if [[ $? -eq 0 ]]; then
mv "$temp_file" "$json_file"
return 0
else
rm -f "$temp_file"
return 1
fi
}
# Function to extract all keys from a JSON file recursively
extract_keys() {
local json_file=$1
@@ -207,6 +241,78 @@ extract_keys() {
' "$json_file" 2>/dev/null | sort
}
# Function to extract empty keys from a JSON file recursively
extract_empty_keys() {
local json_file=$1
if [[ ! -f "$json_file" ]]; then
echo "Error: File $json_file not found" >&2
return 1
fi
# Extract all keys with empty string or null values recursively using jq
jq -r '
def empty_keys_recursive:
if type == "object" then
keys[] as $k |
if (.[$k] | type) == "object" then
($k + "." + (.[$k] | empty_keys_recursive))
elif (.[$k] == "" or .[$k] == null) then
$k
else
empty
end
else
empty
end;
empty_keys_recursive
' "$json_file" 2>/dev/null | sort
}
# Function to remove empty objects recursively from JSON file
remove_empty_objects() {
local json_file=$1
# Create a temporary file
local temp_file=$(mktemp)
# Use jq to recursively remove empty objects
# This function walks the entire JSON tree and removes any object that contains no leaf values
jq '
def remove_empty:
if type == "object" then
to_entries |
map(
.value |= remove_empty
) |
map(
select(
.value != {} and
.value != [] and
.value != null and
.value != ""
)
) |
from_entries |
if length == 0 then empty else . end
elif type == "array" then
map(remove_empty) |
map(select(. != null and . != {} and . != [] and . != ""))
else
.
end;
remove_empty
' "$json_file" > "$temp_file" 2>/dev/null
if [[ $? -eq 0 ]]; then
mv "$temp_file" "$json_file"
return 0
else
rm -f "$temp_file"
return 1
fi
}
# Function to get language files
get_language_files() {
find "$FOLDER_PATH" -maxdepth 1 -name "*.json" -type f | sort
@@ -223,15 +329,20 @@ generate_header() {
echo "Reference file: $REFERENCE_FILE"
echo "Folder: $(realpath "$FOLDER_PATH")"
if $TRANSLATE_MODE; then
echo "Mode: TRANSLATION ENABLED"
echo "Mode: TRANSLATION ENABLED (translates missing keys, removes extra/empty keys and empty objects)"
fi
echo ""
echo "Notes:"
echo "- Keys are compared recursively through all nested JSON objects"
echo "- Missing keys indicate incomplete translations"
echo "- Extra keys might indicate deprecated keys or translation-specific additions"
echo "- Empty keys are keys with empty string (\"\") or null values"
echo "- Empty objects are nested objects containing no actual values (only other empty objects)"
echo "- Translation completion percentage is calculated based on English reference"
echo "- Results are sorted by descending line numbers for easier editing"
if $TRANSLATE_MODE; then
echo "- In translation mode, extra keys, empty keys, and empty objects are automatically removed"
fi
echo ""
echo "This report compares all language JSON files against the English reference file"
echo "and identifies missing keys and extra keys in each language."
@@ -427,11 +538,92 @@ compare_language() {
done
rm -f "$temp_extra"
echo ""
# Remove extra keys if in translate mode
if $TRANSLATE_MODE; then
print_color $BLUE "Removing extra keys from $lang_name..." >&2
local removed_count=0
local failed_removal_count=0
while IFS= read -r key; do
if [[ -n "$key" ]]; then
print_color $YELLOW " Removing: $key" >&2
if remove_json_key "$lang_file" "$key"; then
print_color $GREEN " ✓ Removed: $key" >&2
removed_count=$((removed_count + 1))
else
print_color $RED " ✗ Failed to remove: $key" >&2
failed_removal_count=$((failed_removal_count + 1))
fi
fi
done <<< "$extra_keys"
echo ""
print_color $GREEN "Removal complete: $removed_count removed, $failed_removal_count failed" >&2
echo ""
fi
else
echo "✅ No extra keys in $lang_name"
echo ""
fi
# Handle empty keys in translate mode
if $TRANSLATE_MODE; then
local empty_keys=$(extract_empty_keys "$lang_file")
local empty_count=$(count_non_empty_lines "$empty_keys")
if [[ $empty_count -gt 0 && -n "$empty_keys" ]]; then
echo "EMPTY KEYS IN $lang_name:"
# Display empty keys
local counter=1
while IFS= read -r key; do
if [[ -n "$key" ]]; then
local lang_line=$(find_key_line_number "$lang_file" "$key")
printf " %3d. %s (%s:%s)\n" "$counter" "$key" "$(basename "$lang_file")" "$lang_line"
counter=$((counter + 1))
fi
done <<< "$empty_keys"
echo ""
print_color $BLUE "Removing empty keys from $lang_name..." >&2
local removed_empty_count=0
local failed_empty_removal_count=0
while IFS= read -r key; do
if [[ -n "$key" ]]; then
print_color $YELLOW " Removing empty key: $key" >&2
if remove_json_key "$lang_file" "$key"; then
print_color $GREEN " ✓ Removed: $key" >&2
removed_empty_count=$((removed_empty_count + 1))
else
print_color $RED " ✗ Failed to remove: $key" >&2
failed_empty_removal_count=$((failed_empty_removal_count + 1))
fi
fi
done <<< "$empty_keys"
echo ""
print_color $GREEN "Empty key removal complete: $removed_empty_count removed, $failed_empty_removal_count failed" >&2
echo ""
else
echo "✅ No empty keys in $lang_name"
echo ""
fi
# Remove empty objects (nested objects with no actual values)
print_color $BLUE "Cleaning up empty objects in $lang_name..." >&2
if remove_empty_objects "$lang_file"; then
print_color $GREEN "✓ Successfully removed all empty objects" >&2
echo ""
else
print_color $RED "✗ Failed to clean up empty objects" >&2
echo ""
fi
fi
# Clean up
rm -f "$lang_keys_file"
}
@@ -545,7 +737,7 @@ main() {
echo "Target language: $target_language"
fi
if $TRANSLATE_MODE; then
echo "Translation mode: ENABLED"
echo "Translation mode: ENABLED (translated missing keys, removed extra keys, removed empty keys and objects)"
fi
echo "Report generated: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""
@@ -568,7 +760,9 @@ show_usage() {
echo "This script compares JSON language files in '$FOLDER_PATH' against the English reference." >&2
echo "" >&2
echo "Arguments:" >&2
echo " --translate Enable automatic translation of missing keys using Gemini API" >&2
echo " --translate Enable automatic translation of missing keys, removal of extra keys," >&2
echo " removal of empty keys (empty strings or null values), and removal of" >&2
echo " empty objects (nested objects containing no actual values)" >&2
echo " --list-models List all available Gemini models and exit" >&2
echo " language_code Optional. Compare only the specified language (e.g., 'fr', 'es', 'de')" >&2
echo " If not provided, all language files will be compared" >&2
@@ -581,8 +775,8 @@ show_usage() {
echo " $0 # Compare all languages" >&2
echo " $0 fr # Compare only French (fr.json)" >&2
echo " $0 --list-models # List available Gemini models" >&2
echo " $0 --translate # Compare all and translate missing keys" >&2
echo " $0 --translate fr # Translate missing keys for French only" >&2
echo " $0 --translate # Compare all, translate missing, remove extra/empty keys and objects" >&2
echo " $0 --translate fr # Translate and clean French only" >&2
echo "" >&2
echo "Requirements:" >&2
echo " - jq must be installed" >&2
@@ -595,6 +789,7 @@ show_usage() {
echo " - Comparison report is printed to stdout" >&2
echo " - Progress messages are printed to stderr" >&2
echo " - Results are sorted by descending line numbers for easier editing" >&2
echo " - In translate mode, extra keys, empty keys, and empty objects are removed" >&2
}
# Handle command line arguments
View File
+14 -4
View File
@@ -54,6 +54,9 @@ Singleton {
var data = JSON.parse(text())
root.translations = data
Logger.log("I18n", `Loaded translations for "${root.langCode}"`)
if (debug) {
Logger.log("I18n", `Available root keys: ${Object.keys(data).join(", ")}`)
}
root.isLoaded = true
root.translationsLoaded()
@@ -279,9 +282,9 @@ Singleton {
interpolations = {}
if (!isLoaded) {
// if (debug) {
// Logger.warn("I18n", "Translations not loaded yet")
// }
if (debug) {
Logger.warn("I18n", "Translations not loaded yet")
}
return key
}
@@ -291,12 +294,19 @@ Singleton {
// Look-up translation in the active language
var value = translations
var notFound = false
if (debug) {
Logger.log("I18n", `Looking up key: "${key}"`)
}
for (var i = 0; i < keys.length; i++) {
if (value && typeof value === "object" && keys[i] in value) {
value = value[keys[i]]
if (debug) {
Logger.log("I18n", `Found key part "${keys[i]}"`)
}
} else {
if (debug) {
Logger.warn("I18n", `Translation key "${key}" not found`)
Logger.warn("I18n", `Translation key "${key}" not found at part "${keys[i]}"`)
Logger.warn("I18n", `Available keys: ${Object.keys(value || {}).join(", ")}`)
}
notFound = true
break
+79 -11
View File
@@ -33,6 +33,7 @@ Singleton {
// Signal emitted when settings are loaded after startupcale changes
signal settingsLoaded
signal settingsSaved
// -----------------------------------------------------
// -----------------------------------------------------
@@ -71,11 +72,7 @@ Singleton {
running: false
interval: 1000
onTriggered: {
settingsFileView.writeAdapter()
// Write to fallback location if set
if (Quickshell.env("NOCTALIA_SETTINGS_FALLBACK")) {
settingsFallbackFileView.writeAdapter()
}
root.saveImmediate()
}
}
@@ -162,10 +159,6 @@ Singleton {
"id": "Tray"
}, {
"id": "NotificationHistory"
}, {
"id": "WiFi"
}, {
"id": "Bluetooth"
}, {
"id": "Battery"
}, {
@@ -186,10 +179,12 @@ Singleton {
property bool dimDesktop: true
property bool showScreenCorners: false
property bool forceBlackScreenCorners: false
property real scaleRatio: 1.0
property real radiusRatio: 1.0
property real screenRadiusRatio: 1.0
property real animationSpeed: 1.0
property bool animationDisabled: false
property bool compactLockScreen: false
}
// location
@@ -246,6 +241,43 @@ Singleton {
property JsonObject controlCenter: JsonObject {
// Position: close_to_bar_button, center, top_left, top_right, bottom_left, bottom_right, bottom_center, top_center
property string position: "close_to_bar_button"
property JsonObject shortcuts
shortcuts: JsonObject {
property list<var> left: [{
"id": "WiFi"
}, {
"id": "Bluetooth"
}, {
"id": "ScreenRecorder"
}, {
"id": "WallpaperSelector"
}]
property list<var> right: [{
"id": "Notifications"
}, {
"id": "PowerProfile"
}, {
"id": "KeepAwake"
}, {
"id": "NightLight"
}]
}
property list<var> cards: [{
"id": "profile-card",
"enabled": true
}, {
"id": "shortcuts-card",
"enabled": true
}, {
"id": "audio-card",
"enabled": true
}, {
"id": "weather-card",
"enabled": true
}, {
"id": "media-sysmon-card",
"enabled": true
}]
}
// dock
@@ -257,6 +289,7 @@ Singleton {
property list<string> monitors: []
// Desktop entry IDs pinned to the dock (e.g., "org.kde.konsole", "firefox.desktop")
property list<string> pinnedApps: []
property bool colorizeIcons: false
}
// network
@@ -283,6 +316,7 @@ Singleton {
property string location: "top_right"
property list<string> monitors: []
property int autoHideMs: 2000
property bool alwaysOnTop: false
}
// audio
@@ -301,7 +335,6 @@ Singleton {
property string fontFixed: "DejaVu Sans Mono"
property real fontDefaultScale: 1.0
property real fontFixedScale: 1.0
property list<var> monitorsScaling: []
property bool idleInhibitorEnabled: false
property bool tooltipsEnabled: true
}
@@ -323,11 +356,18 @@ Singleton {
property JsonObject templates: JsonObject {
property bool gtk: false
property bool qt: false
property bool kcolorscheme: false
property bool kitty: false
property bool ghostty: false
property bool foot: false
property bool fuzzel: false
property bool vesktop: false
property bool discord: false
property bool discord_vesktop: false
property bool discord_webcord: false
property bool discord_armcord: false
property bool discord_equibop: false
property bool discord_lightcord: false
property bool discord_dorion: false
property bool pywalfox: false
property bool enableUserTemplates: false
}
@@ -356,6 +396,34 @@ Singleton {
}
}
// -----------------------------------------------------
// Function to preprocess paths by expanding "~" to user's home directory
function preprocessPath(path) {
if (typeof path !== "string" || path === "") {
return path
}
// Expand "~" to user's home directory
if (path.startsWith("~/")) {
return Quickshell.env("HOME") + path.substring(1)
} else if (path === "~") {
return Quickshell.env("HOME")
}
return path
}
// -----------------------------------------------------
// Public function to trigger immediate settings saving
function saveImmediate() {
settingsFileView.writeAdapter()
// Write to fallback location if set
if (Quickshell.env("NOCTALIA_SETTINGS_FALLBACK")) {
settingsFallbackFileView.writeAdapter()
}
root.settingsSaved() // Emit signal after saving
}
// -----------------------------------------------------
// Generate default settings at the root of the repo
function generateDefaultSettings() {
+36 -30
View File
@@ -29,27 +29,25 @@ Singleton {
property int fontWeightBold: 700
// Radii
property int radiusXXS: 4 * Settings.data.general.radiusRatio
property int radiusXS: 8 * Settings.data.general.radiusRatio
property int radiusS: 12 * Settings.data.general.radiusRatio
property int radiusM: 16 * Settings.data.general.radiusRatio
property int radiusL: 20 * Settings.data.general.radiusRatio
//screen Radii
property int screenRadius: 20 * Settings.data.general.screenRadiusRatio
property int radiusXXS: Math.round(4 * Settings.data.general.radiusRatio)
property int radiusXS: Math.round(8 * Settings.data.general.radiusRatio)
property int radiusS: Math.round(12 * Settings.data.general.radiusRatio)
property int radiusM: Math.round(16 * Settings.data.general.radiusRatio)
property int radiusL: Math.round(20 * Settings.data.general.radiusRatio)
property int screenRadius: Math.round(20 * Settings.data.general.screenRadiusRatio)
// Border
property int borderS: 1
property int borderM: 2
property int borderL: 3
property int borderS: Math.round(1 * uiScaleRatio)
property int borderM: Math.round(2 * uiScaleRatio)
property int borderL: Math.round(3 * uiScaleRatio)
// Margins (for margins and spacing)
property int marginXXS: 2
property int marginXS: 4
property int marginS: 8
property int marginM: 12
property int marginL: 16
property int marginXL: 24
property int marginXXS: Math.round(2 * uiScaleRatio)
property int marginXS: Math.round(4 * uiScaleRatio)
property int marginS: Math.round(6 * uiScaleRatio)
property int marginM: Math.round(9 * uiScaleRatio)
property int marginL: Math.round(13 * uiScaleRatio)
property int marginXL: Math.round(18 * uiScaleRatio)
// Opacity
property real opacityNone: 0.0
@@ -70,31 +68,39 @@ Singleton {
property int tooltipDelayLong: 1200
property int pillDelay: 500
// Settings widgets base size
// Widgets base size
property real baseWidgetSize: 33
property real sliderWidth: 200
property real uiScaleRatio: Settings.data.general.scaleRatio
// Bar Dimensions
property real barHeight: {
if (Settings.data.bar.density === "compact") {
switch (Settings.data.bar.density) {
case "mini":
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 22 : 20
case "compact":
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 27 : 25
}
if (Settings.data.bar.density === "default") {
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 33 : 31
}
if (Settings.data.bar.density === "comfortable") {
case "comfortable":
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 39 : 37
default:
case "default":
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 33 : 31
}
}
property real capsuleHeight: {
if (Settings.data.bar.density === "compact") {
switch (Settings.data.bar.density) {
case "mini":
return barHeight * 1.0
case "compact":
return barHeight * 0.85
}
if (Settings.data.bar.density === "default") {
return barHeight * 0.82
}
if (Settings.data.bar.density === "comfortable") {
case "comfortable":
return barHeight * 0.73
default:
case "default":
return barHeight * 0.82
}
}
}
+3 -1
View File
@@ -101,7 +101,9 @@ Singleton {
"brightness-low": "brightness-down-filled",
"brightness-high": "brightness-up-filled",
"settings-general": "adjustments-horizontal",
"settings-bar": "capsule-horizontal",
"settings-bar": "crop-16-9",
"settings-user-interface": "layout-board",
"settings-control-center": "adjustments-horizontal",
"settings-dock": "layout-bottombar",
"settings-launcher": "rocket",
"settings-audio": "device-speaker",
+2 -2
View File
@@ -41,7 +41,7 @@ Singleton {
return `${year}${month}${day}-${hours}${minutes}${seconds}`
}
// Format an easy to read approximate duration ex: 4h32m
// Format an easy to read approximate duration ex: 4h 32m
// Used to display the time remaining on the Battery widget, computer uptime, etc..
function formatVagueHumanReadableDuration(totalSeconds) {
if (typeof totalSeconds !== 'number' || totalSeconds < 0) {
@@ -69,7 +69,7 @@ Singleton {
parts.push(`${seconds}s`)
}
return parts.join('')
return parts.join(' ')
}
// Format a date into
+46 -45
View File
@@ -44,19 +44,6 @@ Variants {
property real fillMode: WallpaperService.getFillModeUniform()
property vector4d fillColor: Qt.vector4d(Settings.data.wallpaper.fillColor.r, Settings.data.wallpaper.fillColor.g, Settings.data.wallpaper.fillColor.b, 1.0)
property int monitoredWidth: modelData.width
property int monitoredHeight: modelData.height
onMonitoredWidthChanged: {
Logger.log("Background", "Screen width changed to:", monitoredWidth, "for", modelData.name)
recalculateImageSizes()
}
onMonitoredHeightChanged: {
Logger.log("Background", "Screen height changed to:", monitoredHeight, "for", modelData.name)
recalculateImageSizes()
}
Component.onCompleted: setWallpaperInitial()
Component.onDestruction: {
@@ -87,6 +74,13 @@ Variants {
}
}
Connections {
target: CompositorService
function onDisplayScalesChanged() {
setWallpaperInitial()
}
}
color: Color.transparent
screen: modelData
WlrLayershell.layer: WlrLayer.Background
@@ -121,33 +115,22 @@ Variants {
visible: false
cache: false
asynchronous: true
sourceSize: undefined
onStatusChanged: {
if (status === Image.Error) {
Logger.warn("Current wallpaper failed to load:", source)
} else if (status === Image.Ready && !dimensionsCalculated) {
dimensionsCalculated = true
calculateSourceSize()
const optimalSize = calculateOptimalWallpaperSize(implicitWidth, implicitHeight)
if (optimalSize !== false) {
sourceSize = optimalSize
}
}
}
onSourceChanged: {
dimensionsCalculated = false
sourceSize = undefined
}
function calculateSourceSize() {
if (implicitWidth > 0 && implicitHeight > 0) {
const imageAspectRatio = implicitWidth / implicitHeight
if (modelData.width >= modelData.height) {
const w = Math.min(modelData.width, implicitWidth)
sourceSize = Qt.size(w, w / imageAspectRatio)
} else {
const h = Math.min(modelData.height, implicitHeight)
sourceSize = Qt.size(h * imageAspectRatio, h)
}
}
}
}
Image {
@@ -161,33 +144,22 @@ Variants {
visible: false
cache: false
asynchronous: true
sourceSize: undefined
onStatusChanged: {
if (status === Image.Error) {
Logger.warn("Next wallpaper failed to load:", source)
} else if (status === Image.Ready && !dimensionsCalculated) {
dimensionsCalculated = true
calculateSourceSize()
const optimalSize = calculateOptimalWallpaperSize(implicitWidth, implicitHeight)
if (optimalSize !== false) {
sourceSize = optimalSize
}
}
}
onSourceChanged: {
dimensionsCalculated = false
sourceSize = undefined
}
function calculateSourceSize() {
if (implicitWidth > 0 && implicitHeight > 0) {
const imageAspectRatio = implicitWidth / implicitHeight
if (modelData.width >= modelData.height) {
const w = Math.min(modelData.width, implicitWidth)
sourceSize = Qt.size(w, w / imageAspectRatio)
} else {
const h = Math.min(modelData.height, implicitHeight)
sourceSize = Qt.size(h * imageAspectRatio, h)
}
}
}
}
// Dynamic shader loader - only loads the active transition shader
@@ -344,6 +316,31 @@ Variants {
}
}
// ------------------------------------------------------
function calculateOptimalWallpaperSize(wpWidth, wpHeight) {
const compositorScale = CompositorService.getDisplayScale(modelData.name)
const screenWidth = modelData.width * compositorScale
const screenHeight = modelData.height * compositorScale
if (wpWidth <= screenWidth || wpHeight <= screenHeight || wpWidth <= 0 || wpHeight <= 0) {
// Do not resize if wallpaper is smaller than one of the screen dimension
return
}
const imageAspectRatio = wpWidth / wpHeight
var dim = Qt.size(0, 0)
if (screenWidth >= screenHeight) {
const w = Math.min(screenWidth, wpWidth)
dim = Qt.size(w, w / imageAspectRatio)
} else {
const h = Math.min(screenHeight, wpHeight)
dim = Qt.size(h * imageAspectRatio, h)
}
Logger.log("Background", `Wallpaper resized on ${modelData.name} ${screenWidth}x${screenHeight} @ ${compositorScale}x`, "src:", wpWidth, wpHeight, "dst:", dim.width, dim.height)
return dim
}
// ------------------------------------------------------
function recalculateImageSizes() {
if (currentWallpaper.status === Image.Ready) {
currentWallpaper.calculateSourceSize()
@@ -353,6 +350,7 @@ Variants {
}
}
// ------------------------------------------------------
function setWallpaperInitial() {
// On startup, defer assigning wallpaper until the service cache is ready, retries every tick
if (!WallpaperService || !WallpaperService.isInitialized) {
@@ -363,6 +361,7 @@ Variants {
setWallpaperImmediate(WallpaperService.getWallpaper(modelData.name))
}
// ------------------------------------------------------
function setWallpaperImmediate(source) {
transitionAnimation.stop()
transitionProgress = 0.0
@@ -376,6 +375,7 @@ Variants {
})
}
// ------------------------------------------------------
function setWallpaperWithTransition(source) {
if (source === currentWallpaper.source) {
return
@@ -409,6 +409,7 @@ Variants {
transitionAnimation.start()
}
// ------------------------------------------------------
// Main method that actually trigger the wallpaper change
function changeWallpaper() {
// Get the transitionType from the settings
+6 -16
View File
@@ -16,21 +16,11 @@ Loader {
id: root
required property ShellScreen modelData
property real scaling: ScalingService.getScreenScale(screen)
screen: modelData
property color cornerColor: Settings.data.general.forceBlackScreenCorners ? Qt.rgba(0, 0, 0, 1) : Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity)
property real cornerRadius: Style.screenRadius * scaling
property real cornerSize: Style.screenRadius * scaling
Connections {
target: ScalingService
function onScaleChanged(screenName, scale) {
if (screenName === screen.name) {
scaling = scale
}
}
}
property real cornerRadius: Style.screenRadius
property real cornerSize: Style.screenRadius
color: Color.transparent
@@ -48,10 +38,10 @@ Loader {
margins {
// When bar is floating, corners should be at screen edges (no margins)
// When bar is not floating, respect bar margins as before
top: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "top" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0
bottom: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "bottom" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0
left: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "left" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0
right: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "right" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0
top: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "top" && Settings.data.bar.backgroundOpacity > 0 ? Style.barHeight : 0
bottom: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "bottom" && Settings.data.bar.backgroundOpacity > 0 ? Style.barHeight : 0
left: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "left" && Settings.data.bar.backgroundOpacity > 0 ? Style.barHeight : 0
right: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "right" && Settings.data.bar.backgroundOpacity > 0 ? Style.barHeight : 0
}
mask: Region {}
+16 -32
View File
@@ -17,16 +17,6 @@ Variants {
id: root
required property ShellScreen modelData
property real scaling: ScalingService.getScreenScale(modelData)
Connections {
target: ScalingService
function onScaleChanged(screenName, scale) {
if ((modelData !== null) && (screenName === modelData.name)) {
scaling = scale
}
}
}
active: BarService.isVisible && modelData && modelData.name ? (Settings.data.bar.monitors.includes(modelData.name) || (Settings.data.bar.monitors.length === 0)) : false
@@ -35,8 +25,8 @@ Variants {
WlrLayershell.namespace: "noctalia-bar"
implicitHeight: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? screen.height : Math.round(Style.barHeight * scaling)
implicitWidth: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? Math.round(Style.barHeight * scaling) : screen.width
implicitHeight: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? screen.height : Style.barHeight
implicitWidth: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? Style.barHeight : screen.width
color: Color.transparent
anchors {
@@ -49,10 +39,10 @@ Variants {
// Floating bar margins - only apply when floating is enabled
// Also don't apply margin on the opposite side ot the bar orientation, ex: if bar is floating on top, margin is only applied on top, not bottom.
margins {
top: Settings.data.bar.floating && Settings.data.bar.position !== "bottom" ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0
bottom: Settings.data.bar.floating && Settings.data.bar.position !== "top" ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0
left: Settings.data.bar.floating && Settings.data.bar.position !== "right" ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0
right: Settings.data.bar.floating && Settings.data.bar.position !== "left" ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0
top: Settings.data.bar.floating && Settings.data.bar.position !== "bottom" ? Settings.data.bar.marginVertical * Style.marginXL : 0
bottom: Settings.data.bar.floating && Settings.data.bar.position !== "top" ? Settings.data.bar.marginVertical * Style.marginXL : 0
left: Settings.data.bar.floating && Settings.data.bar.position !== "right" ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
right: Settings.data.bar.floating && Settings.data.bar.position !== "left" ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
}
Component.onCompleted: {
@@ -105,8 +95,8 @@ Variants {
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: Style.marginM * root.scaling
spacing: Style.marginS * root.scaling
anchors.topMargin: Style.marginM
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.left
@@ -114,7 +104,6 @@ Variants {
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"scaling": ScalingService.getScreenScale(screen),
"widgetId": modelData.id,
"section": "left",
"sectionWidgetIndex": index,
@@ -129,7 +118,7 @@ Variants {
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS * root.scaling
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.center
@@ -137,7 +126,6 @@ Variants {
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"scaling": ScalingService.getScreenScale(screen),
"widgetId": modelData.id,
"section": "center",
"sectionWidgetIndex": index,
@@ -152,8 +140,8 @@ Variants {
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.marginM * root.scaling
spacing: Style.marginS * root.scaling
anchors.bottomMargin: Style.marginM
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.right
@@ -161,7 +149,6 @@ Variants {
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"scaling": ScalingService.getScreenScale(screen),
"widgetId": modelData.id,
"section": "right",
"sectionWidgetIndex": index,
@@ -185,9 +172,9 @@ Variants {
id: leftSection
objectName: "leftSection"
anchors.left: parent.left
anchors.leftMargin: Style.marginS * root.scaling
anchors.leftMargin: Style.marginS
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS * root.scaling
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.left
@@ -195,7 +182,6 @@ Variants {
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"scaling": ScalingService.getScreenScale(screen),
"widgetId": modelData.id,
"section": "left",
"sectionWidgetIndex": index,
@@ -212,7 +198,7 @@ Variants {
objectName: "centerSection"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS * root.scaling
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.center
@@ -220,7 +206,6 @@ Variants {
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"scaling": ScalingService.getScreenScale(screen),
"widgetId": modelData.id,
"section": "center",
"sectionWidgetIndex": index,
@@ -236,9 +221,9 @@ Variants {
id: rightSection
objectName: "rightSection"
anchors.right: parent.right
anchors.rightMargin: Style.marginS * root.scaling
anchors.rightMargin: Style.marginS
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS * root.scaling
spacing: Style.marginS
Repeater {
model: Settings.data.bar.widgets.right
@@ -246,7 +231,6 @@ Variants {
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"scaling": ScalingService.getScreenScale(screen),
"widgetId": modelData.id,
"section": "right",
"sectionWidgetIndex": index,
+17 -17
View File
@@ -18,11 +18,11 @@ ColumnLayout {
}
Layout.fillWidth: true
spacing: Style.marginM * scaling
spacing: Style.marginM
NText {
text: root.label
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
color: Color.mSecondary
font.weight: Style.fontWeightMedium
Layout.fillWidth: true
@@ -51,35 +51,35 @@ ColumnLayout {
}
Layout.fillWidth: true
Layout.preferredHeight: deviceLayout.implicitHeight + (Style.marginM * scaling * 2)
radius: Style.radiusM * scaling
Layout.preferredHeight: deviceLayout.implicitHeight + (Style.marginM * 2)
radius: Style.radiusM
color: Color.mSurface
border.width: Math.max(1, Style.borderS * scaling)
border.width: Math.max(1, Style.borderS)
border.color: getContentColor(Color.mOutline)
RowLayout {
id: deviceLayout
anchors.fill: parent
anchors.margins: Style.marginM * scaling
spacing: Style.marginM * scaling
anchors.margins: Style.marginM
spacing: Style.marginM
Layout.alignment: Qt.AlignVCenter
// One device BT icon
NIcon {
icon: BluetoothService.getDeviceIcon(modelData)
pointSize: Style.fontSizeXXL * scaling
pointSize: Style.fontSizeXXL
color: getContentColor(Color.mOnSurface)
Layout.alignment: Qt.AlignVCenter
}
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginXXS * scaling
spacing: Style.marginXXS
// Device name
NText {
text: modelData.name || modelData.deviceName
pointSize: Style.fontSizeM * scaling
pointSize: Style.fontSizeM
font.weight: Style.fontWeightMedium
elide: Text.ElideRight
color: getContentColor(Color.mOnSurface)
@@ -90,7 +90,7 @@ ColumnLayout {
NText {
text: BluetoothService.getStatusString(modelData)
visible: text !== ""
pointSize: Style.fontSizeXS * scaling
pointSize: Style.fontSizeXS
color: getContentColor(Color.mOnSurfaceVariant)
}
@@ -98,26 +98,26 @@ ColumnLayout {
RowLayout {
visible: modelData.signalStrength !== undefined
Layout.fillWidth: true
spacing: Style.marginXS * scaling
spacing: Style.marginXS
// Device signal strength - "Unknown" when not connected
NText {
text: BluetoothService.getSignalStrength(modelData)
pointSize: Style.fontSizeXS * scaling
pointSize: Style.fontSizeXS
color: getContentColor(Color.mOnSurfaceVariant)
}
NIcon {
visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
text: BluetoothService.getSignalIcon(modelData)
pointSize: Style.fontSizeXS * scaling
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 * scaling
pointSize: Style.fontSizeXS
color: getContentColor(Color.mOnSurface)
}
}
@@ -126,7 +126,7 @@ ColumnLayout {
NText {
visible: modelData.batteryAvailable
text: BluetoothService.getBattery(modelData)
pointSize: Style.fontSizeXS * scaling
pointSize: Style.fontSizeXS
color: getContentColor(Color.mOnSurfaceVariant)
}
}
@@ -142,7 +142,7 @@ ColumnLayout {
visible: (modelData.state !== BluetoothDeviceState.Connecting)
enabled: (canConnect || canDisconnect) && !isBusy
outlined: !button.hovered
fontSize: Style.fontSizeXS * scaling
fontSize: Style.fontSizeXS
fontWeight: Style.fontWeightMedium
backgroundColor: {
if (device.canDisconnect && !isBusy) {
+18 -18
View File
@@ -11,8 +11,8 @@ import qs.Widgets
NPanel {
id: root
preferredWidth: 380
preferredHeight: 500
preferredWidth: 380 * Style.uiScaleRatio
preferredHeight: 500 * Style.uiScaleRatio
panelKeyboardFocus: true
panelContent: Rectangle {
@@ -20,23 +20,23 @@ NPanel {
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginL * scaling
spacing: Style.marginM * scaling
anchors.margins: Style.marginL
spacing: Style.marginM
// HEADER
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM * scaling
spacing: Style.marginM
NIcon {
icon: "bluetooth"
pointSize: Style.fontSizeXXL * scaling
pointSize: Style.fontSizeXXL
color: Color.mPrimary
}
NText {
text: I18n.tr("bluetooth.panel.title")
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.fillWidth: true
@@ -46,7 +46,7 @@ NPanel {
id: bluetoothSwitch
checked: BluetoothService.enabled
onToggled: checked => BluetoothService.setBluetoothEnabled(checked)
baseSize: Style.baseWidgetSize * 0.65 * scaling
baseSize: Style.baseWidgetSize * 0.65
}
NIconButton {
@@ -84,25 +84,25 @@ NPanel {
// Center the content within this rectangle
ColumnLayout {
anchors.centerIn: parent
spacing: Style.marginM * scaling
spacing: Style.marginM
NIcon {
icon: "bluetooth-off"
pointSize: 64 * scaling
pointSize: 64
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("bluetooth.panel.disabled")
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("bluetooth.panel.enable-message")
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
@@ -120,7 +120,7 @@ NPanel {
ColumnLayout {
width: parent.width
spacing: Style.marginM * scaling
spacing: Style.marginM
// Connected devices
BluetoothDevicesList {
@@ -168,7 +168,7 @@ NPanel {
// Fallback - No devices, scanning
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Style.marginM * scaling
spacing: Style.marginM
visible: {
if (!BluetoothService.adapter || !BluetoothService.adapter.discovering || !Bluetooth.devices) {
return false
@@ -182,11 +182,11 @@ NPanel {
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Style.marginXS * scaling
spacing: Style.marginXS
NIcon {
icon: "refresh"
pointSize: Style.fontSizeXXL * 1.5 * scaling
pointSize: Style.fontSizeXXL * 1.5
color: Color.mPrimary
RotationAnimation on rotation {
@@ -200,14 +200,14 @@ NPanel {
NText {
text: I18n.tr("bluetooth.panel.scanning")
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
color: Color.mOnSurface
}
}
NText {
text: I18n.tr("bluetooth.panel.pairing-mode")
pointSize: Style.fontSizeM * scaling
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
+278 -136
View File
@@ -10,22 +10,40 @@ import qs.Widgets
NPanel {
id: root
preferredWidth: Settings.data.location.showWeekNumberInCalendar ? 340 : 320
preferredHeight: 380
readonly property var now: Time.date
preferredWidth: (Settings.data.location.showWeekNumberInCalendar ? 400 : 380) * Style.uiScaleRatio
preferredHeight: 520 * Style.uiScaleRatio
panelKeyboardFocus: true
panelContent: ColumnLayout {
id: content
anchors.fill: parent
anchors.margins: Style.marginL * scaling
spacing: Style.marginM * scaling
anchors.margins: Style.marginL
spacing: Style.marginM
readonly property int firstDayOfWeek: Qt.locale().firstDayOfWeek
property bool isCurrentMonth: checkIsCurrentMonth()
readonly property bool weatherReady: (LocationService.data.weather !== null)
function checkIsCurrentMonth() {
return (Time.date.getMonth() === grid.month) && (Time.date.getFullYear() === grid.year)
}
Shortcut {
sequence: "Escape"
onActivated: {
if (timerActive) {
cancelTimer()
} else {
cancelTimer()
root.close()
}
}
context: Qt.WidgetShortcut
enabled: root.opened
}
Connections {
target: Time
function onDateChanged() {
@@ -33,143 +51,290 @@ NPanel {
}
}
// Current day
// Combined blue banner with date/time and weather summary
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 80 * scaling
radius: Style.radiusL * scaling
Layout.preferredHeight: blueColumn.implicitHeight + Style.marginM * 2
radius: Style.radiusL
color: Color.mPrimary
RowLayout {
anchors.fill: parent
anchors.margins: Style.marginL * scaling
anchors.topMargin: 12 * scaling
spacing: Style.marginM * scaling
ColumnLayout {
id: blueColumn
anchors.top: parent.top
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.topMargin: Style.marginM
anchors.leftMargin: Style.marginM
anchors.bottomMargin: Style.marginM
anchors.rightMargin: clockItem.width + (Style.marginM * 2)
spacing: 0
// Month, Year and Day
// Combined layout for weather icon, date, and weather text
RowLayout {
Layout.alignment: Qt.AlignVCenter
Layout.fillHeight: true
spacing: Style.marginM * scaling
Layout.fillWidth: true
height: 60 * Style.uiScaleRatio
clip: true
spacing: Style.marginS
// Big day of the month
// Weather icon and temperature
ColumnLayout {
Layout.alignment: Qt.AlignVCenter
spacing: Style.marginXXS
NIcon {
Layout.alignment: Qt.AlignHCenter
icon: weatherReady ? LocationService.weatherSymbolFromCode(LocationService.data.weather.current_weather.weathercode) : "cloud"
pointSize: Style.fontSizeXXL
color: Color.mOnPrimary
}
NText {
Layout.alignment: Qt.AlignHCenter
text: {
if (!weatherReady)
return ""
var temp = LocationService.data.weather.current_weather.temperature
var suffix = "C"
if (Settings.data.location.useFahrenheit) {
temp = LocationService.celsiusToFahrenheit(temp)
suffix = "F"
}
temp = Math.round(temp)
return `${temp}°${suffix}`
}
pointSize: Style.fontSizeM
font.weight: Style.fontWeightBold
color: Color.mOnPrimary
}
}
// Today day number - with simple, stable animation
NText {
opacity: content.isCurrentMonth ? 1.0 : 0.0
Layout.preferredWidth: content.isCurrentMonth ? implicitWidth : 0
elide: Text.ElideNone
clip: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
text: Time.date.getDate()
pointSize: Style.fontSizeXXXL * 1.5 * scaling
pointSize: Style.fontSizeXXXL * 1.5
font.weight: Style.fontWeightBold
color: Color.mOnPrimary
visible: isCurrentMonth
Layout.preferredWidth: visible ? implicitWidth : 0
Layout.fillHeight: true
Behavior on opacity {
NumberAnimation {
duration: Style.animationFast
}
}
Behavior on Layout.preferredWidth {
NumberAnimation {
duration: Style.animationFast
easing.type: Easing.InOutQuad
}
}
}
// Month and Year
// Month, year, location
ColumnLayout {
spacing: 0
Layout.preferredWidth: 170 * Style.uiScaleRatio
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.bottomMargin: Style.marginXXS
Layout.topMargin: -Style.marginXXS
spacing: -Style.marginXS
NText {
text: Qt.locale().monthName(grid.month, Locale.LongFormat).toUpperCase()
pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnPrimary
}
RowLayout {
spacing: 0
NText {
text: grid.year
pointSize: Style.fontSizeM * scaling
color: Qt.alpha(Color.mOnPrimary, 0.8)
}
}
}
NText {
text: Qt.locale().monthName(grid.month, Locale.LongFormat).toUpperCase()
pointSize: Style.fontSizeXL * 1.1
font.weight: Style.fontWeightBold
color: Color.mOnPrimary
Layout.alignment: Qt.AlignBaseline
elide: Text.ElideRight
}
Item {
Layout.fillWidth: true
}
// Digital clock with circular progress
Item {
width: Style.fontSizeXXXL * 2 * scaling
height: Style.fontSizeXXXL * 2 * scaling
// Seconds circular progress
Canvas {
id: secondsProgress
anchors.fill: parent
property real progress: Time.date.getSeconds() / 60
onProgressChanged: requestPaint()
Connections {
target: Time
function onDateChanged() {
secondsProgress.progress = Time.date.getSeconds() / 60
NText {
text: ` ${grid.year}`
pointSize: Style.fontSizeM
font.weight: Style.fontWeightBold
color: Qt.alpha(Color.mOnPrimary, 0.7)
Layout.alignment: Qt.AlignBaseline
}
}
onPaint: {
var ctx = getContext("2d")
var centerX = width / 2
var centerY = height / 2
var radius = Math.min(width, height) / 2 - 4 * scaling
RowLayout {
spacing: 0
ctx.reset()
NText {
text: {
if (!weatherReady)
return I18n.tr("calendar.weather.loading")
const chunks = Settings.data.location.name.split(",")
return chunks[0]
}
pointSize: Style.fontSizeM
font.weight: Style.fontWeightMedium
color: Color.mOnPrimary
Layout.maximumWidth: 150
elide: Text.ElideRight
}
// Background circle
ctx.beginPath()
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI)
ctx.lineWidth = 3 * scaling
ctx.strokeStyle = Qt.alpha(Color.mOnPrimary, 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 = 3 * scaling
ctx.strokeStyle = Color.mOnPrimary
ctx.lineCap = "round"
ctx.stroke()
NText {
text: weatherReady ? ` (${LocationService.data.weather.timezone_abbreviation})` : ""
pointSize: Style.fontSizeXS
font.weight: Style.fontWeightMedium
color: Qt.alpha(Color.mOnPrimary, 0.7)
}
}
}
// Digital clock
ColumnLayout {
anchors.centerIn: parent
spacing: -3 * scaling
// Spacer to push content left
Item {
Layout.fillWidth: true
}
}
}
NText {
text: {
var t = Settings.data.location.use12hourFormat ? Qt.locale().toString(new Date(), "hh AP") : Qt.locale().toString(new Date(), "HH")
return t.split(" ")[0]
}
pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightBold
color: Color.mOnPrimary
family: Settings.data.ui.fontFixed
Layout.alignment: Qt.AlignHCenter
// Digital clock with circular progress
Item {
id: clockItem
Layout.alignment: Qt.AlignVCenter
anchors.right: parent.right
anchors.rightMargin: Style.marginM
anchors.verticalCenter: parent.verticalCenter
height: Math.round((Style.fontSizeXXXL * 1.9) / 2 * Style.uiScaleRatio) * 2
width: clockItem.height
// 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(Color.mOnPrimary, 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.mOnPrimary
ctx.lineCap = "round"
ctx.stroke()
}
}
// Digital clock
ColumnLayout {
anchors.centerIn: parent
spacing: -Style.marginXXS
NText {
text: {
var t = Settings.data.location.use12hourFormat ? Qt.locale().toString(now, "hh AP") : Qt.locale().toString(now, "HH")
return t.split(" ")[0]
}
NText {
text: Qt.formatTime(Time.date, "mm")
pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightBold
color: Color.mOnPrimary
family: Settings.data.ui.fontFixed
Layout.alignment: Qt.AlignHCenter
}
pointSize: Style.fontSizeXS
font.weight: Style.fontWeightBold
color: Color.mOnPrimary
family: Settings.data.ui.fontFixed
Layout.alignment: Qt.AlignHCenter
}
NText {
text: Qt.formatTime(now, "mm")
pointSize: Style.fontSizeXXS
font.weight: Style.fontWeightBold
color: Color.mOnPrimary
family: Settings.data.ui.fontFixed
Layout.alignment: Qt.AlignHCenter
}
}
}
}
// Navigation and divider
// ... (rest of the file is unchanged) ...
RowLayout {
visible: weatherReady
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
spacing: Style.marginL
Repeater {
model: weatherReady ? Math.min(6, LocationService.data.weather.daily.time.length) : 0
delegate: ColumnLayout {
Layout.preferredWidth: 0
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
spacing: Style.marginS
NText {
text: {
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"))
return Qt.locale().toString(weatherDate, "ddd")
}
color: Color.mOnSurfaceVariant
pointSize: Style.fontSizeM
font.weight: Style.fontWeightMedium
Layout.alignment: Qt.AlignHCenter
}
NIcon {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index])
pointSize: Style.fontSizeXXL * 1.5
color: Color.mPrimary
}
NText {
Layout.alignment: Qt.AlignHCenter
text: {
var max = LocationService.data.weather.daily.temperature_2m_max[index]
var min = LocationService.data.weather.daily.temperature_2m_min[index]
if (Settings.data.location.useFahrenheit) {
max = LocationService.celsiusToFahrenheit(max)
min = LocationService.celsiusToFahrenheit(min)
}
max = Math.round(max)
min = Math.round(min)
return `${max}°/${min}°`
}
pointSize: Style.fontSizeXS
color: Color.mOnSurfaceVariant
font.weight: Style.fontWeightMedium
}
}
}
}
RowLayout {
visible: !weatherReady
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
NBusyIndicator {}
}
Item {}
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS * scaling
spacing: Style.marginS
NDivider {
Layout.fillWidth: true
}
NIconButton {
icon: "chevron-left"
onClicked: {
@@ -179,7 +344,6 @@ NPanel {
content.isCurrentMonth = content.checkIsCurrentMonth()
}
}
NIconButton {
icon: "calendar"
onClicked: {
@@ -188,7 +352,6 @@ NPanel {
content.isCurrentMonth = true
}
}
NIconButton {
icon: "chevron-right"
onClicked: {
@@ -199,31 +362,24 @@ NPanel {
}
}
}
// Names of days of the week
RowLayout {
Layout.fillWidth: true
spacing: 0
Item {
visible: Settings.data.location.showWeekNumberInCalendar
Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 * scaling : 0
Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 : 0
}
GridLayout {
Layout.fillWidth: true
columns: 7
rows: 1
columnSpacing: 0
rowSpacing: 0
Repeater {
model: 7
Item {
Layout.fillWidth: true
Layout.preferredHeight: Style.baseWidgetSize * 0.6 * scaling
Layout.preferredHeight: Style.baseWidgetSize * 0.6
NText {
anchors.centerIn: parent
text: {
@@ -232,7 +388,7 @@ NPanel {
return dayNames[dayIndex]
}
color: Color.mPrimary
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
font.weight: Style.fontWeightBold
horizontalAlignment: Text.AlignHCenter
}
@@ -240,31 +396,24 @@ NPanel {
}
}
}
// Grid with weeks and days
RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 0
// Column of week numbers
ColumnLayout {
visible: Settings.data.location.showWeekNumberInCalendar
Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 * scaling : 0
Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 : 0
Layout.fillHeight: true
spacing: 0
Repeater {
model: 6
Item {
Layout.fillWidth: true
Layout.fillHeight: true
NText {
anchors.centerIn: parent
color: Color.mOutline
pointSize: Style.fontSizeXXS * scaling
pointSize: Style.fontSizeXXS
font.weight: Style.fontWeightMedium
text: {
let firstOfMonth = new Date(grid.year, grid.month, 1)
@@ -292,27 +441,21 @@ NPanel {
}
}
}
// Days Grid
MonthGrid {
id: grid
Layout.fillWidth: true
Layout.fillHeight: true
spacing: Style.marginXXS * scaling
spacing: Style.marginXXS
month: Time.date.getMonth()
year: Time.date.getFullYear()
locale: Qt.locale()
delegate: Item {
Rectangle {
width: Style.baseWidgetSize * 0.9 * scaling
height: Style.baseWidgetSize * 0.9 * scaling
width: Style.baseWidgetSize * 0.9
height: Style.baseWidgetSize * 0.9
anchors.centerIn: parent
radius: Style.radiusM * scaling
radius: Style.radiusM
color: model.today ? Color.mSecondary : Color.transparent
NText {
anchors.centerIn: parent
text: model.day
@@ -324,10 +467,9 @@ NPanel {
return Color.mOnSurfaceVariant
}
opacity: model.month === grid.month ? 1.0 : 0.4
pointSize: Style.fontSizeM * scaling
pointSize: Style.fontSizeM
font.weight: model.today ? Style.fontWeightBold : Style.fontWeightMedium
}
Behavior on color {
ColorAnimation {
duration: Style.animationFast
+3 -3
View File
@@ -12,13 +12,13 @@ Item {
property string text: ""
property string suffix: ""
property string tooltipText: ""
property string density: ""
property bool autoHide: false
property bool forceOpen: false
property bool forceClose: false
property bool disableOpen: false
property bool rightOpen: false
property bool hovered: false
property bool compact: false
readonly property string barPosition: Settings.data.bar.position
readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right"
@@ -54,7 +54,7 @@ Item {
disableOpen: root.disableOpen
rightOpen: root.rightOpen
hovered: root.hovered
compact: root.compact
density: root.density
onShown: root.shown()
onHidden: root.hidden()
onEntered: root.entered()
@@ -79,7 +79,7 @@ Item {
disableOpen: root.disableOpen
rightOpen: root.rightOpen
hovered: root.hovered
compact: root.compact
density: root.density
onShown: root.shown()
onHidden: root.hidden()
onEntered: root.entered()
+32 -13
View File
@@ -14,13 +14,13 @@ Item {
property string text: ""
property string suffix: ""
property string tooltipText: ""
property string density: ""
property bool autoHide: false
property bool forceOpen: false
property bool forceClose: false
property bool disableOpen: false
property bool rightOpen: false
property bool hovered: false
property bool compact: false
// Effective shown state (true if hovered/animated open or forced)
readonly property bool revealed: !forceClose && (forceOpen || showPill)
@@ -38,13 +38,28 @@ Item {
property bool showPill: false
property bool shouldAnimateHide: false
readonly property int pillHeight: Math.round(Style.capsuleHeight * scaling)
readonly property int pillPaddingHorizontal: Math.round(Style.capsuleHeight * 0.2 * scaling)
readonly property int pillOverlap: Math.round(Style.capsuleHeight * 0.5 * scaling)
readonly property int pillMaxWidth: Math.max(1, textItem.implicitWidth + pillPaddingHorizontal * 2 + pillOverlap)
readonly property int pillHeight: Style.capsuleHeight
readonly property int pillPaddingHorizontal: Math.round(Style.capsuleHeight * 0.2)
readonly property int pillOverlap: Math.round(Style.capsuleHeight * 0.5)
readonly property int pillMaxWidth: Math.max(1, Math.round(textItem.implicitWidth + pillPaddingHorizontal * 2 + pillOverlap))
readonly property real iconSize: Math.max(1, compact ? pillHeight * 0.65 : pillHeight * 0.48)
readonly property real textSize: Math.max(1, compact ? pillHeight * 0.45 : pillHeight * 0.33)
readonly property real iconSize: {
switch (root.density) {
case "compact":
return Math.max(1, Math.round(pillHeight * 0.65))
default:
return Math.max(1, Math.round(pillHeight * 0.48))
}
}
readonly property real textSize: {
switch (root.density) {
case "compact":
return Math.max(1, Math.round(pillHeight * 0.45))
default:
return Math.max(1, Math.round(pillHeight * 0.33))
}
}
width: pillHeight + Math.max(0, pill.width - pillOverlap)
height: pillHeight
@@ -68,10 +83,12 @@ Item {
opacity: revealed ? Style.opacityFull : Style.opacityNone
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
topLeftRadius: rightOpen ? 0 : pillHeight * 0.5
bottomLeftRadius: rightOpen ? 0 : pillHeight * 0.5
topRightRadius: rightOpen ? pillHeight * 0.5 : 0
bottomRightRadius: rightOpen ? pillHeight * 0.5 : 0
readonly property int halfPillHeight: Math.round(pillHeight * 0.5)
topLeftRadius: rightOpen ? 0 : halfPillHeight
bottomLeftRadius: rightOpen ? 0 : halfPillHeight
topRightRadius: rightOpen ? halfPillHeight : 0
bottomRightRadius: rightOpen ? halfPillHeight : 0
anchors.verticalCenter: parent.verticalCenter
NText {
@@ -80,16 +97,17 @@ Item {
x: {
// Better text horizontal centering
var centerX = (parent.width - width) / 2
var offset = rightOpen ? Style.marginXS * scaling : -Style.marginXS * scaling
var offset = rightOpen ? Style.marginXS : -Style.marginXS
if (forceOpen) {
// If its force open, the icon disc background is the same color as the bg pill move text slightly
offset += rightOpen ? -Style.marginXXS * scaling : Style.marginXXS * scaling
offset += rightOpen ? -Style.marginXXS : Style.marginXXS
}
return centerX + offset
}
text: root.text + root.suffix
family: Settings.data.ui.fontFixed
pointSize: textSize
applyUiScale: false
font.weight: Style.fontWeightBold
color: forceOpen ? Color.mOnSurface : Color.mPrimary
visible: revealed
@@ -131,6 +149,7 @@ Item {
NIcon {
icon: root.icon
pointSize: iconSize
applyUiScale: false
color: hovered ? Color.mOnTertiary : Color.mOnSurface
// Center horizontally
x: (iconCircle.width - width) / 2
+32 -13
View File
@@ -12,13 +12,13 @@ Item {
property string text: ""
property string suffix: ""
property string tooltipText: ""
property string density: ""
property bool autoHide: false
property bool forceOpen: false
property bool forceClose: false
property bool disableOpen: false
property bool rightOpen: false
property bool hovered: false
property bool compact: false
// Bar position detection for pill direction
readonly property string barPosition: Settings.data.bar.position
@@ -45,15 +45,30 @@ Item {
property bool shouldAnimateHide: false
// Sizing logic for vertical bars
readonly property int buttonSize: Math.round(Style.capsuleHeight * scaling)
readonly property int buttonSize: Style.capsuleHeight
readonly property int pillHeight: buttonSize
readonly property int pillPaddingVertical: 3 * 2 * scaling // Very precise adjustment don't replace by Style.margin
readonly property int pillOverlap: buttonSize * 0.5
readonly property int pillPaddingVertical: 3 * 2 // Very precise adjustment don't replace by Style.margin
readonly property int pillOverlap: Math.round(buttonSize * 0.5)
readonly property int maxPillWidth: buttonSize
readonly property int maxPillHeight: Math.max(1, textItem.implicitHeight + pillPaddingVertical * 4)
readonly property int maxPillHeight: Math.max(1, Math.round(textItem.implicitHeight + pillPaddingVertical * 4))
readonly property real iconSize: Math.max(1, compact ? pillHeight * 0.65 : pillHeight * 0.48)
readonly property real textSize: Math.max(1, compact ? pillHeight * 0.38 : pillHeight * 0.33)
readonly property real iconSize: {
switch (root.density) {
case "compact":
return Math.max(1, Math.round(pillHeight * 0.65))
default:
return Math.max(1, Math.round(pillHeight * 0.48))
}
}
readonly property real textSize: {
switch (root.density) {
case "compact":
return Math.max(1, Math.round(pillHeight * 0.38))
default:
return Math.max(1, Math.round(pillHeight * 0.33))
}
}
// For vertical bars: width is just icon size, height includes pill space
width: buttonSize
@@ -79,11 +94,13 @@ Item {
opacity: revealed ? Style.opacityFull : Style.opacityNone
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
readonly property int halfButtonSize: Math.round(buttonSize * 0.5)
// Radius logic for vertical expansion - rounded on the side that connects to icon
topLeftRadius: openUpward ? buttonSize * 0.5 : 0
bottomLeftRadius: openDownward ? buttonSize * 0.5 : 0
topRightRadius: openUpward ? buttonSize * 0.5 : 0
bottomRightRadius: openDownward ? buttonSize * 0.5 : 0
topLeftRadius: openUpward ? halfButtonSize : 0
bottomLeftRadius: openDownward ? halfButtonSize : 0
topRightRadius: openUpward ? halfButtonSize : 0
bottomRightRadius: openDownward ? halfButtonSize : 0
anchors.horizontalCenter: parent.horizontalCenter
@@ -92,16 +109,17 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: {
var offset = openDownward ? pillPaddingVertical * 0.75 : -pillPaddingVertical * 0.75
var offset = openDownward ? Math.round(pillPaddingVertical * 0.75) : -Math.round(pillPaddingVertical * 0.75)
if (forceOpen) {
// If its force open, the icon disc background is the same color as the bg pill move text slightly
offset += rightOpen ? -Style.marginXXS * scaling : Style.marginXXS * scaling
offset += rightOpen ? -Style.marginXXS : Style.marginXXS
}
return offset
}
text: root.text + root.suffix
family: Settings.data.ui.fontFixed
pointSize: textSize
applyUiScale: false
font.weight: Style.fontWeightMedium
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
@@ -154,6 +172,7 @@ Item {
NIcon {
icon: root.icon
pointSize: iconSize
applyUiScale: false
color: hovered ? Color.mOnTertiary : Color.mOnSurface
// Center horizontally
x: (iconCircle.width - width) / 2
+2 -12
View File
@@ -16,18 +16,8 @@ Item {
implicitWidth: getImplicitSize(loader.item, "implicitWidth")
implicitHeight: getImplicitSize(loader.item, "implicitHeight")
Connections {
target: ScalingService
enabled: loader.item && (loader.item.screen !== undefined)
function onScaleChanged(aScreenName, scale) {
if (loader.item && loader.item.screen && aScreenName === screenName) {
loader.item['scaling'] = scale
}
}
}
function getImplicitSize(item, prop) {
return (item && item.visible) ? item[prop] : 0
return (item && item.visible) ? Math.round(item[prop]) : 0
}
Loader {
@@ -77,7 +67,7 @@ Item {
// Error handling
onWidgetIdChanged: {
if (widgetId && !BarWidgetRegistry.hasWidget(widgetId)) {
Logger.warn("BarWidgetLoader", "Widget not found in bar registry:", widgetId)
Logger.warn("BarWidgetLoader", "Widget not found in registry:", widgetId)
}
}
}
+20 -29
View File
@@ -15,23 +15,13 @@ PopupWindow {
property bool isSubMenu: false
property bool isHovered: rootMouseArea.containsMouse
property ShellScreen screen
property real scaling: ScalingService.getScreenScale(screen)
Connections {
target: ScalingService
function onScaleChanged(screenName, scale) {
if ((screen != null) && (screenName === screen.name)) {
scaling = scale
}
}
}
readonly property int menuWidth: 180
implicitWidth: menuWidth * scaling
implicitWidth: menuWidth
// Use the content height of the Flickable for implicit height
implicitHeight: Math.min(screen ? screen.height * 0.9 : Screen.height * 0.9, flickable.contentHeight + (Style.marginS * 2 * scaling))
implicitHeight: Math.min(screen ? screen.height * 0.9 : Screen.height * 0.9, flickable.contentHeight + (Style.marginS * 2))
visible: false
color: Color.transparent
anchor.item: anchorItem
@@ -98,14 +88,14 @@ PopupWindow {
anchors.fill: parent
color: Color.mSurface
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
radius: Style.radiusM * scaling
border.width: Math.max(1, Style.borderS)
radius: Style.radiusM
}
Flickable {
id: flickable
anchors.fill: parent
anchors.margins: Style.marginS * scaling
anchors.margins: Style.marginS
contentHeight: columnLayout.implicitHeight
interactive: true
@@ -125,11 +115,11 @@ PopupWindow {
Layout.preferredWidth: parent.width
Layout.preferredHeight: {
if (modelData?.isSeparator) {
return 8 * scaling
return 8
} else {
// Calculate based on text content
const textHeight = text.contentHeight || (Style.fontSizeS * scaling * 1.2)
return Math.max(28 * scaling, textHeight + (Style.marginS * 2 * scaling))
const textHeight = text.contentHeight || (Style.fontSizeS * 1.2)
return Math.max(28, textHeight + (Style.marginS * 2))
}
}
@@ -138,35 +128,35 @@ PopupWindow {
NDivider {
anchors.centerIn: parent
width: parent.width - (Style.marginM * scaling * 2)
width: parent.width - (Style.marginM * 2)
visible: modelData?.isSeparator ?? false
}
Rectangle {
anchors.fill: parent
color: mouseArea.containsMouse ? Color.mTertiary : Color.transparent
radius: Style.radiusS * scaling
radius: Style.radiusS
visible: !(modelData?.isSeparator ?? false)
RowLayout {
anchors.fill: parent
anchors.leftMargin: Style.marginM * scaling
anchors.rightMargin: Style.marginM * scaling
spacing: Style.marginS * scaling
anchors.leftMargin: Style.marginM
anchors.rightMargin: Style.marginM
spacing: Style.marginS
NText {
id: text
Layout.fillWidth: true
color: (modelData?.enabled ?? true) ? (mouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface) : Color.mOnSurfaceVariant
text: modelData?.text !== "" ? modelData?.text.replace(/[\n\r]+/g, ' ') : "..."
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
}
Image {
Layout.preferredWidth: Style.marginL * scaling
Layout.preferredHeight: Style.marginL * scaling
Layout.preferredWidth: Style.marginL
Layout.preferredHeight: Style.marginL
source: modelData?.icon ?? ""
visible: (modelData?.icon ?? "") !== ""
fillMode: Image.PreserveAspectFit
@@ -174,7 +164,8 @@ PopupWindow {
NIcon {
icon: modelData?.hasChildren ? "menu" : ""
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
applyUiScale: false
verticalAlignment: Text.AlignVCenter
visible: modelData?.hasChildren ?? false
color: (mouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface)
@@ -216,8 +207,8 @@ PopupWindow {
}
// Need a slight overlap so that menu don't close when moving the mouse to a submenu
const submenuWidth = menuWidth * scaling // Assuming a similar width as the parent
const overlap = 4 * scaling // A small overlap to bridge the mouse path
const submenuWidth = menuWidth // Assuming a similar width as the parent
const overlap = 4 // A small overlap to bridge the mouse path
// Determine submenu opening direction based on bar position and available space
let openLeft = false
+78 -78
View File
@@ -10,8 +10,8 @@ import qs.Widgets
NPanel {
id: root
preferredWidth: 400
preferredHeight: 500
preferredWidth: 400 * Style.uiScaleRatio
preferredHeight: 500 * Style.uiScaleRatio
panelKeyboardFocus: true
property string passwordSsid: ""
@@ -25,23 +25,23 @@ NPanel {
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginL * scaling
spacing: Style.marginM * scaling
anchors.margins: Style.marginL
spacing: Style.marginM
// Header
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM * scaling
spacing: Style.marginM
NIcon {
icon: Settings.data.network.wifiEnabled ? "wifi" : "wifi-off"
pointSize: Style.fontSizeXXL * scaling
pointSize: Style.fontSizeXXL
color: Settings.data.network.wifiEnabled ? Color.mPrimary : Color.mOnSurfaceVariant
}
NText {
text: I18n.tr("wifi.panel.title")
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.fillWidth: true
@@ -51,7 +51,7 @@ NPanel {
id: wifiSwitch
checked: Settings.data.network.wifiEnabled
onToggled: checked => NetworkService.setWifiEnabled(checked)
baseSize: Style.baseWidgetSize * 0.65 * scaling
baseSize: Style.baseWidgetSize * 0.65
}
NIconButton {
@@ -78,28 +78,28 @@ NPanel {
Rectangle {
visible: NetworkService.lastError.length > 0
Layout.fillWidth: true
Layout.preferredHeight: errorRow.implicitHeight + (Style.marginM * scaling * 2)
Layout.preferredHeight: errorRow.implicitHeight + (Style.marginM * 2)
color: Qt.rgba(Color.mError.r, Color.mError.g, Color.mError.b, 0.1)
radius: Style.radiusS * scaling
border.width: Math.max(1, Style.borderS * scaling)
radius: Style.radiusS
border.width: Math.max(1, Style.borderS)
border.color: Color.mError
RowLayout {
id: errorRow
anchors.fill: parent
anchors.margins: Style.marginM * scaling
spacing: Style.marginS * scaling
anchors.margins: Style.marginM
spacing: Style.marginS
NIcon {
icon: "warning"
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
color: Color.mError
}
NText {
text: NetworkService.lastError
color: Color.mError
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
wrapMode: Text.Wrap
Layout.fillWidth: true
}
@@ -122,7 +122,7 @@ NPanel {
ColumnLayout {
visible: !Settings.data.network.wifiEnabled
anchors.fill: parent
spacing: Style.marginM * scaling
spacing: Style.marginM
Item {
Layout.fillHeight: true
@@ -130,21 +130,21 @@ NPanel {
NIcon {
icon: "wifi-off"
pointSize: 64 * scaling
pointSize: 64
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("wifi.panel.disabled")
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("wifi.panel.enable-message")
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
@@ -158,7 +158,7 @@ NPanel {
ColumnLayout {
visible: Settings.data.network.wifiEnabled && NetworkService.scanning && Object.keys(NetworkService.networks).length === 0
anchors.fill: parent
spacing: Style.marginL * scaling
spacing: Style.marginL
Item {
Layout.fillHeight: true
@@ -167,13 +167,13 @@ NPanel {
NBusyIndicator {
running: true
color: Color.mPrimary
size: Style.baseWidgetSize * scaling
size: Style.baseWidgetSize
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("wifi.panel.searching")
pointSize: Style.fontSizeNormal * scaling
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
@@ -193,7 +193,7 @@ NPanel {
ColumnLayout {
width: parent.width
spacing: Style.marginM * scaling
spacing: Style.marginM
// Network list
Repeater {
@@ -211,14 +211,14 @@ NPanel {
Rectangle {
Layout.fillWidth: true
implicitHeight: netColumn.implicitHeight + (Style.marginM * scaling * 2)
radius: Style.radiusM * scaling
implicitHeight: netColumn.implicitHeight + (Style.marginM * 2)
radius: Style.radiusM
// Add opacity for operations in progress
opacity: (NetworkService.disconnectingFrom === modelData.ssid || NetworkService.forgettingNetwork === modelData.ssid) ? 0.6 : 1.0
color: modelData.connected ? Qt.rgba(Color.mPrimary.r, Color.mPrimary.g, Color.mPrimary.b, 0.05) : Color.mSurface
border.width: Math.max(1, Style.borderS * scaling)
border.width: Math.max(1, Style.borderS)
border.color: modelData.connected ? Color.mPrimary : Color.mOutline
// Smooth opacity animation
@@ -230,29 +230,29 @@ NPanel {
ColumnLayout {
id: netColumn
width: parent.width - (Style.marginM * scaling * 2)
x: Style.marginM * scaling
y: Style.marginM * scaling
spacing: Style.marginS * scaling
width: parent.width - (Style.marginM * 2)
x: Style.marginM
y: Style.marginM
spacing: Style.marginS
// Main row
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS * scaling
spacing: Style.marginS
NIcon {
icon: NetworkService.signalIcon(modelData.signal)
pointSize: Style.fontSizeXXL * scaling
pointSize: Style.fontSizeXXL
color: modelData.connected ? Color.mPrimary : Color.mOnSurface
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2 * scaling
spacing: 2
NText {
text: modelData.ssid
pointSize: Style.fontSizeNormal * scaling
pointSize: Style.fontSizeM
font.weight: modelData.connected ? Style.fontWeightBold : Style.fontWeightMedium
color: Color.mOnSurface
elide: Text.ElideRight
@@ -260,30 +260,30 @@ NPanel {
}
RowLayout {
spacing: Style.marginXS * scaling
spacing: Style.marginXS
NText {
text: I18n.tr("system.signal-strength", {
"signal": modelData.signal
})
pointSize: Style.fontSizeXXS * scaling
pointSize: Style.fontSizeXXS
color: Color.mOnSurfaceVariant
}
NText {
text: "•"
pointSize: Style.fontSizeXXS * scaling
pointSize: Style.fontSizeXXS
color: Color.mOnSurfaceVariant
}
NText {
text: NetworkService.isSecured(modelData.security) ? modelData.security : "Open"
pointSize: Style.fontSizeXXS * scaling
pointSize: Style.fontSizeXXS
color: Color.mOnSurfaceVariant
}
Item {
Layout.preferredWidth: Style.marginXXS * scaling
Layout.preferredWidth: Style.marginXXS
}
// Update the status badges area (around line 237)
@@ -291,14 +291,14 @@ NPanel {
visible: modelData.connected && NetworkService.disconnectingFrom !== modelData.ssid
color: Color.mPrimary
radius: height * 0.5
width: connectedText.implicitWidth + (Style.marginS * scaling * 2)
height: connectedText.implicitHeight + (Style.marginXXS * scaling * 2)
width: connectedText.implicitWidth + (Style.marginS * 2)
height: connectedText.implicitHeight + (Style.marginXXS * 2)
NText {
id: connectedText
anchors.centerIn: parent
text: I18n.tr("wifi.panel.connected")
pointSize: Style.fontSizeXXS * scaling
pointSize: Style.fontSizeXXS
color: Color.mOnPrimary
}
}
@@ -307,14 +307,14 @@ NPanel {
visible: NetworkService.disconnectingFrom === modelData.ssid
color: Color.mError
radius: height * 0.5
width: disconnectingText.implicitWidth + (Style.marginS * scaling * 2)
height: disconnectingText.implicitHeight + (Style.marginXXS * scaling * 2)
width: disconnectingText.implicitWidth + (Style.marginS * 2)
height: disconnectingText.implicitHeight + (Style.marginXXS * 2)
NText {
id: disconnectingText
anchors.centerIn: parent
text: I18n.tr("wifi.panel.disconnecting")
pointSize: Style.fontSizeXXS * scaling
pointSize: Style.fontSizeXXS
color: Color.mOnPrimary
}
}
@@ -323,14 +323,14 @@ NPanel {
visible: NetworkService.forgettingNetwork === modelData.ssid
color: Color.mError
radius: height * 0.5
width: forgettingText.implicitWidth + (Style.marginS * scaling * 2)
height: forgettingText.implicitHeight + (Style.marginXXS * scaling * 2)
width: forgettingText.implicitWidth + (Style.marginS * 2)
height: forgettingText.implicitHeight + (Style.marginXXS * 2)
NText {
id: forgettingText
anchors.centerIn: parent
text: I18n.tr("wifi.panel.forgetting")
pointSize: Style.fontSizeXXS * scaling
pointSize: Style.fontSizeXXS
color: Color.mOnPrimary
}
}
@@ -339,16 +339,16 @@ NPanel {
visible: modelData.cached && !modelData.connected && NetworkService.forgettingNetwork !== modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid
color: Color.transparent
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
border.width: Math.max(1, Style.borderS)
radius: height * 0.5
width: savedText.implicitWidth + (Style.marginS * scaling * 2)
height: savedText.implicitHeight + (Style.marginXXS * scaling * 2)
width: savedText.implicitWidth + (Style.marginS * 2)
height: savedText.implicitHeight + (Style.marginXXS * 2)
NText {
id: savedText
anchors.centerIn: parent
text: I18n.tr("wifi.panel.saved")
pointSize: Style.fontSizeXXS * scaling
pointSize: Style.fontSizeXXS
color: Color.mOnSurfaceVariant
}
}
@@ -357,13 +357,13 @@ NPanel {
// Action area
RowLayout {
spacing: Style.marginS * scaling
spacing: Style.marginS
NBusyIndicator {
visible: NetworkService.connectingTo === modelData.ssid || NetworkService.disconnectingFrom === modelData.ssid || NetworkService.forgettingNetwork === modelData.ssid
running: visible
color: Color.mPrimary
size: Style.baseWidgetSize * 0.5 * scaling
size: Style.baseWidgetSize * 0.5
}
NIconButton {
@@ -384,7 +384,7 @@ NPanel {
return I18n.tr("wifi.panel.password")
}
outlined: !hovered
fontSize: Style.fontSizeXS * scaling
fontSize: Style.fontSizeXS
enabled: !NetworkService.connecting
onClicked: {
if (modelData.existing || modelData.cached || !NetworkService.isSecured(modelData.security)) {
@@ -401,7 +401,7 @@ NPanel {
visible: modelData.connected && NetworkService.disconnectingFrom !== modelData.ssid
text: I18n.tr("wifi.panel.disconnect")
outlined: !hovered
fontSize: Style.fontSizeXS * scaling
fontSize: Style.fontSizeXS
backgroundColor: Color.mError
onClicked: NetworkService.disconnect(modelData.ssid)
}
@@ -412,35 +412,35 @@ NPanel {
Rectangle {
visible: passwordSsid === modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid && NetworkService.forgettingNetwork !== modelData.ssid
Layout.fillWidth: true
height: passwordRow.implicitHeight + Style.marginS * scaling * 2
height: passwordRow.implicitHeight + Style.marginS * 2
color: Color.mSurfaceVariant
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
radius: Style.radiusS * scaling
border.width: Math.max(1, Style.borderS)
radius: Style.radiusS
RowLayout {
id: passwordRow
anchors.fill: parent
anchors.margins: Style.marginS * scaling
spacing: Style.marginM * scaling
anchors.margins: Style.marginS
spacing: Style.marginM
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
radius: Style.radiusXS * scaling
radius: Style.radiusXS
color: Color.mSurface
border.color: pwdInput.activeFocus ? Color.mSecondary : Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
border.width: Math.max(1, Style.borderS)
TextInput {
id: pwdInput
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Style.marginS * scaling
anchors.margins: Style.marginS
text: passwordInput
font.family: Settings.data.ui.fontFixed
font.pointSize: Style.fontSizeS * scaling
font.pointSize: Style.fontSizeS
color: Color.mOnSurface
echoMode: TextInput.Password
selectByMouse: true
@@ -462,14 +462,14 @@ NPanel {
anchors.verticalCenter: parent.verticalCenter
text: I18n.tr("wifi.panel.enter-password")
color: Color.mOnSurfaceVariant
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
}
}
}
NButton {
text: I18n.tr("wifi.panel.connect")
fontSize: Style.fontSizeXXS * scaling
fontSize: Style.fontSizeXXS
enabled: passwordInput.length > 0 && !NetworkService.connecting
outlined: true
onClicked: {
@@ -494,28 +494,28 @@ NPanel {
Rectangle {
visible: expandedSsid === modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid && NetworkService.forgettingNetwork !== modelData.ssid
Layout.fillWidth: true
height: forgetRow.implicitHeight + Style.marginS * 2 * scaling
height: forgetRow.implicitHeight + Style.marginS * 2
color: Color.mSurfaceVariant
radius: Style.radiusS * scaling
border.width: Math.max(1, Style.borderS * scaling)
radius: Style.radiusS
border.width: Math.max(1, Style.borderS)
border.color: Color.mOutline
RowLayout {
id: forgetRow
anchors.fill: parent
anchors.margins: Style.marginS * scaling
spacing: Style.marginM * scaling
anchors.margins: Style.marginS
spacing: Style.marginM
RowLayout {
NIcon {
icon: "trash"
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
color: Color.mError
}
NText {
text: I18n.tr("wifi.panel.forget-network")
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
color: Color.mError
Layout.fillWidth: true
}
@@ -524,7 +524,7 @@ NPanel {
NButton {
id: forgetButton
text: I18n.tr("wifi.panel.forget")
fontSize: Style.fontSizeXXS * scaling
fontSize: Style.fontSizeXXS
backgroundColor: Color.mError
outlined: forgetButton.hovered ? false : true
onClicked: {
@@ -550,7 +550,7 @@ NPanel {
ColumnLayout {
visible: Settings.data.network.wifiEnabled && !NetworkService.scanning && Object.keys(NetworkService.networks).length === 0
anchors.fill: parent
spacing: Style.marginL * scaling
spacing: Style.marginL
Item {
Layout.fillHeight: true
@@ -558,14 +558,14 @@ NPanel {
NIcon {
icon: "search"
pointSize: 64 * scaling
pointSize: 64
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("wifi.panel.no-networks")
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
+59 -36
View File
@@ -10,8 +10,8 @@ import qs.Widgets
Item {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -30,23 +30,23 @@ Item {
return {}
}
readonly property bool hasActiveWindow: CompositorService.getFocusedWindowTitle() !== ""
readonly property string windowTitle: CompositorService.getFocusedWindowTitle() || "No active window"
readonly property string fallbackIcon: "user-desktop"
readonly property string barPosition: Settings.data.bar.position
readonly property bool compact: (Settings.data.bar.density === "compact")
// Widget settings - matching MediaMini pattern
readonly property bool showIcon: (widgetSettings.showIcon !== undefined) ? widgetSettings.showIcon : widgetMetadata.showIcon
readonly property bool autoHide: (widgetSettings.autoHide !== undefined) ? widgetSettings.autoHide : widgetMetadata.autoHide
readonly property string hideMode: (widgetSettings.hideMode !== undefined) ? widgetSettings.hideMode : widgetMetadata.hideMode
readonly property string scrollingMode: (widgetSettings.scrollingMode !== undefined) ? widgetSettings.scrollingMode : (widgetMetadata.scrollingMode !== undefined ? widgetMetadata.scrollingMode : "hover")
readonly property int widgetWidth: (widgetSettings.width !== undefined) ? widgetSettings.width : Math.max(widgetMetadata.width, screen.width * 0.06)
implicitHeight: visible ? ((barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling)) : 0
implicitWidth: visible ? ((barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (widgetWidth * scaling)) : 0
readonly property bool isVerticalBar: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right")
readonly property bool hasFocusedWindow: CompositorService.getFocusedWindow() !== null
readonly property string windowTitle: CompositorService.getFocusedWindowTitle() || "No active window"
readonly property string fallbackIcon: "user-desktop"
opacity: !autoHide || hasActiveWindow ? 1.0 : 0
implicitHeight: visible ? (isVerticalBar ? calculatedVerticalDimension() : Style.barHeight) : 0
implicitWidth: visible ? (isVerticalBar ? calculatedVerticalDimension() : widgetWidth) : 0
// "visible": Always Visible, "hidden": Hide When Empty, "transparent": Transparent When Empty
visible: hideMode !== "hidden" || hasFocusedWindow
opacity: hideMode !== "transparent" || hasFocusedWindow ? 1.0 : 0
Behavior on opacity {
NumberAnimation {
duration: Style.animationNormal
@@ -54,8 +54,9 @@ Item {
}
}
function calculatedVerticalHeight() {
return Math.round(Style.baseWidgetSize * 0.8 * scaling)
function calculatedVerticalDimension() {
const ratio = (Settings.data.bar.density === "mini") ? 0.67 : 0.8
return Math.round(Style.baseWidgetSize * ratio)
}
function getAppIcon() {
@@ -106,7 +107,8 @@ Item {
id: fullTitleMetrics
visible: false
text: windowTitle
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
applyUiScale: false
font.weight: Style.fontWeightMedium
}
@@ -115,29 +117,29 @@ Item {
visible: root.visible
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (widgetWidth * scaling)
height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : Math.round(Style.capsuleHeight * scaling)
radius: (barPosition === "left" || barPosition === "right") ? width / 2 : Math.round(Style.radiusM * scaling)
width: isVerticalBar ? root.width : widgetWidth
height: isVerticalBar ? width : Style.capsuleHeight
radius: isVerticalBar ? width / 2 : Style.radiusM
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
Item {
id: mainContainer
anchors.fill: parent
anchors.leftMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS * scaling
anchors.rightMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS * scaling
anchors.leftMargin: isVerticalBar ? 0 : Style.marginS
anchors.rightMargin: isVerticalBar ? 0 : Style.marginS
// Horizontal layout for top/bottom bars
RowLayout {
id: rowLayout
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS * scaling
visible: barPosition === "top" || barPosition === "bottom"
spacing: Style.marginS
visible: !isVerticalBar
z: 1
// Window icon
Item {
Layout.preferredWidth: Math.round(18 * scaling)
Layout.preferredHeight: Math.round(18 * scaling)
Layout.preferredWidth: 18
Layout.preferredHeight: 18
Layout.alignment: Qt.AlignVCenter
visible: showIcon
@@ -148,6 +150,15 @@ Item {
asynchronous: true
smooth: true
visible: source !== ""
// Apply dock shader to active window icon (always themed)
layer.enabled: widgetSettings.colorizeIcons !== false
layer.effect: ShaderEffect {
property color targetColor: Color.mOnSurface
property real colorizeMode: 0.0 // Dock mode (grayscale)
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
}
}
}
@@ -156,10 +167,10 @@ Item {
id: titleContainer
Layout.preferredWidth: {
// Calculate available width based on other elements
var iconWidth = (showIcon && windowIcon.visible ? (18 * scaling + Style.marginS * scaling) : 0)
var totalMargins = Style.marginXXS * scaling * 2
var iconWidth = (showIcon && windowIcon.visible ? (18 + Style.marginS) : 0)
var totalMargins = Style.marginXXS * 2
var availableWidth = mainContainer.width - iconWidth - totalMargins
return Math.max(20 * scaling, availableWidth)
return Math.max(20, availableWidth)
}
Layout.maximumWidth: Layout.preferredWidth
Layout.alignment: Qt.AlignVCenter
@@ -238,12 +249,13 @@ Item {
x: scrollX
RowLayout {
spacing: 50 * scaling // Gap between text copies
spacing: 50 // Gap between text copies
NText {
id: titleText
text: windowTitle
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
applyUiScale: false
font.weight: Style.fontWeightMedium
verticalAlignment: Text.AlignVCenter
color: Color.mOnSurface
@@ -253,6 +265,8 @@ Item {
NText {
text: windowTitle
font: titleText.font
pointSize: Style.fontSizeS
applyUiScale: false
verticalAlignment: Text.AlignVCenter
color: Color.mOnSurface
visible: titleContainer.needsScrolling && titleContainer.isScrolling
@@ -275,7 +289,7 @@ Item {
id: infiniteScroll
running: titleContainer.isScrolling && !titleContainer.isResetting
from: 0
to: -(titleContainer.textWidth + 50 * scaling)
to: -(titleContainer.textWidth + 50)
duration: Math.max(4000, windowTitle.length * 100)
loops: Animation.Infinite
easing.type: Easing.Linear
@@ -295,15 +309,15 @@ Item {
Item {
id: verticalLayout
anchors.centerIn: parent
width: parent.width - Style.marginM * scaling * 2
height: parent.height - Style.marginM * scaling * 2
visible: barPosition === "left" || barPosition === "right"
width: parent.width - Style.marginM * 2
height: parent.height - Style.marginM * 2
visible: isVerticalBar
z: 1
// Window icon
Item {
width: Style.baseWidgetSize * 0.5 * scaling
height: Style.baseWidgetSize * 0.5 * scaling
width: Style.baseWidgetSize * 0.5
height: width
anchors.centerIn: parent
visible: windowTitle !== ""
@@ -314,6 +328,15 @@ Item {
asynchronous: true
smooth: true
visible: source !== ""
// Apply dock shader to active window icon (always themed)
layer.enabled: widgetSettings.colorizeIcons !== false
layer.effect: ShaderEffect {
property color targetColor: Color.mOnSurface
property real colorizeMode: 0.0 // Dock mode (grayscale)
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
}
}
}
}
@@ -326,7 +349,7 @@ Item {
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onEntered: {
if ((windowTitle !== "") && (barPosition === "left" || barPosition === "right") || (scrollingMode === "never")) {
if ((windowTitle !== "") && isVerticalBar || (scrollingMode === "never")) {
TooltipService.show(Screen, root, windowTitle, BarService.getTooltipDirection())
}
}
+1 -2
View File
@@ -11,7 +11,6 @@ Item {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -87,7 +86,7 @@ Item {
BarPill {
id: pill
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
rightOpen: BarService.getPillDirection(root)
icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent, charging, isReady)
text: (isReady || testMode) ? Math.round(percent) : "-"
+3 -2
View File
@@ -10,10 +10,11 @@ import qs.Widgets
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
baseSize: Style.capsuleHeight
compact: (Settings.data.bar.density === "compact")
applyUiScale: false
density: Settings.data.bar.density
colorBg: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
colorFg: Color.mOnSurface
colorBorder: Color.transparent
+1 -2
View File
@@ -10,7 +10,6 @@ Item {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -77,7 +76,7 @@ Item {
BarPill {
id: pill
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
rightOpen: BarService.getPillDirection(root)
icon: getIcon()
autoHide: false // Important to be false so we can hover as long as we want
+11 -10
View File
@@ -9,7 +9,6 @@ Rectangle {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -30,7 +29,7 @@ Rectangle {
readonly property string barPosition: Settings.data.bar.position
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
readonly property bool compact: (Settings.data.bar.density === "compact")
readonly property bool density: Settings.data.bar.density
readonly property var now: Time.date
@@ -41,11 +40,11 @@ Rectangle {
readonly property string formatHorizontal: widgetSettings.formatHorizontal !== undefined ? widgetSettings.formatHorizontal : widgetMetadata.formatHorizontal
readonly property string formatVertical: widgetSettings.formatVertical !== undefined ? widgetSettings.formatVertical : widgetMetadata.formatVertical
implicitWidth: isBarVertical ? Math.round(Style.capsuleHeight * scaling) : Math.round((isBarVertical ? verticalLoader.implicitWidth : horizontalLoader.implicitWidth) + Style.marginM * 2 * scaling)
implicitWidth: isBarVertical ? Style.capsuleHeight : Math.round((isBarVertical ? verticalLoader.implicitWidth : horizontalLoader.implicitWidth) + Style.marginM * 2)
implicitHeight: isBarVertical ? Math.round(verticalLoader.implicitHeight + Style.marginS * 2 * scaling) : Math.round(Style.capsuleHeight * scaling)
implicitHeight: isBarVertical ? Math.round(verticalLoader.implicitHeight + Style.marginS * 2) : Style.capsuleHeight
radius: Math.round(Style.radiusS * scaling)
radius: Style.radiusS
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
Item {
@@ -59,7 +58,7 @@ Rectangle {
anchors.centerIn: parent
sourceComponent: ColumnLayout {
anchors.centerIn: parent
spacing: Settings.data.bar.showCapsule ? -4 * scaling : -2 * scaling
spacing: Settings.data.bar.showCapsule ? -4 : -2
Repeater {
id: repeater
model: Qt.locale().toString(now, formatHorizontal.trim()).split("\\n")
@@ -69,11 +68,12 @@ Rectangle {
family: useCustomFont && customFont ? customFont : Settings.data.ui.fontDefault
pointSize: {
if (repeater.model.length == 1) {
return Style.fontSizeS * scaling
return Style.fontSizeS
} else {
return (index == 0) ? Style.fontSizeXS * scaling : Style.fontSizeXXS * scaling
return (index == 0) ? Style.fontSizeXS : Style.fontSizeXXS
}
}
applyUiScale: false
font.weight: Style.fontWeightBold
color: usePrimaryColor ? Color.mPrimary : Color.mOnSurface
wrapMode: Text.WordWrap
@@ -90,14 +90,15 @@ Rectangle {
anchors.centerIn: parent // Now this works without layout conflicts
sourceComponent: ColumnLayout {
anchors.centerIn: parent
spacing: -2 * scaling
spacing: -2
Repeater {
model: Qt.locale().toString(now, formatVertical.trim()).split(" ")
delegate: NText {
visible: text !== ""
text: modelData
family: useCustomFont && customFont ? customFont : Settings.data.ui.fontDefault
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
applyUiScale: false
font.weight: Style.fontWeightBold
color: usePrimaryColor ? Color.mPrimary : Color.mOnSurface
wrapMode: Text.WordWrap
+3 -2
View File
@@ -9,7 +9,7 @@ import qs.Services
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -37,7 +37,8 @@ NIconButton {
tooltipText: I18n.tr("tooltips.open-control-center")
tooltipDirection: BarService.getTooltipDirection()
baseSize: Style.capsuleHeight
compact: (Settings.data.bar.density === "compact")
applyUiScale: false
density: Settings.data.bar.density
colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
colorFg: Color.mOnSurface
colorBgHover: useDistroLogo ? Color.mSurfaceVariant : Color.mTertiary
+2 -4
View File
@@ -11,9 +11,7 @@ import qs.Modules.Bar.Extras
Item {
id: root
// Widget properties passed from Bar.qml
property var screen
property real scaling: 1.0
property ShellScreen screen
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -50,7 +48,7 @@ Item {
rightOpen: BarService.getPillDirection(root)
icon: customIcon
text: _dynamicText
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
autoHide: false
forceOpen: _dynamicText !== ""
forceClose: false
+3 -2
View File
@@ -6,13 +6,14 @@ import qs.Services
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
icon: "dark-mode"
tooltipText: Settings.data.colorSchemes.darkMode ? I18n.tr("tooltips.switch-to-light-mode") : I18n.tr("tooltips.switch-to-dark-mode")
tooltipDirection: BarService.getTooltipDirection()
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
baseSize: Style.capsuleHeight
applyUiScale: false
colorBg: Settings.data.colorSchemes.darkMode ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary
colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary
colorBorder: Color.transparent
+3 -2
View File
@@ -8,10 +8,11 @@ import qs.Widgets
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
baseSize: Style.capsuleHeight
compact: (Settings.data.bar.density === "compact")
applyUiScale: false
density: Settings.data.bar.density
icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off"
tooltipText: IdleInhibitorService.isInhibited ? I18n.tr("tooltips.disable-keep-awake") : I18n.tr("tooltips.enable-keep-awake")
tooltipDirection: BarService.getTooltipDirection()
+1 -2
View File
@@ -12,7 +12,6 @@ Item {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -43,7 +42,7 @@ Item {
id: pill
anchors.verticalCenter: parent.verticalCenter
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
rightOpen: BarService.getPillDirection(root)
icon: "keyboard"
autoHide: false // Important to be false so we can hover as long as we want
+45 -41
View File
@@ -11,7 +11,6 @@ Item {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -30,10 +29,9 @@ Item {
return {}
}
readonly property string barPosition: Settings.data.bar.position
readonly property bool compact: (Settings.data.bar.density === "compact")
readonly property bool isVerticalBar: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right")
readonly property bool autoHide: (widgetSettings.autoHide !== undefined) ? widgetSettings.autoHide : widgetMetadata.autoHide
readonly property string hideMode: (widgetSettings.hideMode !== undefined) ? widgetSettings.hideMode : "hidden" // "visible", "hidden", "transparent"
readonly property bool showAlbumArt: (widgetSettings.showAlbumArt !== undefined) ? widgetSettings.showAlbumArt : widgetMetadata.showAlbumArt
readonly property bool showVisualizer: (widgetSettings.showVisualizer !== undefined) ? widgetSettings.showVisualizer : widgetMetadata.showVisualizer
readonly property string visualizerType: (widgetSettings.visualizerType !== undefined && widgetSettings.visualizerType !== "") ? widgetSettings.visualizerType : widgetMetadata.visualizerType
@@ -42,7 +40,7 @@ Item {
// Fixed width - no expansion
readonly property real widgetWidth: Math.max(145, screen.width * 0.06)
readonly property bool hasActivePlayer: MediaService.currentPlayer !== null && getTitle() !== ""
readonly property bool hasActivePlayer: MediaService.currentPlayer !== null
readonly property string placeholderText: I18n.tr("bar.widget-settings.media-mini.no-active-player")
readonly property string tooltipText: {
@@ -60,10 +58,12 @@ Item {
return title
}
implicitHeight: visible ? ((barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling)) : 0
implicitWidth: visible ? ((barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (widgetWidth * scaling)) : 0
implicitHeight: visible ? (isVerticalBar ? calculatedVerticalDimension() : Style.barHeight) : 0
implicitWidth: visible ? (isVerticalBar ? calculatedVerticalDimension() : widgetWidth) : 0
opacity: !autoHide || hasActivePlayer || (!hasActivePlayer && !autoHide) ? 1.0 : 0
// "visible": Always Visible, "hidden": Hide When Empty, "transparent": Transparent When Empty
visible: hideMode !== "hidden" || hasActivePlayer
opacity: hideMode !== "transparent" || hasActivePlayer ? 1.0 : 0
Behavior on opacity {
NumberAnimation {
duration: Style.animationNormal
@@ -75,8 +75,9 @@ Item {
return MediaService.trackTitle + (MediaService.trackArtist !== "" ? ` - ${MediaService.trackArtist}` : "")
}
function calculatedVerticalHeight() {
return Math.round(Style.baseWidgetSize * 0.8 * scaling)
function calculatedVerticalDimension() {
const ratio = (Settings.data.bar.density === "mini") ? 0.67 : 0.8
return Math.round(Style.baseWidgetSize * ratio)
}
// A hidden text element to safely measure the full title width
@@ -85,6 +86,7 @@ Item {
visible: false
text: titleText.text
font: titleText.font
applyUiScale: false
}
Rectangle {
@@ -92,16 +94,16 @@ Item {
visible: root.visible
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (widgetWidth * scaling)
height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : Math.round(Style.capsuleHeight * scaling)
radius: (barPosition === "left" || barPosition === "right") ? width / 2 : Math.round(Style.radiusM * scaling)
width: isVerticalBar ? root.width : (widgetWidth)
height: isVerticalBar ? width : Style.capsuleHeight
radius: isVerticalBar ? width / 2 : Style.radiusM
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
Item {
id: mainContainer
anchors.fill: parent
anchors.leftMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS * scaling
anchors.rightMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS * scaling
anchors.leftMargin: isVerticalBar ? 0 : Style.marginS
anchors.rightMargin: isVerticalBar ? 0 : Style.marginS
Loader {
anchors.verticalCenter: parent.verticalCenter
@@ -110,8 +112,8 @@ Item {
z: 0
sourceComponent: LinearSpectrum {
width: mainContainer.width - Style.marginS * scaling
height: 20 * scaling
width: mainContainer.width - Style.marginS
height: 20
values: CavaService.values
fillColor: Color.mPrimary
opacity: 0.4
@@ -125,8 +127,8 @@ Item {
z: 0
sourceComponent: MirroredSpectrum {
width: mainContainer.width - Style.marginS * scaling
height: mainContainer.height - Style.marginS * scaling
width: mainContainer.width - Style.marginS
height: mainContainer.height - Style.marginS
values: CavaService.values
fillColor: Color.mPrimary
opacity: 0.4
@@ -140,8 +142,8 @@ Item {
z: 0
sourceComponent: WaveSpectrum {
width: mainContainer.width - Style.marginS * scaling
height: mainContainer.height - Style.marginS * scaling
width: mainContainer.width - Style.marginS
height: mainContainer.height - Style.marginS
values: CavaService.values
fillColor: Color.mPrimary
opacity: 0.4
@@ -153,15 +155,15 @@ Item {
id: rowLayout
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS * scaling
visible: (barPosition === "top" || barPosition === "bottom")
spacing: Style.marginS
visible: !isVerticalBar
z: 1 // Above the visualizer
NIcon {
id: windowIcon
icon: hasActivePlayer ? (MediaService.isPlaying ? "media-pause" : "media-play") : "disc"
color: hasActivePlayer ? Color.mOnSurface : Color.mOnSurfaceVariant
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignVCenter
visible: !hasActivePlayer || (!showAlbumArt && !trackArt.visible)
@@ -173,15 +175,15 @@ Item {
spacing: 0
Item {
Layout.preferredWidth: Math.round(21 * scaling)
Layout.preferredHeight: Math.round(21 * scaling)
Layout.preferredWidth: Math.round(21 * Style.uiScaleRatio)
Layout.preferredHeight: Math.round(21 * Style.uiScaleRatio)
NImageCircled {
id: trackArt
anchors.fill: parent
imagePath: MediaService.trackArtUrl
fallbackIcon: MediaService.isPlaying ? "media-pause" : "media-play"
fallbackIconSize: 10 * scaling
fallbackIconSize: 10
borderWidth: 0
border.color: Color.transparent
}
@@ -192,11 +194,11 @@ Item {
id: titleContainer
Layout.preferredWidth: {
// Calculate available width based on other elements in the row
var iconWidth = (windowIcon.visible ? (Style.fontSizeL * scaling + Style.marginS * scaling) : 0)
var albumArtWidth = (hasActivePlayer && showAlbumArt ? (18 * scaling + Style.marginS * scaling) : 0)
var totalMargins = Style.marginXXS * scaling * 2
var iconWidth = (windowIcon.visible ? (Style.fontSizeL + Style.marginS) : 0)
var albumArtWidth = (hasActivePlayer && showAlbumArt ? (18 + Style.marginS) : 0)
var totalMargins = Style.marginXXS * 2
var availableWidth = mainContainer.width - iconWidth - albumArtWidth - totalMargins
return Math.max(20 * scaling, availableWidth)
return Math.max(20, availableWidth)
}
Layout.maximumWidth: Layout.preferredWidth
Layout.alignment: Qt.AlignVCenter
@@ -281,12 +283,13 @@ Item {
x: scrollX
RowLayout {
spacing: 50 * scaling // Gap between text copies
spacing: 50 // Gap between text copies
NText {
id: titleText
text: hasActivePlayer ? getTitle() : placeholderText
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
applyUiScale: false
font.weight: Style.fontWeightMedium
verticalAlignment: Text.AlignVCenter
horizontalAlignment: hasActivePlayer ? Text.AlignLeft : Text.AlignHCenter
@@ -296,6 +299,7 @@ Item {
NText {
text: hasActivePlayer ? getTitle() : placeholderText
font: titleText.font
applyUiScale: false
verticalAlignment: Text.AlignVCenter
horizontalAlignment: hasActivePlayer ? Text.AlignLeft : Text.AlignHCenter
color: hasActivePlayer ? Color.mOnSurface : Color.mOnSurfaceVariant
@@ -319,7 +323,7 @@ Item {
id: infiniteScroll
running: titleContainer.isScrolling && !titleContainer.isResetting
from: 0
to: -(titleContainer.textWidth + 50 * scaling) // Scroll one complete text width + gap
to: -(titleContainer.textWidth + 50) // Scroll one complete text width + gap
duration: Math.max(4000, getTitle().length * 120)
loops: Animation.Infinite
easing.type: Easing.Linear
@@ -339,15 +343,15 @@ Item {
Item {
id: verticalLayout
anchors.centerIn: parent
width: parent.width - Style.marginM * scaling * 2
height: parent.height - Style.marginM * scaling * 2
visible: barPosition === "left" || barPosition === "right"
width: parent.width - Style.marginM * 2
height: parent.height - Style.marginM * 2
visible: isVerticalBar
z: 1 // Above the visualizer
// Media icon
Item {
width: Style.baseWidgetSize * 0.5 * scaling
height: Style.baseWidgetSize * 0.5 * scaling
width: Style.baseWidgetSize * 0.5
height: width
anchors.centerIn: parent
NIcon {
@@ -355,7 +359,7 @@ Item {
anchors.fill: parent
icon: hasActivePlayer ? (MediaService.isPlaying ? "media-pause" : "media-play") : "disc"
color: hasActivePlayer ? Color.mOnSurface : Color.mOnSurfaceVariant
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
@@ -387,7 +391,7 @@ Item {
onEntered: {
var textToShow = hasActivePlayer ? tooltipText : placeholderText
if ((textToShow !== "") && (barPosition === "left" || barPosition === "right") || (scrollingMode === "never")) {
if ((textToShow !== "") && isVerticalBar || (scrollingMode === "never")) {
TooltipService.show(Screen, root, textToShow, BarService.getTooltipDirection())
}
}
+1 -2
View File
@@ -12,7 +12,6 @@ Item {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -92,7 +91,7 @@ Item {
rightOpen: BarService.getPillDirection(root)
icon: getIcon()
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
autoHide: false // Important to be false so we can hover as long as we want
text: Math.round(AudioService.inputVolume * 100)
suffix: "%"
+3 -2
View File
@@ -11,10 +11,11 @@ import qs.Widgets
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
baseSize: Style.capsuleHeight
applyUiScale: false
colorBg: Settings.data.nightLight.forced ? Color.mPrimary : (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
colorFg: Settings.data.nightLight.forced ? Color.mOnPrimary : Color.mOnSurface
colorBorder: Color.transparent
+6 -5
View File
@@ -10,7 +10,7 @@ import qs.Widgets
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -49,7 +49,8 @@ NIconButton {
}
baseSize: Style.capsuleHeight
compact: (Settings.data.bar.density === "compact")
applyUiScale: false
density: Settings.data.bar.density
icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell"
tooltipText: Settings.data.notifications.doNotDisturb ? I18n.tr("tooltips.open-notification-history-disable-dnd") : I18n.tr("tooltips.open-notification-history-enable-dnd")
tooltipDirection: BarService.getTooltipDirection()
@@ -68,14 +69,14 @@ NIconButton {
Loader {
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: 2 * scaling
anchors.topMargin: 1 * scaling
anchors.rightMargin: 2
anchors.topMargin: 1
z: 2
active: showUnreadBadge && (!hideWhenZero || computeUnreadCount() > 0)
sourceComponent: Rectangle {
id: badge
readonly property int count: computeUnreadCount()
height: 8 * scaling
height: 8
width: height
radius: height / 2
color: Color.mError
+3 -3
View File
@@ -9,17 +9,17 @@ import qs.Widgets
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
baseSize: Style.capsuleHeight
applyUiScale: false
density: Settings.data.bar.density
visible: PowerProfileService.available
icon: PowerProfileService.getIcon()
tooltipText: I18n.tr("tooltips.power-profile", {
"profile": PowerProfileService.getName()
})
tooltipDirection: BarService.getTooltipDirection()
compact: (Settings.data.bar.density === "compact")
colorBg: (PowerProfileService.profile === PowerProfile.Balanced) ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary
colorFg: (PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnSurface : Color.mOnPrimary
colorBorder: Color.transparent
+3 -2
View File
@@ -7,13 +7,14 @@ import qs.Widgets
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
icon: "camera-video"
tooltipText: ScreenRecorderService.isRecording ? I18n.tr("tooltips.click-to-stop-recording") : I18n.tr("tooltips.click-to-start-recording")
tooltipDirection: BarService.getTooltipDirection()
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
baseSize: Style.capsuleHeight
applyUiScale: false
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mOnSurface
colorBorder: Color.transparent
+3 -2
View File
@@ -8,10 +8,11 @@ import qs.Widgets
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
baseSize: Style.capsuleHeight
applyUiScale: false
icon: "power"
tooltipText: I18n.tr("tooltips.session-menu")
tooltipDirection: BarService.getTooltipDirection()
+3 -5
View File
@@ -8,9 +8,7 @@ import qs.Widgets
Item {
id: root
// Widget properties passed from Bar.qml
property var screen
property real scaling: 1.0
property ShellScreen screen
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -33,8 +31,8 @@ Item {
readonly property int spacerWidth: widgetSettings.width !== undefined ? widgetSettings.width : widgetMetadata.width
// Set the width based on user settings
implicitWidth: spacerWidth * scaling
implicitHeight: Style.barHeight * scaling
implicitWidth: spacerWidth
implicitHeight: Style.barHeight
width: implicitWidth
height: implicitHeight
}
+46 -35
View File
@@ -9,7 +9,6 @@ Rectangle {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -30,7 +29,7 @@ Rectangle {
readonly property string barPosition: Settings.data.bar.position
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
readonly property bool compact: (Settings.data.bar.density === "compact")
readonly property bool density: Settings.data.bar.density
readonly property bool showCpuUsage: (widgetSettings.showCpuUsage !== undefined) ? widgetSettings.showCpuUsage : widgetMetadata.showCpuUsage
readonly property bool showCpuTemp: (widgetSettings.showCpuTemp !== undefined) ? widgetSettings.showCpuTemp : widgetMetadata.showCpuTemp
@@ -42,12 +41,12 @@ Rectangle {
readonly property real iconSize: textSize * 1.4
readonly property real textSize: {
var base = isVertical ? width * 0.82 : height
return Math.max(1, compact ? base * 0.43 : base * 0.33)
return Math.max(1, (density === "compact") ? base * 0.43 : base * 0.33)
}
readonly property int percentTextWidth: Math.ceil(percentMetrics.boundingRect.width + 3 * scaling)
readonly property int tempTextWidth: Math.ceil(tempMetrics.boundingRect.width + 3 * scaling)
readonly property int memTextWidth: Math.ceil(memMetrics.boundingRect.width + 3 * scaling)
readonly property int percentTextWidth: Math.ceil(percentMetrics.boundingRect.width + 3)
readonly property int tempTextWidth: Math.ceil(tempMetrics.boundingRect.width + 3)
readonly property int memTextWidth: Math.ceil(memMetrics.boundingRect.width + 3)
TextMetrics {
id: percentMetrics
@@ -74,9 +73,9 @@ Rectangle {
}
anchors.centerIn: parent
implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : Math.round(mainGrid.implicitWidth + Style.marginM * 2 * scaling)
implicitHeight: isVertical ? Math.round(mainGrid.implicitHeight + Style.marginM * 2 * scaling) : Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
implicitWidth: isVertical ? Style.capsuleHeight : Math.round(mainGrid.implicitWidth + Style.marginM * 2)
implicitHeight: isVertical ? Math.round(mainGrid.implicitHeight + Style.marginM * 2) : Style.capsuleHeight
radius: Style.radiusM
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
GridLayout {
@@ -85,13 +84,13 @@ Rectangle {
flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: isVertical ? -1 : 1
columns: isVertical ? 1 : -1
rowSpacing: isVertical ? (Style.marginM * scaling) : 0
columnSpacing: isVertical ? 0 : (Style.marginM * scaling)
rowSpacing: isVertical ? (Style.marginM) : 0
columnSpacing: isVertical ? 0 : (Style.marginM)
// CPU Usage Component
Item {
Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS)
Layout.preferredHeight: Style.capsuleHeight
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showCpuUsage
@@ -101,12 +100,13 @@ Rectangle {
flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: isVertical ? 2 : 1
columns: isVertical ? 1 : 2
rowSpacing: Style.marginXXS * scaling
columnSpacing: Style.marginXXS * scaling
rowSpacing: Style.marginXXS
columnSpacing: Style.marginXXS
NIcon {
icon: "cpu-usage"
pointSize: iconSize
applyUiScale: false
Layout.alignment: Qt.AlignCenter
Layout.row: isVertical ? 1 : 0
Layout.column: 0
@@ -116,6 +116,7 @@ Rectangle {
text: `${Math.round(SystemStatService.cpuUsage)}%`
family: Settings.data.ui.fontFixed
pointSize: textSize
applyUiScale: false
font.weight: Style.fontWeightMedium
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: isVertical ? -1 : percentTextWidth
@@ -131,8 +132,8 @@ Rectangle {
// CPU Temperature Component
Item {
Layout.preferredWidth: isVertical ? root.width : (iconSize + tempTextWidth) + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.preferredWidth: isVertical ? root.width : (iconSize + tempTextWidth) + (Style.marginXXS)
Layout.preferredHeight: Style.capsuleHeight
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showCpuTemp
@@ -142,12 +143,13 @@ Rectangle {
flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: isVertical ? 2 : 1
columns: isVertical ? 1 : 2
rowSpacing: Style.marginXXS * scaling
columnSpacing: Style.marginXXS * scaling
rowSpacing: Style.marginXXS
columnSpacing: Style.marginXXS
NIcon {
icon: "cpu-temperature"
pointSize: iconSize
applyUiScale: false
Layout.alignment: Qt.AlignCenter
Layout.row: isVertical ? 1 : 0
Layout.column: 0
@@ -157,6 +159,7 @@ Rectangle {
text: `${Math.round(SystemStatService.cpuTemp)}°`
family: Settings.data.ui.fontFixed
pointSize: textSize
applyUiScale: false
font.weight: Style.fontWeightMedium
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: isVertical ? -1 : tempTextWidth
@@ -172,8 +175,8 @@ Rectangle {
// Memory Usage Component
Item {
Layout.preferredWidth: isVertical ? root.width : iconSize + (showMemoryAsPercent ? percentTextWidth : memTextWidth) + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.preferredWidth: isVertical ? root.width : iconSize + (showMemoryAsPercent ? percentTextWidth : memTextWidth) + (Style.marginXXS)
Layout.preferredHeight: Style.capsuleHeight
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showMemoryUsage
@@ -183,12 +186,13 @@ Rectangle {
flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: isVertical ? 2 : 1
columns: isVertical ? 1 : 2
rowSpacing: Style.marginXXS * scaling
columnSpacing: Style.marginXXS * scaling
rowSpacing: Style.marginXXS
columnSpacing: Style.marginXXS
NIcon {
icon: "memory"
pointSize: iconSize
applyUiScale: false
Layout.alignment: Qt.AlignCenter
Layout.row: isVertical ? 1 : 0
Layout.column: 0
@@ -198,6 +202,7 @@ Rectangle {
text: showMemoryAsPercent ? `${Math.round(SystemStatService.memPercent)}%` : `${SystemStatService.memGb.toFixed(1)}G`
family: Settings.data.ui.fontFixed
pointSize: textSize
applyUiScale: false
font.weight: Style.fontWeightMedium
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: isVertical ? -1 : (showMemoryAsPercent ? percentTextWidth : memTextWidth)
@@ -213,8 +218,8 @@ Rectangle {
// Network Download Speed Component
Item {
Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS)
Layout.preferredHeight: Style.capsuleHeight
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showNetworkStats
@@ -224,12 +229,13 @@ Rectangle {
flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: isVertical ? 2 : 1
columns: isVertical ? 1 : 2
rowSpacing: Style.marginXXS * scaling
columnSpacing: Style.marginXXS * scaling
rowSpacing: Style.marginXXS
columnSpacing: Style.marginXXS
NIcon {
icon: "download-speed"
pointSize: iconSize
applyUiScale: false
Layout.alignment: Qt.AlignCenter
Layout.row: isVertical ? 1 : 0
Layout.column: 0
@@ -239,6 +245,7 @@ Rectangle {
text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.rxSpeed) : SystemStatService.formatSpeed(SystemStatService.rxSpeed)
family: Settings.data.ui.fontFixed
pointSize: textSize
applyUiScale: false
font.weight: Style.fontWeightMedium
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: isVertical ? -1 : memTextWidth
@@ -254,8 +261,8 @@ Rectangle {
// Network Upload Speed Component
Item {
Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS)
Layout.preferredHeight: Style.capsuleHeight
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showNetworkStats
@@ -265,12 +272,13 @@ Rectangle {
flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: isVertical ? 2 : 1
columns: isVertical ? 1 : 2
rowSpacing: Style.marginXXS * scaling
columnSpacing: Style.marginXXS * scaling
rowSpacing: Style.marginXXS
columnSpacing: Style.marginXXS
NIcon {
icon: "upload-speed"
pointSize: iconSize
applyUiScale: false
Layout.alignment: Qt.AlignCenter
Layout.row: isVertical ? 1 : 0
Layout.column: 0
@@ -280,6 +288,7 @@ Rectangle {
text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.txSpeed) : SystemStatService.formatSpeed(SystemStatService.txSpeed)
family: Settings.data.ui.fontFixed
pointSize: textSize
applyUiScale: false
font.weight: Style.fontWeightMedium
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: isVertical ? -1 : memTextWidth
@@ -295,8 +304,8 @@ Rectangle {
// Disk Usage Component (primary drive)
Item {
Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS * scaling)
Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS)
Layout.preferredHeight: Style.capsuleHeight
Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter
visible: showDiskUsage
@@ -306,12 +315,13 @@ Rectangle {
flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: isVertical ? 2 : 1
columns: isVertical ? 1 : 2
rowSpacing: Style.marginXXS * scaling
columnSpacing: Style.marginXXS * scaling
rowSpacing: Style.marginXXS
columnSpacing: Style.marginXXS
NIcon {
icon: "storage"
pointSize: iconSize
applyUiScale: false
Layout.alignment: Qt.AlignCenter
Layout.row: isVertical ? 1 : 0
Layout.column: 0
@@ -321,6 +331,7 @@ Rectangle {
text: `${SystemStatService.diskPercent}%`
family: Settings.data.ui.fontFixed
pointSize: textSize
applyUiScale: false
font.weight: Style.fontWeightMedium
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: isVertical ? -1 : percentTextWidth
+25 -17
View File
@@ -12,7 +12,6 @@ Rectangle {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -21,8 +20,8 @@ Rectangle {
property int sectionWidgetsCount: 0
readonly property bool isVerticalBar: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
readonly property bool compact: (Settings.data.bar.density === "compact")
readonly property real itemSize: compact ? Style.capsuleHeight * 0.9 * scaling : Style.capsuleHeight * 0.8 * scaling
readonly property bool density: Settings.data.bar.density
readonly property real itemSize: (density === "compact") ? Style.capsuleHeight * 0.9 : Style.capsuleHeight * 0.8
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
property var widgetSettings: {
@@ -36,27 +35,27 @@ Rectangle {
}
// Always visible when there are toplevels
implicitWidth: isVerticalBar ? Math.round(Style.capsuleHeight * scaling) : taskbarLayout.implicitWidth + Style.marginM * scaling * 2
implicitHeight: isVerticalBar ? taskbarLayout.implicitHeight + Style.marginM * scaling * 2 : Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
implicitWidth: isVerticalBar ? Style.capsuleHeight : Math.round(taskbarLayout.implicitWidth + Style.marginM * 2)
implicitHeight: isVerticalBar ? Math.round(taskbarLayout.implicitHeight + Style.marginM * 2) : Style.capsuleHeight
radius: Style.radiusM
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
GridLayout {
id: taskbarLayout
anchors.fill: parent
anchors {
leftMargin: isVerticalBar ? undefined : Style.marginM * scaling
rightMargin: isVerticalBar ? undefined : Style.marginM * scaling
topMargin: compact ? 0 : isVerticalBar ? Style.marginM * scaling : undefined
bottomMargin: compact ? 0 : isVerticalBar ? Style.marginM * scaling : undefined
leftMargin: isVerticalBar ? undefined : Style.marginM
rightMargin: isVerticalBar ? undefined : Style.marginM
topMargin: (density === "compact") ? 0 : isVerticalBar ? Style.marginM : undefined
bottomMargin: (density === "compact") ? 0 : isVerticalBar ? Style.marginM : undefined
}
// Configure GridLayout to behave like RowLayout or ColumnLayout
rows: isVerticalBar ? -1 : 1 // -1 means unlimited
columns: isVerticalBar ? 1 : -1 // -1 means unlimited
rowSpacing: isVerticalBar ? Style.marginXXS * root.scaling : 0
columnSpacing: isVerticalBar ? 0 : Style.marginXXS * root.scaling
rowSpacing: isVerticalBar ? Style.marginXXS : 0
columnSpacing: isVerticalBar ? 0 : Style.marginXXS
Repeater {
model: CompositorService.windows
@@ -81,13 +80,22 @@ Rectangle {
asynchronous: true
opacity: modelData.isFocused ? Style.opacityFull : 0.6
// Apply dock shader to all taskbar icons
layer.enabled: widgetSettings.colorizeIcons !== false
layer.effect: ShaderEffect {
property color targetColor: Color.mOnSurface
property real colorizeMode: 0.0 // Dock mode (grayscale)
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
}
Rectangle {
anchors.bottomMargin: -2 * scaling
anchors.bottomMargin: -2
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
id: iconBackground
width: 4 * scaling
height: 4 * scaling
width: 4
height: 4
color: modelData.isFocused ? Color.mPrimary : Color.transparent
radius: width * 0.5
}
@@ -105,13 +113,13 @@ Rectangle {
if (mouse.button === Qt.LeftButton) {
try {
CompositorService.focusWindow(taskbarItem.modelData.id)
CompositorService.focusWindow(taskbarItem.modelData)
} catch (error) {
Logger.error("Taskbar", "Failed to activate toplevel: " + error)
}
} else if (mouse.button === Qt.RightButton) {
try {
CompositorService.closeWindow(taskbarItem.modelData.id)
CompositorService.closeWindow(taskbarItem.modelData)
} catch (error) {
Logger.error("Taskbar", "Failed to close toplevel: " + error)
}
+185 -66
View File
@@ -14,12 +14,109 @@ Rectangle {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
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 bool compact: (Settings.data.bar.density === "compact")
readonly property real itemSize: isVertical ? width * 0.75 : height * 0.85
readonly property bool density: Settings.data.bar.density
property real itemSize: Math.round(Style.capsuleHeight * 0.65)
property list<string> blacklist: widgetSettings.blacklist || widgetMetadata.blacklist || [] // Read from settings
property var filteredItems: []
function wildCardMatch(str, rule) {
if (!str || !rule) {
return false
}
Logger.log("Tray", "wildCardMatch - Input str:", str, "rule:", rule)
// Escape all special regex characters in the rule
let escapedRule = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
// Convert '*' to '.*' for wildcard matching
let pattern = escapedRule.replace(/\\\*/g, '.*')
// Add ^ and $ to match the entire string
pattern = '^' + pattern + '$'
Logger.log("Tray", "wildCardMatch - Generated pattern:", pattern)
try {
const regex = new RegExp(pattern, 'i')
// 'i' for case-insensitive
Logger.log("Tray", "wildCardMatch - Regex test result:", regex.test(str))
return regex.test(str)
} catch (e) {
Logger.warn("Tray", "Invalid regex pattern for wildcard match:", rule, e.message)
return false // If regex is invalid, it won't match
}
}
// Debounce timer for updateFilteredItems to prevent excessive calls
// when multiple events (e.g., SystemTray changes, settings saves)
// trigger it in rapid succession, reducing redundant processing.
Timer {
id: updateDebounceTimer
interval: 100 // milliseconds
running: false
repeat: false
onTriggered: _performFilteredItemsUpdate()
}
function _performFilteredItemsUpdate() {
if (!root.blacklist || root.blacklist.length === 0) {
if (SystemTray.items && SystemTray.items.values) {
filteredItems = SystemTray.items.values
} else {
filteredItems = []
}
return
}
let newItems = []
if (SystemTray.items && SystemTray.items.values) {
const trayItems = SystemTray.items.values
for (var i = 0; i < trayItems.length; i++) {
const item = trayItems[i]
if (!item) {
continue
}
const title = item.tooltipTitle || item.name || item.id || ""
let isBlacklisted = false
for (var j = 0; j < root.blacklist.length; j++) {
const rule = root.blacklist[j]
if (wildCardMatch(title, rule)) {
isBlacklisted = true
break
}
}
if (!isBlacklisted) {
newItems.push(item)
}
}
}
filteredItems = newItems
}
function updateFilteredItems() {
updateDebounceTimer.restart()
}
function onLoaded() {
// When the widget is fully initialized with its props set the screen for the trayMenu
@@ -28,10 +125,28 @@ Rectangle {
}
}
visible: SystemTray.items.values.length > 0
implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : (trayFlow.implicitWidth + Style.marginS * scaling * 2)
implicitHeight: isVertical ? (trayFlow.implicitHeight + Style.marginS * scaling * 2) : Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
Connections {
target: SystemTray.items
function onValuesChanged() {
root.updateFilteredItems()
}
}
Connections {
target: Settings
function onSettingsSaved() {
root.updateFilteredItems()
}
}
Component.onCompleted: {
root.updateFilteredItems() // Initial update
}
visible: filteredItems.length > 0
implicitWidth: isVertical ? Style.capsuleHeight : Math.round(trayFlow.implicitWidth + Style.marginM * 2)
implicitHeight: isVertical ? Math.round(trayFlow.implicitHeight + Style.marginM * 2) : Style.capsuleHeight
radius: Style.radiusM
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
Layout.alignment: Qt.AlignVCenter
@@ -39,12 +154,12 @@ Rectangle {
Flow {
id: trayFlow
anchors.centerIn: parent
spacing: Style.marginS * scaling
spacing: Style.marginM
flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight
Repeater {
id: repeater
model: SystemTray.items
model: filteredItems
delegate: Item {
width: itemSize
@@ -56,10 +171,7 @@ Rectangle {
property ShellScreen screen: root.screen
anchors.centerIn: parent
width: Style.marginL * scaling
height: Style.marginL * scaling
smooth: false
anchors.fill: parent
asynchronous: true
backer.fillMode: Image.PreserveAspectFit
source: {
@@ -70,7 +182,6 @@ Rectangle {
// Process icon path
if (icon.includes("?path=")) {
// Seems qmlfmt does not support the following ES6 syntax: const[name, path] = icon.split
const chunks = icon.split("?path=")
const name = chunks[0]
const path = chunks[1]
@@ -80,69 +191,77 @@ Rectangle {
return icon
}
opacity: status === Image.Ready ? 1 : 0
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
onClicked: mouse => {
if (!modelData) {
return
}
layer.enabled: widgetSettings.colorizeIcons !== false
layer.effect: ShaderEffect {
property color targetColor: Color.mOnSurface
property real colorizeMode: 1.0 // Tray mode (intensity-based)
if (mouse.button === Qt.LeftButton) {
// Close any open menu first
trayPanel.close()
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
}
if (!modelData.onlyMenu) {
modelData.activate()
}
} else if (mouse.button === Qt.MiddleButton) {
// Close any open menu first
trayPanel.close()
modelData.secondaryActivate && modelData.secondaryActivate()
} else if (mouse.button === Qt.RightButton) {
TooltipService.hideImmediately()
// Close the menu if it was visible
if (trayPanel && trayPanel.visible) {
trayPanel.close()
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
onClicked: mouse => {
if (!modelData) {
return
}
if (modelData.hasMenu && modelData.menu && trayMenu.item) {
trayPanel.open()
if (mouse.button === Qt.LeftButton) {
// Close any open menu first
trayPanel.close()
// Position menu based on bar position
let menuX, menuY
if (barPosition === "left") {
// For left bar: position menu to the right of the bar
menuX = width + Style.marginM * scaling
menuY = 0
} else if (barPosition === "right") {
// For right bar: position menu to the left of the bar
menuX = -trayMenu.item.width - Style.marginM * scaling
menuY = 0
} else {
// For horizontal bars: center horizontally and position below
menuX = (width / 2) - (trayMenu.item.width / 2)
menuY = Math.round(Style.barHeight * scaling)
if (!modelData.onlyMenu) {
modelData.activate()
}
} else if (mouse.button === Qt.MiddleButton) {
// Close any open menu first
trayPanel.close()
modelData.secondaryActivate && modelData.secondaryActivate()
} else if (mouse.button === Qt.RightButton) {
TooltipService.hideImmediately()
// Close the menu if it was visible
if (trayPanel && trayPanel.visible) {
trayPanel.close()
return
}
if (modelData.hasMenu && modelData.menu && trayMenu.item) {
trayPanel.open()
// Position menu based on bar position
let menuX, menuY
if (barPosition === "left") {
// For left bar: position menu to the right of the bar
menuX = width + Style.marginM
menuY = 0
} else if (barPosition === "right") {
// For right bar: position menu to the left of the bar
menuX = -trayMenu.item.width - Style.marginM
menuY = 0
} else {
// For horizontal bars: center horizontally and position below
menuX = (width / 2) - (trayMenu.item.width / 2)
menuY = Style.barHeight
}
trayMenu.item.menu = modelData.menu
trayMenu.item.showAt(parent, menuX, menuY)
} else {
Logger.log("Tray", "No menu available for", modelData.id, "or trayMenu not set")
}
trayMenu.item.menu = modelData.menu
trayMenu.item.showAt(parent, menuX, menuY)
} else {
Logger.log("Tray", "No menu available for", modelData.id, "or trayMenu not set")
}
}
}
onEntered: {
trayPanel.close()
TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection())
onEntered: {
trayPanel.close()
TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection())
}
onExited: TooltipService.hide()
}
onExited: TooltipService.hide()
}
}
}
+1 -2
View File
@@ -12,7 +12,6 @@ Item {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -75,7 +74,7 @@ Item {
BarPill {
id: pill
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
rightOpen: BarService.getPillDirection(root)
icon: getIcon()
autoHide: false // Important to be false so we can hover as long as we want
+3 -2
View File
@@ -8,10 +8,11 @@ import qs.Widgets
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
baseSize: Style.capsuleHeight
compact: (Settings.data.bar.density === "compact")
applyUiScale: false
density: Settings.data.bar.density
icon: "wallpaper-selector"
tooltipText: I18n.tr("tooltips.open-wallpaper-selector")
tooltipDirection: BarService.getTooltipDirection()
+3 -2
View File
@@ -10,10 +10,11 @@ import qs.Widgets
NIconButton {
id: root
property real scaling: 1.0
property ShellScreen screen
compact: (Settings.data.bar.density === "compact")
density: Settings.data.bar.density
baseSize: Style.capsuleHeight
applyUiScale: false
colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent)
colorFg: Color.mOnSurface
colorBorder: Color.transparent
+30 -29
View File
@@ -13,7 +13,6 @@ Item {
id: root
property ShellScreen screen
property real scaling: 1.0
// Widget properties passed from Bar.qml for per-instance settings
property string widgetId: ""
@@ -34,9 +33,9 @@ Item {
readonly property string barPosition: Settings.data.bar.position
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
readonly property bool compact: (Settings.data.bar.density === "compact")
readonly property bool density: Settings.data.bar.density
readonly property real baseDimensionRatio: {
const b = compact ? 0.85 : 0.65
const b = (density === "compact") ? 0.85 : 0.65
if (widgetSettings.labelMode === "none") {
return b * 0.75
}
@@ -54,8 +53,8 @@ Item {
property bool effectsActive: false
property color effectColor: Color.mPrimary
property int horizontalPadding: Math.round(Style.marginS * scaling)
property int spacingBetweenPills: Math.round(Style.marginXS * scaling)
property int horizontalPadding: Math.round(Style.marginS)
property int spacingBetweenPills: Math.round(Style.marginXS)
// Wheel scroll handling
property int wheelAccumulatedDelta: 0
@@ -63,19 +62,19 @@ Item {
signal workspaceChanged(int workspaceId, color accentColor)
implicitWidth: isVertical ? Math.round(Style.barHeight * scaling) : computeWidth()
implicitHeight: isVertical ? computeHeight() : Math.round(Style.barHeight * scaling)
implicitWidth: isVertical ? Style.barHeight : computeWidth()
implicitHeight: isVertical ? computeHeight() : Style.barHeight
function getWorkspaceWidth(ws) {
const d = Style.capsuleHeight * root.baseDimensionRatio
const factor = ws.isFocused ? 2.2 : 1
return d * factor * scaling
const factor = ws.isActive ? 2.2 : 1
return d * factor
}
function getWorkspaceHeight(ws) {
const d = Style.capsuleHeight * root.baseDimensionRatio
const factor = ws.isFocused ? 2.2 : 1
return d * factor * scaling
const factor = ws.isActive ? 2.2 : 1
return d * factor
}
function computeWidth() {
@@ -119,7 +118,7 @@ Item {
next = localWorkspaces.count - 1
const ws = localWorkspaces.get(next)
if (ws && ws.idx !== undefined)
CompositorService.switchToWorkspace(ws.idx)
CompositorService.switchToWorkspace(ws)
}
Component.onCompleted: {
@@ -203,9 +202,9 @@ Item {
Rectangle {
id: workspaceBackground
width: isVertical ? Math.round(Style.capsuleHeight * scaling) : parent.width
height: isVertical ? parent.height : Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
width: isVertical ? Style.capsuleHeight : parent.width
height: isVertical ? parent.height : Style.capsuleHeight
radius: Style.radiusM
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
anchors.horizontalCenter: parent.horizontalCenter
@@ -266,7 +265,7 @@ Item {
Item {
id: workspacePillContainer
width: root.getWorkspaceWidth(model)
height: Style.capsuleHeight * root.baseDimensionRatio * scaling
height: Style.capsuleHeight * root.baseDimensionRatio
Rectangle {
id: pill
@@ -286,7 +285,8 @@ Item {
}
}
family: Settings.data.ui.fontFixed
pointSize: model.isFocused ? workspacePillContainer.height * 0.45 : workspacePillContainer.height * 0.42
pointSize: model.isActive ? workspacePillContainer.height * 0.45 : workspacePillContainer.height * 0.42
applyUiScale: false
font.capitalization: Font.AllUppercase
font.weight: Style.fontWeightBold
wrapMode: Text.Wrap
@@ -295,7 +295,7 @@ Item {
return Color.mOnPrimary
if (model.isUrgent)
return Color.mOnError
if (model.isActive || model.isOccupied)
if (model.isOccupied)
return Color.mOnSecondary
return Color.mOnSecondary
@@ -310,12 +310,12 @@ Item {
return Color.mPrimary
if (model.isUrgent)
return Color.mError
if (model.isActive || model.isOccupied)
if (model.isOccupied)
return Color.mSecondary
return Qt.alpha(Color.mSecondary, 0.3)
}
scale: model.isFocused ? 1.0 : 0.9
scale: model.isActive ? 1.0 : 0.9
z: 0
MouseArea {
@@ -323,7 +323,7 @@ Item {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
CompositorService.switchToWorkspace(model.idx)
CompositorService.switchToWorkspace(model)
}
hoverEnabled: true
}
@@ -387,7 +387,7 @@ Item {
radius: width / 2
color: Color.transparent
border.color: root.effectColor
border.width: Math.max(1, Math.round((2 + 6 * (1.0 - root.masterProgress)) * scaling))
border.width: Math.max(1, Math.round((2 + 6 * (1.0 - root.masterProgress))))
opacity: root.effectsActive && model.isFocused ? (1.0 - root.masterProgress) * 0.7 : 0
visible: root.effectsActive && model.isFocused
z: 1
@@ -409,7 +409,7 @@ Item {
model: localWorkspaces
Item {
id: workspacePillContainerVertical
width: Style.capsuleHeight * root.baseDimensionRatio * scaling
width: Style.capsuleHeight * root.baseDimensionRatio
height: root.getWorkspaceHeight(model)
Rectangle {
@@ -430,7 +430,8 @@ Item {
}
}
family: Settings.data.ui.fontFixed
pointSize: model.isFocused ? workspacePillContainerVertical.width * 0.45 : workspacePillContainerVertical.width * 0.42
pointSize: model.isActive ? workspacePillContainerVertical.width * 0.45 : workspacePillContainerVertical.width * 0.42
applyUiScale: false
font.capitalization: Font.AllUppercase
font.weight: Style.fontWeightBold
wrapMode: Text.Wrap
@@ -439,7 +440,7 @@ Item {
return Color.mOnPrimary
if (model.isUrgent)
return Color.mOnError
if (model.isActive || model.isOccupied)
if (model.isOccupied)
return Color.mOnSecondary
return Color.mOnSurface
@@ -454,12 +455,12 @@ Item {
return Color.mPrimary
if (model.isUrgent)
return Color.mError
if (model.isActive || model.isOccupied)
if (model.isOccupied)
return Color.mSecondary
return Color.mOutline
}
scale: model.isFocused ? 1.0 : 0.9
scale: model.isActive ? 1.0 : 0.9
z: 0
MouseArea {
@@ -467,7 +468,7 @@ Item {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
CompositorService.switchToWorkspace(model.idx)
CompositorService.switchToWorkspace(model)
}
hoverEnabled: true
}
@@ -531,7 +532,7 @@ Item {
radius: width / 2
color: Color.transparent
border.color: root.effectColor
border.width: Math.max(1, Math.round((2 + 6 * (1.0 - root.masterProgress)) * scaling))
border.width: Math.max(1, Math.round((2 + 6 * (1.0 - root.masterProgress))))
opacity: root.effectsActive && model.isFocused ? (1.0 - root.masterProgress) * 0.7 : 0
visible: root.effectsActive && model.isFocused
z: 1
+155
View File
@@ -0,0 +1,155 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
// Audio controls card: output and input volume controls
NBox {
id: root
property real localOutputVolume: AudioService.volume || 0
property bool localOutputVolumeChanging: false
property real localInputVolume: AudioService.inputVolume || 0
property bool localInputVolumeChanging: false
// Timer to debounce volume changes
Timer {
interval: 100
running: true
repeat: true
onTriggered: {
if (Math.abs(localOutputVolume - AudioService.volume) >= 0.01) {
AudioService.setVolume(localOutputVolume)
}
if (Math.abs(localInputVolume - AudioService.inputVolume) >= 0.01) {
AudioService.setInputVolume(localInputVolume)
}
}
}
// Connections to update local volumes when AudioService changes
Connections {
target: AudioService.sink?.audio ? AudioService.sink?.audio : null
function onVolumeChanged() {
if (!localOutputVolumeChanging) {
localOutputVolume = AudioService.volume
}
}
}
Connections {
target: AudioService.source?.audio ? AudioService.source?.audio : null
function onVolumeChanged() {
if (!localInputVolumeChanging) {
localInputVolume = AudioService.inputVolume
}
}
}
RowLayout {
anchors.fill: parent
anchors.margins: Style.marginM
spacing: Style.marginM
// Output Volume Section
ColumnLayout {
spacing: Style.marginXXS
Layout.fillWidth: true
opacity: AudioService.sink ? 1.0 : 0.5
enabled: AudioService.sink
// Output Volume Header
RowLayout {
Layout.fillWidth: true
spacing: Style.marginXS
NIconButton {
icon: AudioService.muted ? "volume-off" : "volume-high"
baseSize: Style.baseWidgetSize * 0.5
colorFg: AudioService.muted ? Color.mError : Color.mOnSurface
colorBg: Color.transparent
colorBgHover: Color.mTertiary
colorFgHover: Color.mOnTertiary
onClicked: {
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = !AudioService.muted
}
}
}
NText {
text: AudioService.sink ? AudioService.sink.description : "No output device"
pointSize: Style.fontSizeXS
color: Color.mOnSurfaceVariant
font.weight: Style.fontWeightMedium
elide: Text.ElideRight
Layout.fillWidth: true
}
}
// Output Volume Slider
NSlider {
Layout.fillWidth: true
from: 0
to: Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
value: localOutputVolume
stepSize: 0.01
heightRatio: 0.5
onMoved: localOutputVolume = value
onPressedChanged: localOutputVolumeChanging = pressed
tooltipText: `${Math.round(localOutputVolume * 100)}%`
tooltipDirection: "bottom"
}
}
// Input Volume Section
ColumnLayout {
spacing: Style.marginXXS
Layout.fillWidth: true
opacity: AudioService.source ? 1.0 : 0.5
enabled: AudioService.source
// Input Volume Header
RowLayout {
Layout.fillWidth: true
spacing: Style.marginXS
NIconButton {
icon: AudioService.inputMuted ? "microphone-off" : "microphone"
baseSize: Style.baseWidgetSize * 0.5
colorFg: AudioService.inputMuted ? Color.mError : Color.mOnSurface
colorBg: Color.transparent
colorBgHover: Color.mTertiary
colorFgHover: Color.mOnTertiary
onClicked: AudioService.setInputMuted(!AudioService.inputMuted)
}
NText {
text: AudioService.source ? AudioService.source.description : "No input device"
pointSize: Style.fontSizeXS
color: Color.mOnSurfaceVariant
font.weight: Style.fontWeightMedium
elide: Text.ElideRight
Layout.fillWidth: true
}
}
// Input Volume Slider
NSlider {
Layout.fillWidth: true
from: 0
to: Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
value: localInputVolume
stepSize: 0.01
heightRatio: 0.5
onMoved: localInputVolume = value
onPressedChanged: localInputVolumeChanging = pressed
tooltipText: `${Math.round(localInputVolume * 100)}%`
tooltipDirection: "bottom"
}
}
}
}
+34 -34
View File
@@ -20,7 +20,7 @@ NBox {
id: bgArtImage
anchors.fill: parent
imagePath: MediaService.trackArtUrl
imageRadius: Style.radiusM * scaling
imageRadius: Style.radiusM
visible: MediaService.trackArtUrl !== ""
}
@@ -29,7 +29,7 @@ NBox {
anchors.fill: parent
color: Color.mSurfaceVariant
opacity: 0.85
radius: Style.radiusM * scaling
radius: Style.radiusM
}
// Border
@@ -38,7 +38,7 @@ NBox {
color: Color.transparent
border.color: Color.mOutline
border.width: 1
radius: Style.radiusM * scaling
radius: Style.radiusM
}
}
@@ -55,7 +55,7 @@ NBox {
sourceItem: Rectangle {
width: root.width
height: root.height
radius: Style.radiusM * scaling
radius: Style.radiusM
color: "white"
}
}
@@ -84,7 +84,7 @@ NBox {
anchors.fill: parent
values: CavaService.values
fillColor: Color.mPrimary
opacity: MediaService.trackArtUrl !== "" ? 0.4 : 0.8
opacity: MediaService.trackArtUrl !== "" ? 0.5 : 0.8
}
}
@@ -94,7 +94,7 @@ NBox {
anchors.fill: parent
values: CavaService.values
fillColor: Color.mPrimary
opacity: MediaService.trackArtUrl !== "" ? 0.4 : 0.8
opacity: MediaService.trackArtUrl !== "" ? 0.5 : 0.8
}
}
@@ -104,41 +104,41 @@ NBox {
anchors.fill: parent
values: CavaService.values
fillColor: Color.mPrimary
opacity: MediaService.trackArtUrl !== "" ? 0.4 : 0.8
opacity: MediaService.trackArtUrl !== "" ? 0.5 : 0.8
}
}
}
}
// Player selector - positioned at the very top
// Player selector
Rectangle {
id: playerSelectorButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: Style.marginXS * scaling
anchors.leftMargin: Style.marginM * scaling
anchors.rightMargin: Style.marginM * scaling
height: Style.barHeight * scaling
anchors.topMargin: Style.marginXS
anchors.leftMargin: Style.marginM
anchors.rightMargin: Style.marginM
height: Style.barHeight
visible: MediaService.getAvailablePlayers().length > 1
radius: Style.radiusM * scaling
radius: Style.radiusM
color: Color.transparent
property var currentPlayer: MediaService.getAvailablePlayers()[MediaService.selectedPlayerIndex]
RowLayout {
anchors.fill: parent
spacing: Style.marginS * scaling
spacing: Style.marginS
NIcon {
icon: "caret-down"
pointSize: Style.fontSizeXXL * scaling
pointSize: Style.fontSizeXXL
color: Color.mOnSurfaceVariant
}
NText {
text: playerSelectorButton.currentPlayer ? playerSelectorButton.currentPlayer.identity : ""
pointSize: Style.fontSizeXS * scaling
pointSize: Style.fontSizeXS
color: Color.mOnSurfaceVariant
Layout.fillWidth: true
}
@@ -170,7 +170,7 @@ NBox {
NContextMenu {
id: playerContextMenu
parent: root
width: 200 * scaling
width: 200
onTriggered: function (action) {
var index = parseInt(action)
@@ -184,14 +184,14 @@ NBox {
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginM * scaling
anchors.margins: Style.marginM
// No media player detected
ColumnLayout {
id: fallback
visible: !main.visible
spacing: Style.marginS * scaling
spacing: Style.marginS
Item {
Layout.fillWidth: true
@@ -204,12 +204,12 @@ NBox {
ColumnLayout {
anchors.centerIn: parent
spacing: Style.marginL * scaling
spacing: Style.marginL
Item {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: Style.fontSizeXXXL * 4 * scaling
Layout.preferredHeight: Style.fontSizeXXXL * 4 * scaling
Layout.preferredWidth: Style.fontSizeXXXL * 4
Layout.preferredHeight: Style.fontSizeXXXL * 4
// Pulsating audio circles (background)
Repeater {
@@ -258,7 +258,7 @@ NBox {
NIcon {
anchors.centerIn: parent
icon: "disc"
pointSize: Style.fontSizeXXXL * 3 * scaling
pointSize: Style.fontSizeXXXL * 3
color: Color.mOnSurfaceVariant
RotationAnimator on rotation {
@@ -274,7 +274,7 @@ NBox {
// Descriptive text
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Style.marginXS * scaling
spacing: Style.marginXS
}
}
}
@@ -290,23 +290,23 @@ NBox {
id: main
visible: MediaService.currentPlayer && MediaService.canPlay
spacing: Style.marginS * scaling
spacing: Style.marginS
// Spacer to push content down
Item {
Layout.preferredHeight: Style.marginM * scaling
Layout.preferredHeight: Style.marginM
}
// Metadata at the bottom left
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
spacing: Style.marginXS * scaling
spacing: Style.marginXS
NText {
visible: MediaService.trackTitle !== ""
text: MediaService.trackTitle
pointSize: Style.fontSizeM * scaling
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
elide: Text.ElideRight
wrapMode: Text.Wrap
@@ -318,7 +318,7 @@ NBox {
visible: MediaService.trackArtist !== ""
text: MediaService.trackArtist
color: Color.mPrimary
pointSize: Style.fontSizeS * scaling
pointSize: Style.fontSizeS
elide: Text.ElideRight
Layout.fillWidth: true
}
@@ -327,7 +327,7 @@ NBox {
visible: MediaService.trackAlbum !== ""
text: MediaService.trackAlbum
color: Color.mOnSurfaceVariant
pointSize: Style.fontSizeM * scaling
pointSize: Style.fontSizeM
elide: Text.ElideRight
Layout.fillWidth: true
}
@@ -338,7 +338,7 @@ NBox {
id: progressWrapper
visible: (MediaService.currentPlayer && MediaService.trackLength > 0)
Layout.fillWidth: true
height: Style.baseWidgetSize * 0.5 * scaling
height: Style.baseWidgetSize * 0.5
property real localSeekRatio: -1
property real lastSentSeekRatio: -1
@@ -376,7 +376,7 @@ NBox {
stepSize: 0
snapAlways: false
enabled: MediaService.trackLength > 0 && MediaService.canSeek
heightRatio: 0.65
heightRatio: 0.6
onMoved: {
progressWrapper.localSeekRatio = value
@@ -408,12 +408,12 @@ NBox {
// Spacer to push media controls down
Item {
Layout.preferredHeight: Style.marginL * scaling
Layout.preferredHeight: Style.marginL
}
// Media controls
RowLayout {
spacing: Style.marginS * scaling
spacing: Style.marginS
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
+113
View File
@@ -0,0 +1,113 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Widgets
import qs.Modules.Settings
import qs.Modules.ControlCenter
import qs.Commons
import qs.Services
import qs.Widgets
// Header card with avatar, user and quick actions
NBox {
id: root
property string uptimeText: "--"
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: Style.marginM
spacing: Style.marginM
NImageCircled {
Layout.preferredWidth: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio)
Layout.preferredHeight: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio)
imagePath: Settings.preprocessPath(Settings.data.general.avatarImage)
fallbackIcon: "person"
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM)
}
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginXXS
NText {
text: Quickshell.env("USER") || "user"
font.weight: Style.fontWeightBold
font.capitalization: Font.Capitalize
}
NText {
text: I18n.tr("system.uptime", {
"uptime": uptimeText
})
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
}
}
RowLayout {
spacing: Style.marginS
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Item {
Layout.fillWidth: true
}
NIconButton {
icon: "settings"
tooltipText: I18n.tr("tooltips.open-settings")
onClicked: {
settingsPanel.requestedTab = SettingsPanel.Tab.General
settingsPanel.open()
}
}
NIconButton {
icon: "power"
tooltipText: I18n.tr("tooltips.session-menu")
onClicked: {
sessionMenuPanel.open()
controlCenterPanel.close()
}
}
NIconButton {
icon: "close"
tooltipText: I18n.tr("tooltips.close")
onClicked: {
controlCenterPanel.close()
}
}
}
}
// ----------------------------------
// Uptime
Timer {
interval: 60000
repeat: true
running: true
onTriggered: uptimeProcess.running = true
}
Process {
id: uptimeProcess
command: ["cat", "/proc/uptime"]
running: true
stdout: StdioCollector {
onStreamFinished: {
var uptimeSeconds = parseFloat(this.text.trim().split(' ')[0])
uptimeText = Time.formatVagueHumanReadableDuration(uptimeSeconds)
uptimeProcess.running = false
}
}
}
function updateSystemInfo() {
uptimeProcess.running = true
}
}
@@ -0,0 +1,84 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
import qs.Modules.ControlCenter
import qs.Modules.ControlCenter.Cards
RowLayout {
Layout.fillWidth: true
spacing: Style.marginL
NBox {
Layout.fillWidth: true
Layout.preferredHeight: root.shortcutsHeight
RowLayout {
id: leftContent
anchors.fill: parent
spacing: Style.marginS
Item {
Layout.fillWidth: true
}
Repeater {
model: Settings.data.controlCenter.shortcuts.left
delegate: ControlCenterWidgetLoader {
Layout.fillWidth: false
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"widgetId": modelData.id,
"section": "quickSettings",
"sectionWidgetIndex": index,
"sectionWidgetsCount": Settings.data.controlCenter.shortcuts.left.length
}
Layout.alignment: Qt.AlignVCenter
}
}
Item {
Layout.fillWidth: true
}
}
}
NBox {
Layout.fillWidth: true
Layout.preferredHeight: root.shortcutsHeight
RowLayout {
id: rightContent
anchors.fill: parent
spacing: Style.marginS
Item {
Layout.fillWidth: true
}
Repeater {
model: Settings.data.controlCenter.shortcuts.right
delegate: ControlCenterWidgetLoader {
Layout.fillWidth: false
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"widgetId": modelData.id,
"section": "quickSettings",
"sectionWidgetIndex": index,
"sectionWidgetsCount": Settings.data.controlCenter.shortcuts.right.length
}
Layout.alignment: Qt.AlignVCenter
}
}
Item {
Layout.fillWidth: true
}
}
}
}
@@ -9,47 +9,50 @@ import qs.Widgets
NBox {
id: root
GridLayout {
Item {
id: content
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
columns: 2
rows: 2
columnSpacing: Style.marginS * scaling
rowSpacing: Style.marginS * scaling
anchors.margins: Style.marginS
NCircleStat {
value: SystemStatService.cpuUsage
icon: "cpu-usage"
flat: true
contentScale: 0.8
Layout.fillWidth: true
Layout.fillHeight: true
}
NCircleStat {
value: SystemStatService.cpuTemp
suffix: "°C"
icon: "cpu-temperature"
flat: true
contentScale: 0.8
Layout.fillWidth: true
Layout.fillHeight: true
}
NCircleStat {
value: SystemStatService.memPercent
icon: "memory"
flat: true
contentScale: 0.8
Layout.fillWidth: true
Layout.fillHeight: true
}
NCircleStat {
value: SystemStatService.diskPercent
icon: "storage"
flat: true
contentScale: 0.8
Layout.fillWidth: true
Layout.fillHeight: true
property int widgetHeight: Math.round(65 * Style.uiScaleRatio)
ColumnLayout {
anchors.centerIn: parent
spacing: 0
NCircleStat {
value: SystemStatService.cpuUsage
icon: "cpu-usage"
flat: true
contentScale: 0.8
height: content.widgetHeight
Layout.alignment: Qt.AlignHCenter
}
NCircleStat {
value: SystemStatService.cpuTemp
suffix: "°C"
icon: "cpu-temperature"
flat: true
contentScale: 0.8
height: content.widgetHeight
Layout.alignment: Qt.AlignHCenter
}
NCircleStat {
value: SystemStatService.memPercent
icon: "memory"
flat: true
contentScale: 0.8
height: content.widgetHeight
Layout.alignment: Qt.AlignHCenter
}
NCircleStat {
value: SystemStatService.diskPercent
icon: "storage"
flat: true
contentScale: 0.8
height: content.widgetHeight
Layout.alignment: Qt.AlignHCenter
}
}
}
}
-330
View File
@@ -1,330 +0,0 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Widgets
import Quickshell.Services.UPower
import qs.Modules.Settings
import qs.Modules.ControlCenter
import qs.Commons
import qs.Services
import qs.Widgets
// Header card with avatar, user and quick actions
NBox {
id: root
property string uptimeText: "--"
property real spacing: Style.marginS * scaling
readonly property bool hasPP: PowerProfileService.available
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginM * scaling
// Profile, Uptime, Settings, SessionMenu, Close
RowLayout {
id: content
spacing: root.spacing
Layout.alignment: Qt.AlignVCenter
NImageCircled {
width: Style.baseWidgetSize * 1.25 * scaling
height: Style.baseWidgetSize * 1.25 * scaling
imagePath: Settings.data.general.avatarImage
fallbackIcon: "person"
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
Layout.alignment: Qt.AlignVCenter
Layout.topMargin: Style.marginXS * scaling
}
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginXXS * scaling
NText {
text: Quickshell.env("USER") || "user"
font.weight: Style.fontWeightBold
font.capitalization: Font.Capitalize
}
NText {
text: I18n.tr("system.uptime", {
"uptime": uptimeText
})
pointSize: Style.fontSizeS * scaling
color: Color.mOnSurfaceVariant
}
}
Item {
Layout.fillWidth: true
}
RowLayout {
spacing: root.spacing
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
icon: "settings"
tooltipText: I18n.tr("tooltips.open-settings")
onClicked: {
settingsPanel.requestedTab = SettingsPanel.Tab.General
settingsPanel.open()
}
}
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
icon: "power"
tooltipText: I18n.tr("tooltips.session-menu")
onClicked: {
sessionMenuPanel.open()
controlCenterPanel.close()
}
}
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
icon: "close"
tooltipText: I18n.tr("tooltips.close")
onClicked: {
controlCenterPanel.close()
}
}
}
}
RowLayout {
id: utilitiesRow
Layout.alignment: Qt.AlignVCenter
Layout.topMargin: Style.marginM * scaling
Layout.bottomMargin: Style.marginM * scaling
Layout.fillWidth: true
// Left group - Media & Display
Rectangle {
color: Color.mSurface
radius: Style.radiusM * scaling
Layout.preferredHeight: Style.baseWidgetSize * 1.2 * scaling
Layout.preferredWidth: childrenRect.width + (Style.marginS * scaling * 2)
RowLayout {
anchors.centerIn: parent
spacing: Style.marginM * scaling
// Screen Recorder
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
icon: "camera-video"
visible: ProgramCheckerService.gpuScreenRecorderAvailable
tooltipText: ScreenRecorderService.isRecording ? I18n.tr("tooltips.stop-screen-recording") : I18n.tr("tooltips.start-screen-recording")
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
onClicked: {
ScreenRecorderService.toggleRecording()
if (!ScreenRecorderService.isRecording) {
var panel = PanelService.getPanel("controlCenterPanel")
panel?.close()
}
}
}
// Wallpaper
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
visible: Settings.data.wallpaper.enabled
icon: "wallpaper-selector"
tooltipText: I18n.tr("tooltips.wallpaper-selector")
onClicked: PanelService.getPanel("wallpaperPanel")?.toggle(this)
onRightClicked: WallpaperService.setRandomWallpaper()
}
// Night Light
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
visible: ProgramCheckerService.wlsunsetAvailable
colorBg: Settings.data.nightLight.forced ? Color.mPrimary : Color.transparent
colorFg: Settings.data.nightLight.forced ? Color.mOnPrimary : Color.mPrimary
icon: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? "nightlight-forced" : "nightlight-on") : "nightlight-off"
tooltipText: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? I18n.tr("tooltips.night-light-forced") : I18n.tr("tooltips.night-light-enabled")) : I18n.tr("tooltips.night-light-disabled")
onClicked: {
if (!Settings.data.nightLight.enabled) {
Settings.data.nightLight.enabled = true
Settings.data.nightLight.forced = false
} else if (Settings.data.nightLight.enabled && !Settings.data.nightLight.forced) {
Settings.data.nightLight.forced = true
} else {
Settings.data.nightLight.enabled = false
Settings.data.nightLight.forced = false
}
}
onRightClicked: {
var settingsPanel = PanelService.getPanel("settingsPanel")
settingsPanel.requestedTab = SettingsPanel.Tab.Display
settingsPanel.open()
}
}
}
}
// Spacer
Item {
Layout.fillWidth: true
}
// Center group - Network & Caffeine
Rectangle {
color: Color.mSurface
radius: Style.radiusM * scaling
Layout.preferredHeight: Style.baseWidgetSize * 1.2 * scaling
Layout.preferredWidth: childrenRect.width + (Style.marginS * scaling * 2)
RowLayout {
anchors.centerIn: parent
spacing: Style.marginM * scaling
// Wifi
NIconButton {
id: wifiButton
baseSize: Style.baseWidgetSize * 0.9
tooltipText: I18n.tr("tooltips.manage-wifi")
icon: {
try {
if (NetworkService.ethernetConnected) {
return "ethernet"
}
let connected = false
let signalStrength = 0
for (const net in NetworkService.networks) {
if (NetworkService.networks[net].connected) {
connected = true
signalStrength = NetworkService.networks[net].signal
break
}
}
return connected ? NetworkService.signalIcon(signalStrength) : "wifi-off"
} catch (error) {
Logger.error("Wi-Fi", "Error getting icon:", error)
return "signal_wifi_bad"
}
}
onClicked: PanelService.getPanel("wifiPanel")?.toggle(this)
onRightClicked: PanelService.getPanel("wifiPanel")?.toggle(this)
}
// Bluetooth
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
tooltipText: I18n.tr("tooltips.bluetooth-devices")
icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off"
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
onRightClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
}
// Caffeine (Keep Awake)
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off"
tooltipText: IdleInhibitorService.isInhibited ? I18n.tr("tooltips.disable-keep-awake") : I18n.tr("tooltips.enable-keep-awake")
colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary
onClicked: {
IdleInhibitorService.manualToggle()
}
}
}
}
// Spacer
Item {
Layout.fillWidth: true
}
// Right group - Power Profiles
Rectangle {
color: Color.mSurface
radius: Style.radiusM * scaling
Layout.preferredHeight: Style.baseWidgetSize * 1.2 * scaling
Layout.preferredWidth: childrenRect.width + (Style.marginS * scaling * 2)
RowLayout {
anchors.centerIn: parent
spacing: Style.marginM * scaling
// Performance
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
icon: PowerProfileService.getIcon(PowerProfile.Performance)
tooltipText: I18n.tr("tooltips.set-power-profile", {
"profile": PowerProfileService.getName(PowerProfile.Performance)
})
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
colorBg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant
colorFg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mOnPrimary : Color.mPrimary
onClicked: PowerProfileService.setProfile(PowerProfile.Performance)
}
// Balanced
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
icon: PowerProfileService.getIcon(PowerProfile.Balanced)
tooltipText: I18n.tr("tooltips.set-power-profile", {
"profile": PowerProfileService.getName(PowerProfile.Balanced)
})
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
colorBg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant
colorFg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnPrimary : Color.mPrimary
onClicked: PowerProfileService.setProfile(PowerProfile.Balanced)
}
// Eco
NIconButton {
baseSize: Style.baseWidgetSize * 0.9
icon: PowerProfileService.getIcon(PowerProfile.PowerSaver)
tooltipText: I18n.tr("tooltips.set-power-profile", {
"profile": PowerProfileService.getName(PowerProfile.PowerSaver)
})
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
colorBg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant
colorFg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mOnPrimary : Color.mPrimary
onClicked: PowerProfileService.setProfile(PowerProfile.PowerSaver)
}
}
}
}
}
// ----------------------------------
// Uptime
Timer {
interval: 60000
repeat: true
running: true
onTriggered: uptimeProcess.running = true
}
Process {
id: uptimeProcess
command: ["cat", "/proc/uptime"]
running: true
stdout: StdioCollector {
onStreamFinished: {
var uptimeSeconds = parseFloat(this.text.trim().split(' ')[0])
uptimeText = Time.formatVagueHumanReadableDuration(uptimeSeconds)
uptimeProcess.running = false
}
}
}
function updateSystemInfo() {
uptimeProcess.running = true
}
}
+12 -12
View File
@@ -16,28 +16,28 @@ NBox {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Style.marginM * scaling
spacing: Style.marginM * scaling
anchors.margins: Style.marginM
spacing: Style.marginM
clip: true
RowLayout {
spacing: Style.marginS * scaling
spacing: Style.marginS
NIcon {
Layout.alignment: Qt.AlignVCenter
icon: weatherReady ? LocationService.weatherSymbolFromCode(LocationService.data.weather.current_weather.weathercode) : ""
pointSize: Style.fontSizeXXXL * 1.75 * scaling
pointSize: Style.fontSizeXXXL * 1.75
color: Color.mPrimary
}
ColumnLayout {
spacing: Style.marginXXS * scaling
spacing: Style.marginXXS
NText {
text: {
// Ensure the name is not too long if one had to specify the country
const chunks = Settings.data.location.name.split(",")
return chunks[0]
}
pointSize: Style.fontSizeL * scaling
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
}
@@ -57,13 +57,13 @@ NBox {
temp = Math.round(temp)
return `${temp}°${suffix}`
}
pointSize: Style.fontSizeXL * scaling
pointSize: Style.fontSizeXL
font.weight: Style.fontWeightBold
}
NText {
text: weatherReady ? `(${LocationService.data.weather.timezone_abbreviation})` : ""
pointSize: Style.fontSizeXS * scaling
pointSize: Style.fontSizeXS
color: Color.mOnSurfaceVariant
visible: LocationService.data.weather
}
@@ -80,12 +80,12 @@ NBox {
visible: weatherReady
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
spacing: Style.marginL * scaling
spacing: Style.marginL
Repeater {
model: weatherReady ? LocationService.data.weather.daily.time : []
delegate: ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Style.marginS * scaling
spacing: Style.marginXS
NText {
text: {
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"))
@@ -97,7 +97,7 @@ NBox {
NIcon {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index])
pointSize: Style.fontSizeXXL * 1.6 * scaling
pointSize: Style.fontSizeXXL * 1.6
color: Color.mPrimary
}
NText {
@@ -113,7 +113,7 @@ NBox {
min = Math.round(min)
return `${max}°/${min}°`
}
pointSize: Style.fontSizeXS * scaling
pointSize: Style.fontSizeXS
color: Color.mOnSurfaceVariant
}
}
+105 -24
View File
@@ -10,9 +10,39 @@ import qs.Widgets
NPanel {
id: root
preferredWidth: 480
preferredHeight: 580
panelKeyboardFocus: true
preferredWidth: Math.round(460 * Style.uiScaleRatio)
preferredHeight: {
var height = 0
var count = 0
for (var i = 0; i < Settings.data.controlCenter.cards.length; i++) {
const card = Settings.data.controlCenter.cards[i]
if (!card.enabled) {
continue
}
count++
switch (card.id) {
case "profile-card":
height += profileHeight
break
case "shortcuts-card":
height += shortcutsHeight
break
case "audio-card":
height += audioHeight
break
case "weather-card":
height += weatherHeight
break
case "media-sysmon-card":
height += mediaSysMonHeight
break
default:
break
}
}
return height + (count + 1) * Style.marginL
}
// Positioning
readonly property string controlCenterPosition: Settings.data.controlCenter.position
@@ -23,46 +53,97 @@ NPanel {
panelAnchorBottom: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.startsWith("bottom_")
panelAnchorTop: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.startsWith("top_")
readonly property int profileHeight: Math.round(64 * Style.uiScaleRatio)
readonly property int shortcutsHeight: Math.round(52 * Style.uiScaleRatio)
readonly property int audioHeight: Math.round(60 * Style.uiScaleRatio)
readonly property int weatherHeight: Math.round(190 * Style.uiScaleRatio)
readonly property int mediaSysMonHeight: Math.round(260 * Style.uiScaleRatio)
panelContent: Item {
id: content
property real cardSpacing: Style.marginL * scaling
// Layout content
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: content.cardSpacing
spacing: content.cardSpacing
x: Style.marginL
y: Style.marginL
width: parent.width - (Style.marginL * 2)
spacing: Style.marginL
// Top Card: profile + utilities
TopCard {
Layout.fillWidth: true
Layout.preferredHeight: Math.max(124 * scaling)
Repeater {
model: Settings.data.controlCenter.cards
Loader {
active: modelData.enabled
visible: active
Layout.fillWidth: true
Layout.preferredHeight: {
switch (modelData.id) {
case "profile-card":
return profileHeight
case "shortcuts-card":
return shortcutsHeight
case "audio-card":
return audioHeight
case "weather-card":
return weatherHeight
case "media-sysmon-card":
return mediaSysMonHeight
default:
return 0
}
}
sourceComponent: {
switch (modelData.id) {
case "profile-card":
return profileCard
case "shortcuts-card":
return shortcutsCard
case "audio-card":
return audioCard
case "weather-card":
return weatherCard
case "media-sysmon-card":
return mediaSysMonCard
}
}
}
}
}
// Weather
WeatherCard {
Layout.fillWidth: true
Layout.preferredHeight: Math.max(196 * scaling)
}
Component {
id: profileCard
ProfileCard {}
}
// Media + stats column
Component {
id: shortcutsCard
ShortcutsCard {}
}
Component {
id: audioCard
AudioCard {}
}
Component {
id: weatherCard
WeatherCard {}
}
Component {
id: mediaSysMonCard
RowLayout {
Layout.fillWidth: true
Layout.preferredHeight: Math.max(196 * scaling)
spacing: content.cardSpacing
spacing: Style.marginL
// Media card
MediaCard {
Layout.preferredWidth: Math.max(270 * scaling)
Layout.fillWidth: true
Layout.fillHeight: true
}
// System monitors combined in one card
SystemMonitorCard {
Layout.preferredWidth: Math.max(160 * scaling)
Layout.preferredHeight: Math.max(196 * scaling)
Layout.preferredWidth: Math.round(Style.baseWidgetSize * 2.625)
Layout.fillHeight: true
}
}
}
@@ -0,0 +1,64 @@
import QtQuick
import Quickshell
import qs.Services
import qs.Commons
Item {
id: root
property string widgetId: ""
property var widgetProps: ({})
property string screenName: widgetProps && widgetProps.screen ? widgetProps.screen.name : ""
property string section: widgetProps && widgetProps.section || ""
property int sectionIndex: widgetProps && widgetProps.sectionWidgetIndex || 0
// Don't reserve space unless the loaded widget is really visible
implicitWidth: getImplicitSize(loader.item, "implicitWidth")
implicitHeight: getImplicitSize(loader.item, "implicitHeight")
function getImplicitSize(item, prop) {
return (item && item.visible) ? item[prop] : 0
}
Loader {
id: loader
anchors.fill: parent
active: widgetId !== ""
asynchronous: false
sourceComponent: {
if (!active) {
return null
}
return ControlCenterWidgetRegistry.getWidget(widgetId)
}
onLoaded: {
if (item && widgetProps) {
// Apply properties to loaded widget
for (var prop in widgetProps) {
if (item.hasOwnProperty(prop)) {
item[prop] = widgetProps[prop]
}
}
}
if (item.hasOwnProperty("onLoaded")) {
item.onLoaded()
}
//Logger.log("ControlCenterWidgetLoader", "Loaded", widgetId, "on screen", item.screen.name)
}
Component.onDestruction: {
// Explicitly clear references
widgetProps = null
}
}
// Error handling
onWidgetIdChanged: {
if (widgetId && !ControlCenterWidgetRegistry.hasWidget(widgetId)) {
Logger.warn("ControlCenterWidgetLoader", "Widget not found in registry:", widgetId)
}
}
}
@@ -0,0 +1,13 @@
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
NIconButtonHot {
property ShellScreen screen
icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off"
tooltipText: I18n.tr("quickSettings.bluetooth.tooltip.action")
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
}
@@ -0,0 +1,14 @@
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
NIconButtonHot {
property ShellScreen screen
icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off"
hot: IdleInhibitorService.isInhibited
tooltipText: I18n.tr("quickSettings.keepAwake.tooltip.action")
onClicked: IdleInhibitorService.manualToggle()
}
@@ -0,0 +1,32 @@
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
NIconButtonHot {
property ShellScreen screen
enabled: ProgramCheckerService.wlsunsetAvailable
icon: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? "nightlight-forced" : "nightlight-on") : "nightlight-off"
hot: !Settings.data.nightLight.enabled || Settings.data.nightLight.forced
tooltipText: I18n.tr("quickSettings.nightLight.tooltip.action")
onClicked: {
if (!Settings.data.nightLight.enabled) {
Settings.data.nightLight.enabled = true
Settings.data.nightLight.forced = false
} else if (Settings.data.nightLight.enabled && !Settings.data.nightLight.forced) {
Settings.data.nightLight.forced = true
} else {
Settings.data.nightLight.enabled = false
Settings.data.nightLight.forced = false
}
}
onRightClicked: {
var settingsPanel = PanelService.getPanel("settingsPanel")
settingsPanel.requestedTab = SettingsPanel.Tab.Display
settingsPanel.open()
}
}
@@ -0,0 +1,15 @@
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
NIconButtonHot {
property ShellScreen screen
icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell"
hot: Settings.data.notifications.doNotDisturb
tooltipText: I18n.tr("quickSettings.notifications.tooltip.action")
onClicked: PanelService.getPanel("notificationHistoryPanel")?.toggle(this)
onRightClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
}
@@ -0,0 +1,21 @@
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.UPower
import qs.Commons
import qs.Services
import qs.Widgets
// Performance
NIconButtonHot {
property ShellScreen screen
readonly property bool hasPP: PowerProfileService.available
enabled: hasPP
icon: PowerProfileService.getIcon()
hot: !PowerProfileService.isDefault()
tooltipText: I18n.tr("quickSettings.powerProfile.tooltip.action")
onClicked: {
PowerProfileService.cycleProfile()
}
}
@@ -0,0 +1,21 @@
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
NIconButtonHot {
property ShellScreen screen
enabled: ProgramCheckerService.gpuScreenRecorderAvailable
icon: "camera-video"
hot: ScreenRecorderService.isRecording
tooltipText: I18n.tr("quickSettings.screenRecorder.tooltip.action")
onClicked: {
ScreenRecorderService.toggleRecording()
if (!ScreenRecorderService.isRecording) {
var panel = PanelService.getPanel("controlCenterPanel")
panel?.close()
}
}
}
@@ -0,0 +1,15 @@
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
NIconButtonHot {
property ShellScreen screen
enabled: Settings.data.wallpaper.enabled
icon: "wallpaper-selector"
tooltipText: I18n.tr("quickSettings.wallpaperSelector.tooltip.action")
onClicked: PanelService.getPanel("wallpaperPanel")?.toggle(this)
onRightClicked: WallpaperService.setRandomWallpaper()
}
+33
View File
@@ -0,0 +1,33 @@
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
NIconButtonHot {
property ShellScreen screen
icon: {
try {
if (NetworkService.ethernetConnected) {
return "ethernet"
}
let connected = false
let signalStrength = 0
for (const net in NetworkService.networks) {
if (NetworkService.networks[net].connected) {
connected = true
signalStrength = NetworkService.networks[net].signal
break
}
}
return connected ? NetworkService.signalIcon(signalStrength) : "wifi-off"
} catch (error) {
Logger.error("Wi-Fi", "Error getting icon:", error)
return "signal_wifi_bad"
}
}
tooltipText: I18n.tr("quickSettings.wifi.tooltip.action")
onClicked: PanelService.getPanel("wifiPanel")?.toggle(this)
}

Some files were not shown because too many files have changed in this diff Show More