385 lines
13 KiB
JavaScript
385 lines
13 KiB
JavaScript
const bluetooth = await Service.import("bluetooth");
|
|
import DropdownMenu from "../DropdownMenu.js";
|
|
|
|
export default () => {
|
|
bluetooth.connect("changed", (value) => {
|
|
// console.log(JSON.stringify(value, null, 2));
|
|
});
|
|
|
|
const connectedDevices = (btDevices) => {
|
|
const noDevices = () => {
|
|
return Widget.Box({
|
|
hpack: "start",
|
|
hexpand: true,
|
|
child: Widget.Label({
|
|
class_name: "dim",
|
|
label: "No devices connected",
|
|
}),
|
|
});
|
|
};
|
|
|
|
const deviceList = () => {
|
|
return Widget.Box({
|
|
vertical: true,
|
|
children: btDevices.map((dev) =>
|
|
Widget.Box({
|
|
child: Widget.Box({
|
|
children: [
|
|
Widget.Box({
|
|
hpack: "start",
|
|
vertical: true,
|
|
children: [
|
|
Widget.Box({
|
|
children: [
|
|
Widget.Button({
|
|
child: Widget.Icon(`${dev["icon-name"]}-symbolic`),
|
|
}),
|
|
Widget.Label({
|
|
class_name: "menu-button-name bluetooth",
|
|
truncate: "end",
|
|
wrap: true,
|
|
label: dev.alias,
|
|
}),
|
|
],
|
|
}),
|
|
Widget.Box({
|
|
class_name: "menu-button-name-container status dim",
|
|
children: [
|
|
Widget.Label({
|
|
class_name: "menu-button-name status dim",
|
|
label: dev.connected
|
|
? "Connected"
|
|
: dev.paired
|
|
? "Paired"
|
|
: "",
|
|
}),
|
|
],
|
|
}),
|
|
],
|
|
}),
|
|
Widget.Box({
|
|
hpack: "end",
|
|
expand: true,
|
|
children: [
|
|
Widget.Button({
|
|
class_name: "menu-icon-button unpair bluetooth",
|
|
child: Widget.Label({
|
|
tooltip_text: dev.paired ? "unpair" : "pair",
|
|
class_name: "menu-icon-button-label unpair bluetooth",
|
|
label: dev.paired ? "" : "",
|
|
}),
|
|
on_primary_click: () =>
|
|
Utils.execAsync(
|
|
`bluetoothctl ${dev.paired ? "unpair" : "pair"} ${dev.address}`,
|
|
).catch((err) =>
|
|
console.error(
|
|
`bluetoothctl ${dev.paired ? "unpair" : "pair"} ${dev.address}`,
|
|
err,
|
|
),
|
|
),
|
|
}),
|
|
Widget.Button({
|
|
class_name: "menu-icon-button disconnect bluetooth",
|
|
child: Widget.Label({
|
|
tooltip_text: dev.connected ? "disconnect" : "connect",
|
|
class_name:
|
|
"menu-icon-button-label disconnect bluetooth",
|
|
label: dev.connected ? "" : "",
|
|
}),
|
|
on_primary_click: () =>
|
|
Utils.execAsync(
|
|
`bluetoothctl ${dev.connected ? "disconnect" : "connect"} ${dev.address}`,
|
|
).catch((err) =>
|
|
console.error(
|
|
`bluetoothctl ${dev.connected ? "disconnect" : "connect"} ${dev.address}`,
|
|
err,
|
|
),
|
|
),
|
|
}),
|
|
Widget.Button({
|
|
class_name: "menu-icon-button untrust bluetooth",
|
|
child: Widget.Label({
|
|
tooltip_text: dev.trusted ? "untrust" : "trust",
|
|
class_name: "menu-icon-button-label untrust bluetooth",
|
|
label: dev.trusted ? "" : "",
|
|
}),
|
|
on_primary_click: () =>
|
|
Utils.execAsync(
|
|
`bluetoothctl ${dev.trusted ? "untrust" : "trust"} ${dev.address}`,
|
|
).catch((err) =>
|
|
console.error(
|
|
`bluetoothctl ${dev.trusted ? "untrust" : "trust"} ${dev.address}`,
|
|
err,
|
|
),
|
|
),
|
|
}),
|
|
Widget.Button({
|
|
class_name: "menu-icon-button delete bluetooth",
|
|
child: Widget.Label({
|
|
tooltip_text: "delete",
|
|
class_name: "menu-icon-button-label delete bluetooth",
|
|
label: "",
|
|
}),
|
|
on_primary_click: () =>
|
|
Utils.execAsync(
|
|
`bluetoothctl remove ${dev.address}`,
|
|
).catch((err) =>
|
|
console.error("Bluetooth Remove", err),
|
|
),
|
|
}),
|
|
],
|
|
}),
|
|
],
|
|
}),
|
|
}),
|
|
),
|
|
});
|
|
};
|
|
|
|
return btDevices.length === 0 ? noDevices() : deviceList();
|
|
};
|
|
|
|
const renderDevices = (btDevices) => {
|
|
return btDevices
|
|
.filter(
|
|
(device) =>
|
|
device.name !== null &&
|
|
!bluetooth.connected_devices.find(
|
|
(dev) => dev.address === device.address,
|
|
),
|
|
)
|
|
.map((device) => {
|
|
return Widget.Button({
|
|
class_name: `menu-button bluetooth ${device}`,
|
|
on_primary_click: () => {
|
|
Utils.execAsync(`bluetoothctl connect ${device.address}`).catch(
|
|
(err) =>
|
|
console.error(`bluetoothctl connect ${device.address}`, err),
|
|
);
|
|
Utils.execAsync(`bluetoothctl pair ${device.address}`).catch(
|
|
(err) =>
|
|
console.error(`bluetoothctl pair ${device.address}`, err),
|
|
);
|
|
},
|
|
child: Widget.Box({
|
|
children: [
|
|
Widget.Box({
|
|
hpack: "start",
|
|
children: [
|
|
Widget.Icon({
|
|
class_name: bluetooth
|
|
.bind("connected_devices")
|
|
.as((btDevices) =>
|
|
btDevices.find((cd) => cd.alias === device.alias)
|
|
? "menu-button-icon active bluetooth"
|
|
: "menu-button-icon bluetooth",
|
|
),
|
|
icon: `${device["icon-name"]}-symbolic`,
|
|
}),
|
|
Widget.Label({
|
|
class_name: bluetooth
|
|
.bind("connected_devices")
|
|
.as((btDevices) =>
|
|
btDevices.find((cd) => cd.alias === device.alias)
|
|
? "menu-button-name active bluetooth"
|
|
: "menu-button-name bluetooth",
|
|
),
|
|
truncate: "end",
|
|
wrap: true,
|
|
label: device.alias,
|
|
}),
|
|
],
|
|
}),
|
|
Widget.Box({
|
|
hpack: "end",
|
|
expand: true,
|
|
children: [
|
|
Widget.Label({
|
|
class_name: "menu-button-isactive bluetooth",
|
|
label: bluetooth
|
|
.bind("connected_devices")
|
|
.as((btDevices) =>
|
|
btDevices.find((cd) => cd.alias === device.alias)
|
|
? " "
|
|
: "",
|
|
),
|
|
}),
|
|
],
|
|
}),
|
|
],
|
|
}),
|
|
});
|
|
});
|
|
};
|
|
|
|
const bluetoothOnModule = () => {
|
|
return Widget.Box({
|
|
vertical: true,
|
|
children: [
|
|
Widget.Box({
|
|
class_name: "menu-active-container bluetooth",
|
|
vertical: true,
|
|
// children: renderActivePlayback(),
|
|
}),
|
|
Widget.Box({
|
|
class_name: "menu-active-container bluetooth",
|
|
vertical: true,
|
|
// children: renderActiveInput(),
|
|
}),
|
|
Widget.Separator({
|
|
class_name: "menu-separator",
|
|
}),
|
|
Widget.Box({
|
|
class_name: "menu-container bluetooth",
|
|
children: [
|
|
Widget.Box({
|
|
vertical: true,
|
|
children: [
|
|
Widget.Box({
|
|
class_name: "menu-label-container bluetooth",
|
|
children: [
|
|
Widget.Box({
|
|
hpack: "start",
|
|
child: Widget.Label({
|
|
class_name: "menu-label bluetooth",
|
|
label: "Devices",
|
|
}),
|
|
}),
|
|
Widget.Box({
|
|
hexpand: true,
|
|
hpack: "end",
|
|
child: Widget.Button({
|
|
class_name: "menu-icon-button",
|
|
on_primary_click: () =>
|
|
Utils.execAsync(
|
|
"bluetoothctl --timeout 120 scan on",
|
|
).catch((err) =>
|
|
console.error(
|
|
"bluetoothctl --timeout 120 scan on",
|
|
err,
|
|
),
|
|
),
|
|
child: Widget.Icon("view-refresh-symbolic"),
|
|
}),
|
|
}),
|
|
],
|
|
}),
|
|
Widget.Box({
|
|
vertical: true,
|
|
children: bluetooth
|
|
.bind("devices")
|
|
.as((v) => renderDevices(v)),
|
|
}),
|
|
],
|
|
}),
|
|
],
|
|
}),
|
|
],
|
|
});
|
|
};
|
|
|
|
const bluetoothOffModule = () => {
|
|
return Widget.Box({
|
|
class_name: "bluetooth-disabled-menu",
|
|
vertical: true,
|
|
children: [
|
|
Widget.Label({
|
|
hexpand: true,
|
|
vexpand: true,
|
|
label: bluetooth
|
|
.bind("state")
|
|
.as((state) =>
|
|
state === "turning-off"
|
|
? "Bluetooth is turning off..."
|
|
: "Bluetooth is disabled",
|
|
),
|
|
}),
|
|
],
|
|
});
|
|
};
|
|
return DropdownMenu({
|
|
name: "bluetoothmenu",
|
|
transition: "crossfade",
|
|
minWidth: 325,
|
|
child: Widget.Box({
|
|
class_name: "menu-items",
|
|
child: Widget.Box({
|
|
vertical: true,
|
|
class_name: "menu-items-container",
|
|
children: [
|
|
Widget.Box({
|
|
class_name: "menu-dropdown-label-container",
|
|
children: [
|
|
Widget.Box({
|
|
hexpand: true,
|
|
hpack: "start",
|
|
child: Widget.Label({
|
|
class_name: "menu-dropdown-label bluetooth",
|
|
label: "Bluetooth",
|
|
}),
|
|
}),
|
|
Widget.Box({
|
|
hexpand: true,
|
|
hpack: "end",
|
|
child: Widget.Switch({
|
|
class_name: "menu-switch bluetooth",
|
|
active: bluetooth.enabled,
|
|
setup: (self) => {
|
|
bluetooth.connect("changed", ({ enabled }) => {
|
|
self.set_property("active", enabled);
|
|
});
|
|
},
|
|
on_activate: ({ active }) =>
|
|
Utils.execAsync(
|
|
`bluetoothctl power ${active ? "on" : "off"}`,
|
|
).catch((err) =>
|
|
console.error(
|
|
`bluetoothctl power ${active ? "on" : "off"}`,
|
|
err,
|
|
),
|
|
),
|
|
}),
|
|
}),
|
|
],
|
|
}),
|
|
Widget.Separator({
|
|
class_name: "menu-separator",
|
|
}),
|
|
Widget.Box({
|
|
vertical: true,
|
|
children: bluetooth.bind("enabled").as((isOn) =>
|
|
isOn
|
|
? [
|
|
Widget.Box({
|
|
class_name: "menu-label-container",
|
|
child: Widget.Label({
|
|
class_name: "menu-label bluetooth",
|
|
hpack: "start",
|
|
label: "My Devices",
|
|
}),
|
|
}),
|
|
Widget.Box({
|
|
vertical: true,
|
|
class_name: "menu-item-box",
|
|
child: bluetooth
|
|
.bind("connected_devices")
|
|
.as((btConDevs) => connectedDevices(btConDevs)),
|
|
}),
|
|
]
|
|
: [],
|
|
),
|
|
}),
|
|
Widget.Box({
|
|
vertical: true,
|
|
child: bluetooth
|
|
.bind("enabled")
|
|
.as((btEnabled) =>
|
|
btEnabled ? bluetoothOnModule() : bluetoothOffModule(),
|
|
),
|
|
}),
|
|
],
|
|
}),
|
|
}),
|
|
});
|
|
};
|