Files
Panama/config/dot/quickshell/services/DeviceEvents.qml

122 lines
4.2 KiB
QML

pragma Singleton
// Transition-only device monitoring. Resting state is intentionally silent.
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Io
import Quickshell.Services.Pipewire
import QtQuick
Singleton {
id: root
property bool outputInitialized: false
property bool bluetoothInitialized: false
property bool kdeInitialized: false
property string previousOutput: ""
property string previousBluetooth: ""
property bool previousKdeReachable: false
property string previousKdeName: ""
PwObjectTracker { objects: [Pipewire.defaultAudioSink] }
readonly property string outputName: {
const sink = Pipewire.defaultAudioSink;
return sink?.description || sink?.nickname || sink?.name || "";
}
readonly property string bluetoothNames: {
const devices = Bluetooth.devices?.values ?? [];
return devices.filter(device => device.connected)
.map(device => device.name || device.address)
.sort()
.join("\u001f");
}
readonly property string kdeName: KdeConnect.preferredPhone?.name ?? ""
onOutputNameChanged: {
if (!root.outputInitialized) {
root.previousOutput = root.outputName;
return;
}
if (root.outputInitialized && root.outputName && root.outputName !== root.previousOutput) {
StatusEvents.publish({
key: "device-output",
glyph: "\u{F07E7}",
title: root.outputName,
detail: "Audio output selected",
priority: StatusEvents.ambientPriority
});
}
root.previousOutput = root.outputName;
}
onBluetoothNamesChanged: {
if (!root.bluetoothInitialized) {
root.previousBluetooth = root.bluetoothNames;
return;
}
if (root.bluetoothInitialized && root.bluetoothNames !== root.previousBluetooth) {
const current = root.bluetoothNames ? root.bluetoothNames.split("\u001f") : [];
const previous = root.previousBluetooth ? root.previousBluetooth.split("\u001f") : [];
const connected = current.find(name => !previous.includes(name));
const disconnected = previous.find(name => !current.includes(name));
StatusEvents.publish({
key: "device-bluetooth",
glyph: "\u{F00B1}",
title: connected || disconnected || "Bluetooth device",
detail: connected ? "Connected" : "Disconnected",
tone: connected ? "accent" : "warn",
priority: StatusEvents.ambientPriority
});
}
root.previousBluetooth = root.bluetoothNames;
}
Timer {
id: discoverySettle
interval: 1800
onTriggered: {
root.previousOutput = root.outputName;
root.previousBluetooth = root.bluetoothNames;
root.previousKdeReachable = KdeConnect.phoneReachable;
root.previousKdeName = root.kdeName;
root.outputInitialized = true;
root.bluetoothInitialized = true;
root.kdeInitialized = true;
}
}
Connections {
target: KdeConnect
function onPhoneReachableChanged(): void {
if (!root.kdeInitialized)
return;
const reachable = KdeConnect.phoneReachable;
if (reachable === root.previousKdeReachable)
return;
StatusEvents.publish({
key: "device-kdeconnect",
glyph: "\u{F03F2}",
title: root.kdeName || root.previousKdeName || "Phone",
detail: reachable ? "KDE Connect available" : "KDE Connect disconnected",
tone: reachable ? "accent" : "warn",
priority: StatusEvents.ambientPriority
});
root.previousKdeReachable = reachable;
root.previousKdeName = root.kdeName || root.previousKdeName;
}
}
Component.onCompleted: {
root.previousOutput = root.outputName;
root.previousBluetooth = root.bluetoothNames;
root.previousKdeReachable = KdeConnect.phoneReachable;
root.previousKdeName = root.kdeName;
discoverySettle.start();
}
}