[AGS] Bar: Done (WiFi still missing, will be added at some later point)
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
import { bind, readFile, Variable, writeFile } from "astal";
|
||||
import { Gtk } from "astal/gtk4";
|
||||
import AstalBluetooth from "gi://AstalBluetooth";
|
||||
import BTDevice from "./Device";
|
||||
const ALIGN = Gtk.Align;
|
||||
|
||||
const bt = AstalBluetooth.get_default();
|
||||
|
||||
const BluetoothModule = () => {
|
||||
return (
|
||||
<box>
|
||||
<button
|
||||
cssClasses={bind(bt.adapter, "powered").as(powered =>
|
||||
powered
|
||||
? ["toggle-button", "toggle-on"]
|
||||
: ["toggle-button"],
|
||||
)}
|
||||
onClicked={() =>
|
||||
bt.adapter.set_powered(!bt.adapter.get_powered())
|
||||
}
|
||||
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.adapter, "powered").as(
|
||||
p => !p,
|
||||
)}
|
||||
label="Disabled"
|
||||
></label>
|
||||
<label
|
||||
visible={bind(bt.adapter, "powered")}
|
||||
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.adapter, "powered")}
|
||||
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 = readFile("./btconf") === "true" ? true : false;
|
||||
bt.adapter.set_powered(btEnableState);
|
||||
|
||||
const updateState = () => {
|
||||
btEnableState = !btEnableState;
|
||||
writeFile("./btconf", "" + btEnableState);
|
||||
};
|
||||
|
||||
return (
|
||||
<box
|
||||
vertical
|
||||
onDestroy={() => bt.adapter.stop_discovery()}
|
||||
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,
|
||||
};
|
@@ -0,0 +1,72 @@
|
||||
import { bind } from "astal";
|
||||
import AstalBluetooth from "gi://AstalBluetooth";
|
||||
|
||||
const BTDevice = ({ device }: { device: AstalBluetooth.Device }) => {
|
||||
return (
|
||||
<button
|
||||
visible={bind(device, "name").as(n => n !== null)}
|
||||
child={
|
||||
<centerbox
|
||||
startWidget={
|
||||
<box>
|
||||
<image
|
||||
iconName={"chronometer-reset"}
|
||||
tooltipText={"Device is currently connecting"}
|
||||
visible={bind(device, "connecting")}
|
||||
></image>
|
||||
<image
|
||||
iconName={bind(device, "icon")}
|
||||
marginEnd={3}
|
||||
></image>
|
||||
</box>
|
||||
}
|
||||
centerWidget={
|
||||
<label
|
||||
label={bind(device, "name").as(n => n ?? "No name")}
|
||||
marginEnd={5}
|
||||
></label>
|
||||
}
|
||||
endWidget={
|
||||
<box>
|
||||
<label
|
||||
label={bind(device, "batteryPercentage").as(
|
||||
bat => (bat >= 0 ? bat + "%" : "?%"),
|
||||
)}
|
||||
tooltipText={"Device's battery percentage"}
|
||||
marginEnd={3}
|
||||
></label>
|
||||
<image
|
||||
iconName={bind(device, "paired").as(v =>
|
||||
v ? "network-bluetooth-activated-symbolic" : "bluetooth-disconnected-symbolic",
|
||||
)}
|
||||
></image>
|
||||
<button tooltipText={"Device trusted status"} child={
|
||||
<image
|
||||
iconName={bind(device, "trusted").as(v =>
|
||||
v ? "checkbox" : "window-close-symbolic",
|
||||
)}
|
||||
></image>
|
||||
} onClicked={() => device.set_trusted( !device.get_trusted() )}
|
||||
cssClasses={[ 'button-no-margin' ]}
|
||||
></button>
|
||||
</box>
|
||||
}
|
||||
></centerbox>
|
||||
}
|
||||
onClicked={() => {
|
||||
connectOrPair( device );
|
||||
}}
|
||||
></button>
|
||||
);
|
||||
};
|
||||
|
||||
const connectOrPair = (device: AstalBluetooth.Device) => {
|
||||
if ( device.get_paired() ) {
|
||||
device.connect_device(() => { });
|
||||
// Show failed message if tried to connect and failed
|
||||
} else {
|
||||
device.pair();
|
||||
}
|
||||
};
|
||||
|
||||
export default BTDevice;
|
Reference in New Issue
Block a user