summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scss/popdowns/bluetoothdevices.scss43
-rw-r--r--scss/popdowns/index.scss3
-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.tsx37
-rw-r--r--src/modules/popdowns/bluetoothdevices.tsx93
-rw-r--r--src/modules/popdowns/index.tsx2
-rw-r--r--src/modules/popdowns/notifications.tsx2
-rw-r--r--src/widgets/popdownwindow.tsx15
-rw-r--r--style.scss3
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
diff --git a/style.scss b/style.scss
index 0c65fa3..00399f4 100644
--- a/style.scss
+++ b/style.scss
@@ -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