253 lines
8.3 KiB
TypeScript

import { bind, interval, readFile, timeout, writeFile } from "astal";
import { Gtk } from "astal/gtk4";
import AstalBluetooth from "gi://AstalBluetooth";
import BTDevice from "./Device";
const ALIGN = Gtk.Align;
const MAX_RETRY = 20;
const bt = AstalBluetooth.get_default();
// const LaunchBluetoothModule = () => {
// const box = new Gtk.Box();
//
// const placeholder = () => {
// return <button cssClasses={["toggle-button"]} child={
// <box>
// <label
// cssClasses={['title-2']}
// label={"Bluetooth"}></label>
// <label label={"Backend missing"}></label>
// </box>
// }>
// </button>
// }
//
// if (bt.adapter) {
// box.append(BluetoothModule());
// } else {
// const p = placeholder();
// box.append(p);
//
// let count = 0;
// const i = interval(1000, () => {
// if (bt.adapter !== null) {
// box.remove(p);
// box.append(BluetoothModule());
// i.cancel();
// } else if (count >= MAX_RETRY) {
// i.cancel();
// }
// count++;
// });
// }
//
// return box;
// }
const BluetoothModule = () => {
return (
<box>
<button
cssClasses={bind(bt, "isPowered").as(powered =>
powered
? ["toggle-button", "toggle-on"]
: ["toggle-button"],
)}
onClicked={() => {
try {
bt.adapter.set_powered(!bt.adapter.get_powered())
} catch (_) { }
}}
child={
<box vertical>
<label
cssClasses={["title-2"]}
label={"Bluetooth"}
halign={ALIGN.CENTER}
valign={ALIGN.CENTER}
></label>
<box halign={ALIGN.CENTER} valign={ALIGN.CENTER}>
<label
visible={bind(bt, "isPowered").as(
p => !p,
)}
label="Disabled"
></label>
<label
visible={bind(bt, "isPowered")}
label={bind(bt, "devices").as(devices => {
let count = 0;
devices.forEach(device => {
if (device.connected) {
count++;
}
});
return `On (${count} ${count === 1 ? "client" : "clients"} connected)`;
})}
></label>
</box>
<label></label>
</box>
}
></button>
<button
cssClasses={["actions-button"]}
visible={bind(bt, "isPowered")}
child={
<box>
<image iconName={"arrow-right-symbolic"}></image>
{picker}
</box>
}
tooltipText={"View available devices"}
onClicked={() => openBTPicker()}
></button>
</box>
);
};
const openBTPicker = () => {
picker.popup();
try {
bt.adapter.start_discovery();
} catch (_) { }
};
const BluetoothPickerList = () => {
let btEnableState = false;
try {
btEnableState = readFile("./btconf") === "true" ? true : false;
} catch (_) { }
if (bt.get_adapter()) {
print('Setting BT state to ' + btEnableState);
bt.adapter.set_powered(btEnableState);
} else {
timeout(5000, () => {
if (bt.get_adapter()) {
print('Setting BT state to ' + btEnableState);
bt.adapter.set_powered(btEnableState);
} else {
timeout(5000, () => {
try {
bt.adapter.set_powered(btEnableState);
} catch (_) { }
})
}
})
}
const updateState = () => {
btEnableState = !btEnableState;
writeFile("./btconf", "" + btEnableState);
};
return (
<box
vertical
onDestroy={() => {
try {
bt.adapter.stop_discovery()
} catch (_) { }
}}
cssClasses={["popover-box"]}
>
<label cssClasses={["title"]} label={"Bluetooth"}></label>
<Gtk.Separator marginTop={3} marginBottom={5}></Gtk.Separator>
<centerbox
startWidget={<label label={"Turn on at startup"}></label>}
endWidget={
<switch
valign={ALIGN.END}
halign={ALIGN.END}
active={btEnableState}
onButtonPressed={() => updateState()}
></switch>
}
></centerbox>
<label
marginTop={10}
label={"Connected & Trusted devices"}
cssClasses={["title-2"]}
></label>
<Gtk.Separator marginTop={3} marginBottom={5}></Gtk.Separator>
<box vertical cssClasses={["devices-list"]}>
{bind(bt, "devices").as(devices => {
return devices
.filter(device => {
if (device.get_connected() || device.get_paired()) {
return device;
}
})
.map(device => {
return <BTDevice device={device}></BTDevice>;
});
})}
</box>
<label
visible={bind(bt, "devices").as(devices => {
return (
devices.filter(device => {
if (device.get_connected() || device.get_paired()) {
return device;
}
}).length === 0
);
})}
label={"No connected / trusted devices"}
cssClasses={["bt-no-found", "bt-conn-list"]}
></label>
<label
label={"Discovered bluetooth devices"}
cssClasses={["title-2"]}
></label>
<Gtk.Separator marginBottom={5} marginTop={3}></Gtk.Separator>
<box vertical>
{bind(bt, "devices").as(devices => {
return devices
.filter(data => {
if (!data.get_connected() && !data.get_paired()) {
return data;
}
})
.map(device => {
return <BTDevice device={device}></BTDevice>;
});
})}
</box>
<label
visible={bind(bt, "devices").as(devices => {
return (
devices.filter(device => {
if (
!device.get_connected() &&
!device.get_paired()
) {
return device;
}
}).length === 0
);
})}
label={"No discovered devices"}
cssClasses={["bt-no-found"]}
></label>
</box>
);
};
const BluetoothPicker = () => {
const popover = new Gtk.Popover();
popover.set_child(BluetoothPickerList());
popover.connect("closed", () => bt.adapter.stop_discovery());
return popover;
};
const picker = BluetoothPicker();
export default {
BluetoothModule,
};