| 1 | import QtQuick |
| 2 | import Quickshell |
| 3 | import Quickshell.Wayland |
| 4 | import Quickshell.Services.Mpris |
| 5 | |
| 6 | // Desktop layer (per monitor): clock, date, system line, now playing, cava visualizer along the bottom. |
| 7 | // Sits on the Bottom layer: above hyprpaper, below windows, never takes input. |
| 8 | PanelWindow { |
| 9 | id: win |
| 10 | required property var modelData |
| 11 | screen: modelData |
| 12 | readonly property bool showClock: Settings.desktopClock |
| 13 | readonly property bool showViz: Settings.desktopViz |
| 14 | |
| 15 | anchors { top: true; bottom: true; left: true; right: true } |
| 16 | exclusionMode: ExclusionMode.Ignore |
| 17 | color: "transparent" |
| 18 | mask: Region {} |
| 19 | WlrLayershell.layer: WlrLayer.Bottom |
| 20 | WlrLayershell.namespace: "aurora-desktop" |
| 21 | WlrLayershell.keyboardFocus: WlrKeyboardFocus.None |
| 22 | |
| 23 | SystemClock { id: clock; precision: SystemClock.Minutes } |
| 24 | |
| 25 | function pick() { |
| 26 | var l = Mpris.players.values, first = null |
| 27 | for (var i = 0; i < l.length; i++) { |
| 28 | if (l[i].isPlaying) return l[i] |
| 29 | if (first === null) first = l[i] |
| 30 | } |
| 31 | return first |
| 32 | } |
| 33 | readonly property var player: pick() |
| 34 | |
| 35 | Column { |
| 36 | visible: win.showClock |
| 37 | x: 56 |
| 38 | y: Theme.barHeight + 48 |
| 39 | spacing: 2 |
| 40 | |
| 41 | Text { |
| 42 | text: Qt.formatDateTime(clock.date, "HH:mm") |
| 43 | color: Theme.fg |
| 44 | font.family: Theme.font |
| 45 | font.pixelSize: 96 |
| 46 | font.bold: true |
| 47 | } |
| 48 | Row { |
| 49 | spacing: 10 |
| 50 | Rectangle { width: 4; height: 22; color: Theme.accent; anchors.verticalCenter: parent.verticalCenter } |
| 51 | Text { |
| 52 | text: Qt.formatDateTime(clock.date, "dddd, d MMMM").toUpperCase() |
| 53 | color: Theme.accent |
| 54 | font.family: Theme.font |
| 55 | font.pixelSize: 18 |
| 56 | font.bold: true |
| 57 | font.letterSpacing: 2 |
| 58 | } |
| 59 | } |
| 60 | Item { width: 1; height: 10 } |
| 61 | Text { |
| 62 | text: Theme.iChip + " " + Math.round(SysStats.cpu * 100) + "% " |
| 63 | + Theme.iMem + " " + SysStats.memUsed.toFixed(1) + "/" + SysStats.memTotal.toFixed(1) + "G " |
| 64 | + Theme.iClock + " up " + Theme.fmtTime(SysStats.uptime) |
| 65 | color: Theme.dim |
| 66 | font.family: Theme.font |
| 67 | font.pixelSize: Theme.fontSize + 1 |
| 68 | } |
| 69 | Text { |
| 70 | visible: win.player !== null && (win.player.trackTitle || "") !== "" |
| 71 | text: win.player ? (win.player.isPlaying ? Theme.iMusic : Theme.iPause) + " " + win.player.trackTitle |
| 72 | + (win.player.trackArtist ? " · " + win.player.trackArtist : "") : "" |
| 73 | color: win.player && win.player.isPlaying ? Theme.fg : Theme.dim |
| 74 | font.family: Theme.font |
| 75 | font.pixelSize: Theme.fontSize + 1 |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | // visualizer: bottom-up bars across the whole width |
| 80 | Row { |
| 81 | visible: win.showViz && Cava.available |
| 82 | anchors.bottom: parent.bottom |
| 83 | anchors.left: parent.left |
| 84 | anchors.right: parent.right |
| 85 | height: 180 |
| 86 | spacing: 3 |
| 87 | Repeater { |
| 88 | model: Cava.bars |
| 89 | delegate: Rectangle { |
| 90 | required property int index |
| 91 | readonly property real v: index < Cava.values.length ? Cava.values[index] : 0 |
| 92 | anchors.bottom: parent.bottom |
| 93 | width: (win.width - (Cava.bars - 1) * 3) / Cava.bars |
| 94 | height: Math.max(0, v * parent.height) |
| 95 | opacity: 0.85 |
| 96 | gradient: Gradient { |
| 97 | GradientStop { position: 0; color: Theme.accent } |
| 98 | GradientStop { position: 1; color: Theme.accentDim } |
| 99 | } |
| 100 | } |
| 101 | } |
| 102 | } |
| 103 | } |