Files
dotfiles/.config/quickshell/modules/BluetoothWidget.qml
T

62 lines
2.1 KiB
QML

// modules/BluetoothWidget.qml - ᛒ status / device alias
// Uses bluetoothctl via a polled Process (no BlueZ QML bindings in QS yet).
import QtQuick
import Quickshell.Io
import ".."
Pill {
id: root
property string btStatus: "off" // "off" | "on" | "connected"
property string devAlias: ""
readonly property var bgColors: ({
"off": Qt.rgba(0.565, 0.545, 0.671, 0.3), // alpha(@color3, 0.3)
"on": Theme.color2,
"connected": Theme.color4,
})
// Override Pill's own color binding
color: bgColors[btStatus] ?? Theme.pill
onClicked: (m) => {
if (m.button === Qt.LeftButton)
Exec.run(["blueman-manager"])
}
Text {
text: {
var s = root.btStatus
if (s === "connected") return "ᛒ " + (root.devAlias || "connected")
if (s === "on") return "ᛒ on"
return "ᛒ off"
}
font { family: Theme.fontSans; pixelSize: Theme.fontSize }
color: Theme.foreground
}
// Poll bluetoothctl show + info every 5 s
Process {
id: btProc
running: false
command: ["bash", "-c",
"bluetoothctl show | grep -E 'Powered|Name'; " +
"bluetoothctl info 2>/dev/null | grep -E 'Name|Connected'"]
stdout: SplitParser {
onRead: (line) => {
if (/Powered:\s+no/i.test(line)) { root.btStatus = "off"; root.devAlias = "" }
if (/Powered:\s+yes/i.test(line)) { if (root.btStatus === "off") root.btStatus = "on" }
if (/Connected:\s+yes/i.test(line)) root.btStatus = "connected"
if (/Connected:\s+no/i.test(line)) { if (root.btStatus === "connected") { root.btStatus = "on"; root.devAlias = "" } }
var match = /^\s+Name:\s+(.+)/.exec(line)
if (match && root.btStatus === "connected") root.devAlias = match[1].trim()
}
}
onExited: btProc.running = false
}
Timer {
interval: 5000; running: true; repeat: true
triggeredOnStart: true
onTriggered: btProc.running = true
}
}