Krolyxon
Commit a215858

Branches

Refs →

aurora.configquickshellauroraBar.qml

181 lines · 7.3 KB · QML

1import QtQuick
2import Quickshell
3import Quickshell.Wayland
4import Quickshell.Bluetooth
5import Quickshell.Hyprland
6import Quickshell.Services.Pipewire
7import Quickshell.Services.UPower
8
9PanelWindow {
10 id: bar
11 required property var modelData
12 screen: modelData
13 signal togglePanel(string name, var scr)
14 signal toggleOverlay(string name, var scr)
15
16 anchors { top: true; left: true; right: true }
17 implicitHeight: Theme.barHeight
18 color: Theme.barBg
19 WlrLayershell.namespace: "aurora-bar"
20
21 SystemClock { id: clock; precision: SystemClock.Minutes }
22
23 // caffeine: one inhibitor is enough, keep it on the first screen's bar
24 IdleInhibitor {
25 window: bar
26 enabled: Toggles.caffeine && bar.modelData === Quickshell.screens[0]
27 }
28
29 // ---- state ----
30 readonly property var audio: Pipewire.defaultAudioSink ? Pipewire.defaultAudioSink.audio : null
31 readonly property var mic: Pipewire.defaultAudioSource ? Pipewire.defaultAudioSource.audio : null
32 readonly property var bat: UPower.displayDevice
33 readonly property bool hasBat: bat !== null && bat.isPresent
34 readonly property real batPct: hasBat ? (bat.percentage > 1 ? bat.percentage / 100 : bat.percentage) : 0
35 readonly property bool charging: hasBat && bat.state === UPowerDeviceState.Charging
36 readonly property bool plugged: hasBat && bat.state === UPowerDeviceState.FullyCharged
37 readonly property bool batLow: hasBat && batPct <= 0.15 && !charging
38 readonly property var adapter: Bluetooth.defaultAdapter
39
40 // which Hyprland monitor this bar belongs to, and whether it has focus
41 readonly property var hmon: Hyprland.monitorFor(modelData)
42 readonly property bool monFocused: hmon !== null && hmon.focused
43
44 function findHeadset() {
45 var l = Bluetooth.devices.values
46 for (var i = 0; i < l.length; i++) {
47 var d = l[i]
48 if (!d.connected || !d.batteryAvailable) continue
49 var ic = String(d.icon)
50 if (ic.indexOf("head") >= 0 || ic.indexOf("audio") >= 0) return d
51 }
52 return null
53 }
54 function btConnected() {
55 var l = Bluetooth.devices.values
56 for (var i = 0; i < l.length; i++) if (l[i].connected) return true
57 return false
58 }
59 readonly property var headset: findHeadset()
60 readonly property bool btOn: adapter !== null && adapter.enabled
61 readonly property bool btLink: btOn && btConnected()
62
63 Item {
64 anchors.fill: parent
65
66 // ---------------- left ----------------
67 Row {
68 anchors.left: parent.left
69 height: parent.height
70 spacing: 10
71 Workspaces { height: parent.height; monitor: bar.hmon }
72 CatLoop { height: parent.height }
73 }
74
75 // ---------------- center ----------------
76 Text {
77 anchors.centerIn: parent
78 width: Math.min(implicitWidth, parent.width * 0.32)
79 elide: Text.ElideRight
80 horizontalAlignment: Text.AlignHCenter
81 readonly property string title: ToplevelManager.activeToplevel ? ToplevelManager.activeToplevel.title : ""
82 visible: bar.monFocused && title !== "" // active window is global: show it on the focused monitor only
83 text: Theme.iArch + " " + title
84 color: Theme.fg
85 font.family: Theme.font
86 font.pixelSize: Theme.fontSize
87 font.bold: true
88 }
89
90 // ---------------- right ----------------
91 Row {
92 anchors.right: parent.right
93 height: parent.height
94 spacing: 10
95
96 Tray { show: bar.monFocused }
97
98 BarPill { // click to stop recording / cancel the area selection
99 visible: Rec.busy
100 icon: Theme.iStop
101 text: Rec.running ? "rec " + Theme.fmtClock(Rec.elapsed) : "select area"
102 tint: Theme.err
103 underline: Theme.err
104 onActivated: Rec.stop()
105 }
106
107 BarPill {
108 visible: Toggles.caffeine || Toggles.airplane
109 icon: (Toggles.caffeine ? Theme.iCoffee : "") + (Toggles.caffeine && Toggles.airplane ? " " : "")
110 + (Toggles.airplane ? Theme.iPlane : "")
111 onActivated: bar.togglePanel("home", bar.modelData)
112 }
113
114 BarPill {
115 visible: bar.headset !== null
116 icon: Theme.iHeadphones
117 text: bar.headset ? Math.round(bar.headset.battery * 100) + "%" : ""
118 onActivated: bar.togglePanel("bt", bar.modelData)
119 }
120
121 BarPill {
122 visible: bar.audio !== null
123 icon: Theme.volIcon(bar.audio ? bar.audio.volume : 0, bar.audio ? bar.audio.muted : true)
124 text: (bar.audio ? Math.round(bar.audio.volume * 100) : 0) + "%"
125 + (bar.mic && bar.mic.muted ? " " + Theme.iMicOff : "")
126 onActivated: button => {
127 if (button === Qt.RightButton && bar.audio) bar.audio.muted = !bar.audio.muted
128 else if (button === Qt.MiddleButton && bar.mic) bar.mic.muted = !bar.mic.muted
129 else bar.togglePanel("audio", bar.modelData)
130 }
131 onScrolled: dir => {
132 if (bar.audio) bar.audio.volume = Math.max(0, Math.min(1, bar.audio.volume + dir * 0.02))
133 }
134 }
135
136 BarPill {
137 icon: Net.wired && !(Net.wifiEnabled && Net.connected !== "") ? Net.wiredIcon
138 : (Net.wifiEnabled ? Theme.wifiIcon(Net.connected !== "" ? Net.activeSignal : 0) : Theme.iWifiOff)
139 tint: (Net.wired || (Net.wifiEnabled && Net.connected !== "")) ? Theme.fg : Theme.dim
140 onActivated: bar.togglePanel("net", bar.modelData)
141 }
142
143 BarPill {
144 visible: bar.adapter !== null
145 icon: !bar.btOn ? Theme.iBtOff : (bar.btLink ? Theme.iBtConn : Theme.iBt)
146 tint: bar.btLink ? Theme.fg : Theme.dim
147 onActivated: bar.togglePanel("bt", bar.modelData)
148 }
149
150 BarPill {
151 visible: bar.hasBat
152 icon: Theme.batIcon(bar.batPct, bar.charging, bar.plugged)
153 text: Math.round(bar.batPct * 100) + "%"
154 tint: bar.batLow ? Theme.err : Theme.fg
155 underline: bar.batLow ? Theme.err : Theme.accent
156 onActivated: bar.togglePanel("sys", bar.modelData)
157 }
158
159 BarPill {
160 icon: Notifs.dnd ? Theme.iBellOff : Theme.iBell
161 text: Notifs.count > 0 ? String(Notifs.count) : ""
162 tint: Notifs.dnd ? Theme.dim : Theme.fg
163 onActivated: button => {
164 if (button === Qt.RightButton) Notifs.dnd = !Notifs.dnd
165 else bar.togglePanel("notif", bar.modelData)
166 }
167 }
168
169 BarPill {
170 icon: Theme.iCal
171 text: Qt.formatDateTime(clock.date, "dd MMM yyyy")
172 onActivated: bar.toggleOverlay("cal", bar.modelData)
173 }
174 BarPill {
175 icon: Theme.iClock
176 text: Qt.formatDateTime(clock.date, "HH:mm")
177 onActivated: bar.toggleOverlay("cal", bar.modelData)
178 }
179 }
180 }
181}