74 lines
2.6 KiB
TypeScript
74 lines
2.6 KiB
TypeScript
import { App, Astal, Gtk } from "astal/gtk4";
|
|
import { bind, execAsync, Gio } from "astal";
|
|
|
|
import { hideWindow } from "@/lib/utils";
|
|
import Bluetooth from "gi://AstalBluetooth";
|
|
import Hyprland from "gi://AstalHyprland";
|
|
|
|
function DeviceMenu({ device, child }: { device: Bluetooth.Device, child?: JSX.Element }) {
|
|
const menu = Gio.Menu.new();
|
|
const copy_mac = Gio.MenuItem.new("Copy MAC address", "bt.copy_mac");
|
|
const toggle_state = Gio.MenuItem.new(device.get_connected() ? "Disconnect" : "Connect", "bt.toggle_state");
|
|
|
|
const action_group = Gio.SimpleActionGroup.new();
|
|
|
|
const copy_mac_action = Gio.SimpleAction.new("copy_mac", null);
|
|
copy_mac_action.connect("activate", () => execAsync(["wl-copy", device.address]));
|
|
|
|
const toggle_state_action = Gio.SimpleAction.new("toggle_state", null);
|
|
toggle_state_action.connect("activate", async () => {
|
|
if (device.connected)
|
|
await device.disconnect_device()
|
|
else
|
|
await device.connect_device()
|
|
})
|
|
|
|
menu.insert_item(1, copy_mac);
|
|
menu.insert_item(2, toggle_state);
|
|
|
|
action_group.insert(copy_mac_action);
|
|
action_group.insert(toggle_state_action);
|
|
|
|
return <menubutton
|
|
menuModel={menu}
|
|
setup={self => self.insert_action_group("bt", action_group)}
|
|
>
|
|
{child}
|
|
<popover>
|
|
<label label={"Copy MAC address"} />
|
|
<label label={"Toggle state"} />
|
|
</popover>
|
|
</menubutton>;
|
|
};
|
|
|
|
export default function BluetoothWindow(_monitor_id: number) {
|
|
const CENTER = Gtk.Align.CENTER;
|
|
|
|
const bt = Bluetooth.get_default();
|
|
const hypr = Hyprland.get_default();
|
|
|
|
const devices = bind(bt, "devices");
|
|
const connectedDevice = devices.as(devices => devices?.find(device => device.connected));
|
|
|
|
return <window
|
|
name={"qs_bluetooth"}
|
|
cssClasses={["qs_bluetooth"]}
|
|
monitor={bind(hypr, "focusedMonitor").as(monitor => monitor.id)}
|
|
exclusivity={Astal.Exclusivity.IGNORE}
|
|
keymode={Astal.Keymode.EXCLUSIVE}
|
|
application={App}
|
|
onKeyPressed={hideWindow}
|
|
>
|
|
<box vertical halign={CENTER} cssClasses={["inner"]} spacing={5}>
|
|
{devices.as(devices => devices.map(device =>
|
|
<DeviceMenu device={device}>
|
|
<box cssClasses={["device", "small-padding"].concat(device.connected ? ["active"] : [])} spacing={3}>
|
|
<image iconName={device.icon} />
|
|
<label>{device.alias}</label>
|
|
</box>
|
|
</DeviceMenu>
|
|
))}
|
|
</box>
|
|
</window>
|
|
}
|