/ services / Bluetooth.qml
Bluetooth.qml
 1  pragma Singleton
 2  
 3  import Quickshell
 4  import Quickshell.Io
 5  import QtQuick
 6  
 7  Singleton {
 8      id: root
 9  
10      property bool powered
11      property bool discovering
12      readonly property list<Device> devices: []
13  
14      Process {
15          running: true
16          command: ["bluetoothctl"]
17          stdout: SplitParser {
18              onRead: {
19                  getInfo.running = true;
20                  getDevices.running = true;
21              }
22          }
23      }
24  
25      Process {
26          id: getInfo
27          running: true
28          command: ["sh", "-c", "bluetoothctl show | paste -s"]
29          stdout: SplitParser {
30              onRead: data => {
31                  root.powered = data.includes("Powered: yes");
32                  root.discovering = data.includes("Discovering: yes");
33              }
34          }
35      }
36  
37      Process {
38          id: getDevices
39          running: true
40          command: ["fish", "-c", `for a in (bluetoothctl devices | cut -d ' ' -f 2); bluetoothctl info $a | jq -R 'reduce (inputs / ":") as [$key, $value] ({}; .[$key | ltrimstr("\t")] = ($value | ltrimstr(" ")))' | jq -c --arg addr $a '.Address = $addr'; end | jq -sc`]
41          stdout: SplitParser {
42              onRead: data => {
43                  const devices = JSON.parse(data).filter(d => d.Name);
44                  const rDevices = root.devices;
45  
46                  const destroyed = rDevices.filter(rd => !devices.find(d => d.Address === rd.address));
47                  for (const device of destroyed)
48                      rDevices.splice(rDevices.indexOf(device), 1).forEach(d => d.destroy());
49  
50                  for (const device of devices) {
51                      const match = rDevices.find(d => d.address === device.Address);
52                      if (match) {
53                          match.lastIpcObject = device;
54                      } else {
55                          rDevices.push(deviceComp.createObject(root, {
56                              lastIpcObject: device
57                          }));
58                      }
59                  }
60              }
61          }
62      }
63  
64      component Device: QtObject {
65          required property var lastIpcObject
66          readonly property string name: lastIpcObject.Name
67          readonly property string alias: lastIpcObject.Alias
68          readonly property string address: lastIpcObject.Address
69          readonly property string icon: lastIpcObject.Icon
70          readonly property bool connected: lastIpcObject.Connected === "yes"
71          readonly property bool paired: lastIpcObject.Paired === "yes"
72          readonly property bool trusted: lastIpcObject.Trusted === "yes"
73      }
74  
75      Component {
76          id: deviceComp
77  
78          Device {}
79      }
80  }