diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-03-26 16:54:08 +1100 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-03-26 16:54:08 +1100 |
| commit | 8021e580a24fa4703238af27da3bbdee7ff4b144 (patch) | |
| tree | a72d5c76e6948f9d3632ed0b95ff8af11a081b88 /src | |
| parent | notification: body tooltip for dashboard (diff) | |
| download | caelestia-shell-8021e580a24fa4703238af27da3bbdee7ff4b144.tar.gz caelestia-shell-8021e580a24fa4703238af27da3bbdee7ff4b144.tar.bz2 caelestia-shell-8021e580a24fa4703238af27da3bbdee7ff4b144.zip | |
sidebar: connectivity pane
Bluetooth module
Diffstat (limited to 'src')
| -rw-r--r-- | src/modules/sidebar/connectivity.tsx | 7 | ||||
| -rw-r--r-- | src/modules/sidebar/index.tsx | 6 | ||||
| -rw-r--r-- | src/modules/sidebar/modules/bluetooth.tsx | 124 |
3 files changed, 135 insertions, 2 deletions
diff --git a/src/modules/sidebar/connectivity.tsx b/src/modules/sidebar/connectivity.tsx new file mode 100644 index 0000000..437e513 --- /dev/null +++ b/src/modules/sidebar/connectivity.tsx @@ -0,0 +1,7 @@ +import Bluetooth from "./modules/bluetooth"; + +export default () => ( + <box vertical className="pane connectivity" name="connectivity"> + <Bluetooth /> + </box> +); diff --git a/src/modules/sidebar/index.tsx b/src/modules/sidebar/index.tsx index 49a118b..2a13f5c 100644 --- a/src/modules/sidebar/index.tsx +++ b/src/modules/sidebar/index.tsx @@ -2,12 +2,13 @@ import type { Monitor } from "@/services/monitors"; import { bind, register, Variable } from "astal"; import { App, Astal, Gdk, Gtk, Widget } from "astal/gtk3"; import { sidebar } from "config"; +import Connectivity from "./connectivity"; import Dashboard from "./dashboard"; import NotifPane from "./notifpane"; @register() export default class SideBar extends Widget.Window { - readonly shown: Variable<string> = Variable("dashboard"); + readonly shown: Variable<string>; constructor({ monitor }: { monitor: Monitor }) { super({ @@ -20,7 +21,8 @@ export default class SideBar extends Widget.Window { visible: sidebar.showOnStartup.get(), }); - const panes = [<Dashboard />, <NotifPane />]; + const panes = [<Dashboard />, <Connectivity />, <NotifPane />]; + this.shown = Variable(panes[0].name); this.add( <eventbox diff --git a/src/modules/sidebar/modules/bluetooth.tsx b/src/modules/sidebar/modules/bluetooth.tsx new file mode 100644 index 0000000..c74a708 --- /dev/null +++ b/src/modules/sidebar/modules/bluetooth.tsx @@ -0,0 +1,124 @@ +import { bind, Variable } from "astal"; +import { Astal, Gtk } from "astal/gtk3"; +import AstalBluetooth from "gi://AstalBluetooth"; + +const sortDevices = (a: AstalBluetooth.Device, b: AstalBluetooth.Device) => { + if (a.connected || b.connected) return a.connected ? -1 : 1; + if (a.paired || b.paired) return a.paired ? -1 : 1; + return 0; +}; + +const BluetoothDevice = (device: AstalBluetooth.Device) => ( + <box className={bind(device, "connected").as(c => `device ${c ? "connected" : ""}`)}> + <icon + className="icon" + icon={bind(device, "icon").as(i => + Astal.Icon.lookup_icon(`${i}-symbolic`) ? `${i}-symbolic` : "bluetooth-symbolic" + )} + /> + <box vertical hexpand> + <label truncate xalign={0} label={bind(device, "alias")} /> + <label + truncate + className="sublabel" + xalign={0} + setup={self => { + const update = () => { + self.label = device.connected ? "Connected" : "Paired"; + self.visible = device.connected || device.paired; + }; + self.hook(device, "notify::connected", update); + self.hook(device, "notify::paired", update); + update(); + }} + /> + </box> + <button + valign={Gtk.Align.CENTER} + visible={bind(device, "paired")} + cursor="pointer" + onClicked={() => AstalBluetooth.get_default().adapter.remove_device(device)} + label="delete" + /> + <button + valign={Gtk.Align.CENTER} + cursor="pointer" + onClicked={self => { + if (device.connected) + device.disconnect_device((_, res) => { + self.sensitive = true; + device.disconnect_device_finish(res); + }); + else + device.connect_device((_, res) => { + self.sensitive = true; + device.connect_device_finish(res); + }); + self.sensitive = false; + }} + label={bind(device, "connected").as(c => (c ? "bluetooth_disabled" : "bluetooth_searching"))} + /> + </box> +); + +const List = ({ devNotify }: { devNotify: Variable<boolean> }) => ( + <box vertical valign={Gtk.Align.START} className="list"> + {bind(devNotify).as(() => AstalBluetooth.get_default().devices.sort(sortDevices).map(BluetoothDevice))} + </box> +); + +const NoDevices = () => ( + <box homogeneous name="empty"> + <box vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} className="empty"> + <label className="icon" label="bluetooth_searching" /> + <label label="No Bluetooth devices" /> + </box> + </box> +); + +export default () => { + const bluetooth = AstalBluetooth.get_default(); + const devNotify = Variable(false); // Aggregator for device state changes (connected/paired) + + const update = () => devNotify.set(!devNotify.get()); + const connectSignals = (device: AstalBluetooth.Device) => { + device.connect("notify::connected", update); + device.connect("notify::paired", update); + }; + bluetooth.get_devices().forEach(connectSignals); + bluetooth.connect("device-added", (_, device) => connectSignals(device)); + bluetooth.connect("notify::devices", update); + + return ( + <box vertical className="bluetooth"> + <box className="header-bar"> + <label + label={bind(devNotify).as(() => { + const nConnected = bluetooth.get_devices().filter(d => d.connected).length; + return `${nConnected} connected device${nConnected === 1 ? "" : "s"}`; + })} + /> + <box hexpand /> + <button + className={bind(bluetooth.adapter, "discovering").as(d => (d ? "enabled" : ""))} + cursor="pointer" + onClicked={() => { + if (bluetooth.adapter.discovering) bluetooth.adapter.start_discovery(); + else bluetooth.adapter.stop_discovery(); + }} + label=" Discovery" + /> + </box> + <stack + transitionType={Gtk.StackTransitionType.CROSSFADE} + transitionDuration={200} + shown={bind(bluetooth, "devices").as(d => (d.length > 0 ? "list" : "empty"))} + > + <NoDevices /> + <scrollable expand hscroll={Gtk.PolicyType.NEVER} name="list"> + <List devNotify={devNotify} /> + </scrollable> + </stack> + </box> + ); +}; |