ags(pages): add ´show more´ kind of button to pages

This commit is contained in:
retrozinndev
2025-04-10 16:32:53 -03:00
parent 4ca4d5914d
commit afc0a5dacf
2 changed files with 128 additions and 61 deletions
+63 -47
View File
@@ -1,21 +1,32 @@
import { AstalIO, bind, timeout } from "astal"; import { bind, Variable } from "astal";
import { Gtk, Widget } from "astal/gtk3"; import { Gtk, Widget } from "astal/gtk3";
import AstalBluetooth from "gi://AstalBluetooth"; import AstalBluetooth from "gi://AstalBluetooth";
import { Page } from "./Page"; import { Page } from "./Page";
import { Separator, SeparatorProps } from "../../Separator"; import { Separator, SeparatorProps } from "../../Separator";
let watchingDevices: boolean = false;
let watchTimeout: (AstalIO.Time|undefined); const watchingDevices = new Variable<boolean>(false);
export const BluetoothPage: Page = new Page({ export const BluetoothPage: Page = new Page({
title: "Bluetooth Devices", title: "Bluetooth Devices",
description: "Manage your Bluetooth devices and add new ones.", description: "Manage your Bluetooth devices and add new ones.",
className: "bluetooth", className: "bluetooth",
setup: () => { headerButtons: () => [
watchingDevices = true; new Widget.Button({
className: "discover nf",
label: watchingDevices(watching => !watching ? '󰑓' : '󰙦'),
tooltipText: watchingDevices(watching => !watching ? "Start discovering" : "Stop discovery"),
onClick: () => {
if(watchingDevices.get()) {
stopBluetoothDevicesWatch();
return;
}
watchNewDevices(); watchNewDevices();
}, }
onClose: stopBluetoothDevicesWatch, } as Widget.ButtonProps)
],
onClose: () => stopBluetoothDevicesWatch(),
pageChild: () => new Widget.Box({ pageChild: () => new Widget.Box({
className: "connections", className: "connections",
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
@@ -25,28 +36,49 @@ export const BluetoothPage: Page = new Page({
new Widget.Box({ new Widget.Box({
className: "paired", className: "paired",
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
children: bind(AstalBluetooth.get_default(), "devices").as((devices: Array<AstalBluetooth.Device>) => visible: bind(AstalBluetooth.get_default(), "devices").as((devs) =>
devices.filter((device: AstalBluetooth.Device) => device.connected || device.paired) devs.filter(dev => dev.paired || dev.connected).length > 0),
.map((dev: AstalBluetooth.Device) => children: bind(AstalBluetooth.get_default(), "devices").as((devs: Array<AstalBluetooth.Device>) => {
DeviceWidget(dev) const connectedDevices = devs.filter((dev: AstalBluetooth.Device) => dev.connected || dev.paired)
)
) return [
new Widget.Label({
className: "sub-header",
label: "Paired Devices",
xalign: 0,
} as Widget.LabelProps),
...connectedDevices.map((dev: AstalBluetooth.Device) => DeviceWidget(dev))
]
})
} as Widget.BoxProps), } as Widget.BoxProps),
Separator({
size: .5,
orientation: Gtk.Orientation.VERTICAL,
alpha: .7
} as SeparatorProps),
new Widget.Box({ new Widget.Box({
className: "discovered", className: "discovered",
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
children: bind(AstalBluetooth.get_default(), "devices").as((devices: Array<AstalBluetooth.Device>) => visible: bind(AstalBluetooth.get_default(), "devices").as((devs) =>
devices.filter((device: AstalBluetooth.Device) => !device.connected && !device.paired) devs.filter((dev) => !dev.connected && !dev.paired).length > 0),
.map((dev: AstalBluetooth.Device) => children: bind(AstalBluetooth.get_default(), "devices").as((devices: Array<AstalBluetooth.Device>) => {
DeviceWidget(dev) const discoveredDevices = devices.filter((dev: AstalBluetooth.Device) => !dev.connected && !dev.paired);
)
) return [
} as Widget.BoxProps) new Widget.Label({
className: "sub-header",
label: "Others",
xalign: 0
} as Widget.LabelProps),
...discoveredDevices.map((dev: AstalBluetooth.Device) => DeviceWidget(dev))
]
})
} as Widget.BoxProps),
Separator({
size: .2,
orientation: Gtk.Orientation.VERTICAL,
alpha: .2
} as SeparatorProps),
new Widget.Button({
className: "more",
label: "More settings",
xalign: 0
} as Widget.ButtonProps)
] ]
} as Widget.BoxProps) } as Widget.BoxProps)
}); });
@@ -70,7 +102,8 @@ function DeviceWidget(dev: AstalBluetooth.Device): Gtk.Widget {
className: "alias", className: "alias",
halign: Gtk.Align.START, halign: Gtk.Align.START,
hexpand: true, hexpand: true,
label: bind(dev, "alias") label: bind(dev, "alias").as((alias) => alias.split('-').length === 6 ?
`Unknown (${alias})` : alias)
} as Widget.LabelProps), } as Widget.LabelProps),
new Widget.Label({ new Widget.Label({
className: "battery", className: "battery",
@@ -86,30 +119,13 @@ function DeviceWidget(dev: AstalBluetooth.Device): Gtk.Widget {
} }
function watchNewDevices(): void { function watchNewDevices(): void {
if(!watchTimeout) { watchingDevices.set(true);
watchTimeout = timeout(5000, () => { !AstalBluetooth.get_default().adapter.discovering &&
reloadBluetoothDevicesList(2500); AstalBluetooth.get_default().adapter.start_discovery();
watchNewDevices();
watchTimeout = undefined;
});
return;
}
stopBluetoothDevicesWatch();
} }
export function stopBluetoothDevicesWatch(): void { export function stopBluetoothDevicesWatch(): void {
watchingDevices = false; watchingDevices.set(false);
watchTimeout?.cancel();
watchTimeout = undefined;
AstalBluetooth.get_default().adapter.discovering && AstalBluetooth.get_default().adapter.discovering &&
AstalBluetooth.get_default().adapter.stop_discovery(); AstalBluetooth.get_default().adapter.stop_discovery();
} }
export function reloadBluetoothDevicesList(discoveryTimeout?: number): void {
AstalBluetooth.get_default().adapter.start_discovery();
timeout(discoveryTimeout || 2500, () =>
AstalBluetooth.get_default().adapter.stop_discovery());
}
+56 -5
View File
@@ -2,6 +2,10 @@ import { Gtk, Widget } from "astal/gtk3";
import { Page } from "./Page"; import { Page } from "./Page";
import AstalNetwork from "gi://AstalNetwork"; import AstalNetwork from "gi://AstalNetwork";
import { bind } from "astal"; import { bind } from "astal";
import NM from "gi://NM";
import { Separator, SeparatorProps } from "../../Separator";
import { Windows } from "../../../windows";
import AstalHyprland from "gi://AstalHyprland?version=0.1";
export const PageNetwork = new Page({ export const PageNetwork = new Page({
title: "Network", title: "Network",
@@ -19,27 +23,61 @@ export const PageNetwork = new Page({
], ],
pageChild: () => new Widget.Box({ pageChild: () => new Widget.Box({
expand: true, expand: true,
orientation: Gtk.Orientation.VERTICAL,
children: [ children: [
new Widget.Box({ new Widget.Box({
className: "devices", className: "devices",
hexpand: true, hexpand: true,
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
visible: bind(AstalNetwork.get_default().get_client(), "devices").as((devs) => devs.length > 0), visible: bind(AstalNetwork.get_default().get_client(), "devices").as((devs) => devs.length > 0),
children: bind(AstalNetwork.get_default().get_client(), "devices").as((devices) => [ children: bind(AstalNetwork.get_default().get_client(), "devices").as((devices) => {
devices = devices.filter(dev => dev.interface !== "lo");
return [
new Widget.Label({ new Widget.Label({
label: "Devices", label: "Devices",
xalign: 0, xalign: 0,
className: "sub-header", className: "sub-header",
} as Widget.LabelProps), } as Widget.LabelProps),
...devices.map(dev => new Widget.Button({ ...devices.filter(device => device.real).map(dev => new Widget.Button({
className: "device", className: "device",
child: new Widget.Label({ child: bind(AstalNetwork.get_default(), "client").as((client) => new Widget.Box({
children: [
new Widget.Icon({
className: "icon",
icon: bind(dev, "deviceType").as(deviceType =>
deviceType === NM.DeviceType.WIFI ?
"network-wireless-symbolic"
: "network-wired-symbolic"),
css: "font-size: 20px; margin-right: 6px;"
} as Widget.IconProps),
new Widget.Label({
className: "interface name", className: "interface name",
xalign: 0, xalign: 0,
label: dev.interface hexpand: true,
label: bind(dev, "interface").as(iface => iface ?? "Unknown Interface")
} as Widget.LabelProps), } as Widget.LabelProps),
new Widget.Icon({
icon: "object-select-symbolic",
halign: Gtk.Align.END,
visible: bind(client, "primaryConnection").as((primaryConn) =>
primaryConn.devices.filter(device => device === dev)?.[0]).as(Boolean)
} as Widget.IconProps),
new Widget.EventBox({
child: new Widget.Icon({
icon: "view-more-symbolic"
} as Widget.IconProps),
onClick: () => {
Windows.close("control-center");
AstalHyprland.get_default().dispatch("exec",
`[animationstyle gnomed] nm-connection-editor --edit ${dev.get_udi()}`);
}
} as Widget.EventBoxProps)
]
} as Widget.BoxProps))
} as Widget.ButtonProps)) } as Widget.ButtonProps))
]) ]
})
} as Widget.BoxProps), } as Widget.BoxProps),
new Widget.Box({ new Widget.Box({
className: "wireless-aps", className: "wireless-aps",
@@ -70,6 +108,19 @@ export const PageNetwork = new Page({
} as Widget.BoxProps) } as Widget.BoxProps)
} as Widget.ButtonProps))) : [], } as Widget.ButtonProps))) : [],
} as Widget.BoxProps), } as Widget.BoxProps),
Separator({
orientation: Gtk.Orientation.VERTICAL,
alpha: .2,
size: .2
} as SeparatorProps),
new Widget.Button({
label: "More settings",
xalign: 0,
onClick: () => {
Windows.close("control-center");
AstalHyprland.get_default().dispatch("exec", "[animationstyle gnomed] nm-connection-editor");
}
} as Widget.ButtonProps)
] ]
} as Widget.BoxProps) } as Widget.BoxProps)
}); });