diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-01-17 00:16:40 +1100 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-01-17 00:16:40 +1100 |
| commit | 0518ec4214583bcc26f5b052f02fd93b12a00a77 (patch) | |
| tree | 0cfac1c39d54a504215a4b98c8be271e66759295 | |
| parent | refactor: move popdowns to own folder (diff) | |
| download | caelestia-shell-0518ec4214583bcc26f5b052f02fd93b12a00a77.tar.gz caelestia-shell-0518ec4214583bcc26f5b052f02fd93b12a00a77.tar.bz2 caelestia-shell-0518ec4214583bcc26f5b052f02fd93b12a00a77.zip | |
bluetoothdevices: make popup window
| -rw-r--r-- | scss/popdowns/bluetoothdevices.scss | 43 | ||||
| -rw-r--r-- | scss/popdowns/index.scss | 3 | ||||
| -rw-r--r-- | scss/popdowns/notifications.scss (renamed from scss/notifications.scss) | 6 | ||||
| -rw-r--r-- | scss/popdowns/updates.scss (renamed from scss/updates.scss) | 14 | ||||
| -rw-r--r-- | src/modules/bar.tsx | 37 | ||||
| -rw-r--r-- | src/modules/popdowns/bluetoothdevices.tsx | 93 | ||||
| -rw-r--r-- | src/modules/popdowns/index.tsx | 2 | ||||
| -rw-r--r-- | src/modules/popdowns/notifications.tsx | 2 | ||||
| -rw-r--r-- | src/widgets/popdownwindow.tsx | 15 | ||||
| -rw-r--r-- | style.scss | 3 |
10 files changed, 179 insertions, 39 deletions
diff --git a/scss/popdowns/bluetoothdevices.scss b/scss/popdowns/bluetoothdevices.scss new file mode 100644 index 0000000..e426b27 --- /dev/null +++ b/scss/popdowns/bluetoothdevices.scss @@ -0,0 +1,43 @@ +@use "sass:color"; +@use "../scheme"; +@use "../lib"; +@use "../font"; + +$-accent: scheme.$rosewater; + +.bluetooth-devices { + @include lib.popdown-window($-accent); + + min-width: lib.s(500); + min-height: lib.s(400); + + .list { + @include lib.spacing($vertical: true); + + color: scheme.$text; + + .device { + @include lib.spacing(8); + + .icon { + font-size: lib.s(18); + } + + button { + @include lib.rounded(5); + @include lib.element-decel; + + padding: lib.s(3) lib.s(8); + + &:hover, + &:focus { + background-color: scheme.$surface0; + } + + &:active { + background-color: scheme.$surface1; + } + } + } + } +} diff --git a/scss/popdowns/index.scss b/scss/popdowns/index.scss new file mode 100644 index 0000000..81855d3 --- /dev/null +++ b/scss/popdowns/index.scss @@ -0,0 +1,3 @@ +@forward "notifications"; +@forward "updates"; +@forward "bluetoothdevices"; diff --git a/scss/notifications.scss b/scss/popdowns/notifications.scss index e955a4c..c7914c2 100644 --- a/scss/notifications.scss +++ b/scss/popdowns/notifications.scss @@ -1,7 +1,7 @@ @use "sass:color"; -@use "scheme"; -@use "lib"; -@use "font"; +@use "../scheme"; +@use "../lib"; +@use "../font"; @mixin popup($accent) { .separator { diff --git a/scss/updates.scss b/scss/popdowns/updates.scss index 12da977..d11a551 100644 --- a/scss/updates.scss +++ b/scss/popdowns/updates.scss @@ -1,12 +1,12 @@ @use "sass:color"; -@use "scheme"; -@use "lib"; -@use "font"; +@use "../scheme"; +@use "../lib"; +@use "../font"; -$accent: scheme.$blue; +$-accent: scheme.$blue; .updates { - @include lib.popdown-window($accent); + @include lib.popdown-window($-accent); min-width: lib.s(600); min-height: lib.s(400); @@ -16,11 +16,11 @@ $accent: scheme.$blue; &:hover, &:focus { - color: color.mix($accent, scheme.$base, 80%); + color: color.mix($-accent, scheme.$base, 80%); } &:active { - color: color.mix($accent, scheme.$base, 60%); + color: color.mix($-accent, scheme.$base, 60%); } } diff --git a/src/modules/bar.tsx b/src/modules/bar.tsx index 1bcbc08..0bc4485 100644 --- a/src/modules/bar.tsx +++ b/src/modules/bar.tsx @@ -36,6 +36,14 @@ const hookFocusedClientProp = ( callback(lastClient); }; +const togglePopup = (self: JSX.Element, event: Astal.ClickEvent, name: string) => { + const popup = App.get_window(name) as PopupWindow | null; + if (popup) { + if (popup.visible) popup.hide(); + else popup.popup_at_widget(self, event); + } +}; + const OSIcon = () => <label className="module os-icon" label={osIcon} />; const ActiveWindow = () => ( @@ -315,10 +323,9 @@ const Network = () => ( const Bluetooth = () => ( <button - onClick={(_, event) => { - if (event.button === Astal.MouseButton.PRIMARY) { - // TODO: bluetooth panel - } else if (event.button === Astal.MouseButton.SECONDARY) AstalBluetooth.get_default().toggle(); + onClick={(self, event) => { + if (event.button === Astal.MouseButton.PRIMARY) togglePopup(self, event, "bluetooth-devices"); + else if (event.button === Astal.MouseButton.SECONDARY) AstalBluetooth.get_default().toggle(); else if (event.button === Astal.MouseButton.MIDDLE) execAsync("uwsm app -- blueman-manager").catch(console.error); }} @@ -366,15 +373,7 @@ const StatusIcons = () => ( const PkgUpdates = () => ( <button - onClick={(self, event) => { - if (event.button === Astal.MouseButton.PRIMARY) { - const popup = App.get_window("updates") as PopupWindow | null; - if (popup) { - if (popup.visible) popup.hide(); - else popup.popup_at_widget(self, event); - } - } - }} + onClick={(self, event) => event.button === Astal.MouseButton.PRIMARY && togglePopup(self, event, "updates")} setup={self => setupCustomTooltip( self, @@ -391,15 +390,9 @@ const PkgUpdates = () => ( const NotifCount = () => ( <button - onClick={(self, event) => { - if (event.button === Astal.MouseButton.PRIMARY) { - const popup = App.get_window("notifications") as PopupWindow | null; - if (popup) { - if (popup.visible) popup.hide(); - else popup.popup_at_widget(self, event); - } - } - }} + onClick={(self, event) => + event.button === Astal.MouseButton.PRIMARY && togglePopup(self, event, "notifications") + } setup={self => setupCustomTooltip( self, diff --git a/src/modules/popdowns/bluetoothdevices.tsx b/src/modules/popdowns/bluetoothdevices.tsx new file mode 100644 index 0000000..f41516a --- /dev/null +++ b/src/modules/popdowns/bluetoothdevices.tsx @@ -0,0 +1,93 @@ +import { bind, Variable } from "astal"; +import { Gtk } from "astal/gtk3"; +import AstalBluetooth from "gi://AstalBluetooth"; +import PopdownWindow from "../../widgets/popdownwindow"; + +const BluetoothDevice = (device: AstalBluetooth.Device) => ( + <box className="device"> + <icon className="icon" icon={bind(device, "icon").as(i => `${i}-symbolic`)} /> + <label + truncate + xalign={0} + setup={self => { + const update = () => + (self.label = `${device.alias}${ + device.connected || device.paired ? ` (${device.connected ? "Connected" : "Paired"})` : "" + }`); + self.hook(device, "notify::alias", update); + self.hook(device, "notify::connected", update); + self.hook(device, "notify::paired", update); + update(); + }} + /> + <box hexpand /> + <button + 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 ? "Disconnect" : "Connect"))} + /> + <button + cursor="pointer" + onClicked={() => AstalBluetooth.get_default().adapter.remove_device(device)} + label="Remove" + /> + </box> +); + +const List = () => ( + <box vertical valign={Gtk.Align.START} className="list"> + {bind(AstalBluetooth.get_default(), "devices").as(d => d.map(BluetoothDevice))} + </box> +); + +export default () => { + const bluetooth = AstalBluetooth.get_default(); + const label = Variable(""); + + const update = () => { + const devices = bluetooth.get_devices(); + const connected = devices.filter(d => d.connected).length; + label.set(`${connected} connected device${connected === 1 ? "" : "s"} (${devices.length} available)`); + }; + bluetooth.get_devices().forEach(d => d.connect("notify::connected", update)); + bluetooth.connect("device-added", (_, device) => device.connect("notify::connected", update)); + bluetooth.connect("notify::devices", update); + update(); + + return ( + <PopdownWindow + name="bluetooth-devices" + count={bind(bluetooth, "devices").as(n => n.length)} + countLabel={bind(label)} + headerButtons={[ + { + label: bind(bluetooth, "isPowered").as(p => (p ? "Disable" : "Enable")), + onClicked: () => bluetooth.toggle(), + }, + { + label: "Discovery", + onClicked: () => { + if (bluetooth.adapter.discovering) bluetooth.adapter.start_discovery(); + else bluetooth.adapter.stop_discovery(); + }, + enabled: bind(bluetooth.adapter, "discovering"), + }, + ]} + emptyIcon="bluetooth_disabled" + emptyLabel="No Bluetooth devices" + list={<List />} + /> + ); +}; diff --git a/src/modules/popdowns/index.tsx b/src/modules/popdowns/index.tsx index db3245b..ee6208d 100644 --- a/src/modules/popdowns/index.tsx +++ b/src/modules/popdowns/index.tsx @@ -1,9 +1,11 @@ +import BluetoothDevices from "./bluetoothdevices"; import Notifications from "./notifications"; import Updates from "./updates"; export default () => { <Notifications />; <Updates />; + <BluetoothDevices />; return null; }; diff --git a/src/modules/popdowns/notifications.tsx b/src/modules/popdowns/notifications.tsx index bb08c13..4ab0095 100644 --- a/src/modules/popdowns/notifications.tsx +++ b/src/modules/popdowns/notifications.tsx @@ -51,7 +51,7 @@ export default () => ( { label: "Silence", onClicked: () => (AstalNotifd.get_default().dontDisturb = !AstalNotifd.get_default().dontDisturb), - className: bind(AstalNotifd.get_default(), "dontDisturb").as(d => (d ? "enabled" : "")), + enabled: bind(AstalNotifd.get_default(), "dontDisturb"), }, { label: "Clear", diff --git a/src/widgets/popdownwindow.tsx b/src/widgets/popdownwindow.tsx index 8710a59..18e9ae9 100644 --- a/src/widgets/popdownwindow.tsx +++ b/src/widgets/popdownwindow.tsx @@ -5,6 +5,7 @@ import PopupWindow from "./popupwindow"; export default ({ name, count, + countLabel = count.as(c => `${c} ${name.slice(0, -1)}${c === 1 ? "" : "s"}`), headerButtons, emptyIcon, emptyLabel, @@ -12,7 +13,8 @@ export default ({ }: { name: string; count: Binding<number>; - headerButtons: { label: string; onClicked: () => void; className?: Binding<string> }[]; + countLabel?: Binding<string>; + headerButtons: { label: string | Binding<string>; onClicked: () => void; enabled?: Binding<boolean> }[]; emptyIcon: string; emptyLabel: string; list: JSX.Element; @@ -20,10 +22,15 @@ export default ({ <PopupWindow name={name}> <box vertical className={name}> <box className="header"> - <label label={count.as(c => `${c} ${name.slice(0, -1)}${c === 1 ? "" : "s"}`)} /> + <label label={countLabel} /> <box hexpand /> - {headerButtons.map(({ label, onClicked, className }) => ( - <button cursor="pointer" onClicked={onClicked} label={label} className={className} /> + {headerButtons.map(({ label, onClicked, enabled }) => ( + <button + cursor="pointer" + onClicked={onClicked} + label={label} + className={enabled?.as(d => (d ? "enabled" : ""))} + /> ))} </box> <stack @@ -6,8 +6,7 @@ @use "scss/notifpopups"; @use "scss/launcher"; @use "scss/osds"; -@use "scss/notifications"; -@use "scss/updates"; +@use "scss/popdowns"; * { all: unset; // Remove GTK theme styles |