nixos-configs/devices/wim/config/ags/ts/quick-settings/bluetooth.ts

216 lines
7.4 KiB
TypeScript
Raw Normal View History

import App from 'resource:///com/github/Aylur/ags/app.js';
import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
import { Box, Icon, Label, ListBox, Overlay, Revealer, Scrollable } from 'resource:///com/github/Aylur/ags/widget.js';
import CursorBox from '../misc/cursorbox.js';
const SCROLL_THRESH_H = 200;
const SCROLL_THRESH_N = 7;
2024-01-13 11:15:08 -05:00
// Types
import AgsBox from 'types/widgets/box.js';
import AgsScrollable from 'types/widgets/scrollable.js';
type ListBoxRow = typeof imports.gi.Gtk.ListBoxRow;
import { BluetoothDevice as BTDev } from 'types/service/bluetooth.js';
2024-01-13 11:15:08 -05:00
const BluetoothDevice = (dev: BTDev) => Box({
2023-12-23 01:14:21 -05:00
class_name: 'menu-item',
2023-12-23 01:14:21 -05:00
attribute: { dev },
2023-12-23 01:14:21 -05:00
children: [Revealer({
reveal_child: true,
transition: 'slide_down',
2023-12-23 01:14:21 -05:00
child: CursorBox({
on_primary_click_release: () => dev.setConnection(true),
2023-12-23 01:14:21 -05:00
child: Box({
hexpand: true,
children: [
Icon({
icon: dev.bind('icon_name'),
}),
Label({
label: dev.bind('name'),
}),
Icon({
icon: 'object-select-symbolic',
hexpand: true,
hpack: 'end',
}).hook(dev, (self) => {
self.setCss(`opacity: ${dev.paired ?
'1' :
'0'};
`);
}),
],
}),
}),
})],
});
export const BluetoothMenu = () => {
const DevList = new Map();
2023-12-23 01:14:21 -05:00
const topArrow = Revealer({
transition: 'slide_down',
2023-12-23 01:14:21 -05:00
child: Icon({
icon: `${App.configDir }/icons/down-large.svg`,
2023-12-23 01:14:21 -05:00
class_name: 'scrolled-indicator',
size: 16,
css: '-gtk-icon-transform: rotate(180deg);',
}),
});
const bottomArrow = Revealer({
transition: 'slide_up',
2023-12-23 01:14:21 -05:00
child: Icon({
icon: `${App.configDir }/icons/down-large.svg`,
2023-12-23 01:14:21 -05:00
class_name: 'scrolled-indicator',
size: 16,
}),
});
return Overlay({
pass_through: true,
2023-12-23 01:14:21 -05:00
overlays: [
Box({
vpack: 'start',
hpack: 'center',
css: 'margin-top: 12px',
children: [topArrow],
}),
Box({
vpack: 'end',
hpack: 'center',
css: 'margin-bottom: 12px',
children: [bottomArrow],
}),
],
child: Box({
2023-12-23 01:14:21 -05:00
class_name: 'menu',
child: Scrollable({
hscroll: 'never',
vscroll: 'never',
setup: (self) => {
self.on('edge-reached', (_, pos) => {
// Manage scroll indicators
if (pos === 2) {
2023-12-23 01:14:21 -05:00
topArrow.reveal_child = false;
bottomArrow.reveal_child = true;
}
else if (pos === 3) {
2023-12-23 01:14:21 -05:00
topArrow.reveal_child = true;
bottomArrow.reveal_child = false;
}
});
},
child: ListBox({
setup: (self) => {
2024-01-13 11:15:08 -05:00
self.set_sort_func((a, b) => {
const bState = (b.get_children()[0] as AgsBox)
.attribute.dev.paired;
const aState = (a.get_children()[0] as AgsBox)
.attribute.dev.paired;
return bState - aState;
});
self.hook(Bluetooth, () => {
// Get all devices
2023-12-23 01:14:21 -05:00
const Devices = Bluetooth.devices.concat(
Bluetooth.connected_devices,
);
// Add missing devices
Devices.forEach((dev) => {
if (!DevList.has(dev) && dev.name) {
DevList.set(dev, BluetoothDevice(dev));
self.add(DevList.get(dev));
self.show_all();
}
});
// Delete ones that don't exist anymore
const difference = Array.from(DevList.keys())
.filter((dev) => !Devices
.find((d) => dev === d) &&
dev.name);
difference.forEach((dev) => {
const devWidget = DevList.get(dev);
if (devWidget) {
if (devWidget.toDestroy) {
devWidget.get_parent().destroy();
DevList.delete(dev);
}
else {
2024-01-06 12:24:09 -05:00
devWidget.child.reveal_child = false;
devWidget.toDestroy = true;
}
}
});
// Start scrolling after a specified height
// is reached by the children
const height = Math.max(
2023-12-23 01:14:21 -05:00
self.get_parent()?.get_allocated_height() || 0,
SCROLL_THRESH_H,
);
2024-01-13 11:15:08 -05:00
const scroll = (self.get_parent() as ListBoxRow)
?.get_parent() as AgsScrollable;
2023-12-23 01:14:21 -05:00
if (scroll) {
const n_child = self.get_children().length;
2023-12-23 01:14:21 -05:00
if (n_child > SCROLL_THRESH_N) {
scroll.vscroll = 'always';
scroll.setCss(`min-height: ${height}px;`);
2023-12-23 01:14:21 -05:00
// Make bottom scroll indicator appear only
// when first getting overflowing children
if (!(bottomArrow.reveal_child === true ||
topArrow.reveal_child === true)) {
bottomArrow.reveal_child = true;
}
}
else {
scroll.vscroll = 'never';
scroll.setCss('');
topArrow.reveal_child = false;
bottomArrow.reveal_child = false;
}
}
// Trigger sort_func
2024-01-13 11:15:08 -05:00
(self.get_children() as Array<ListBoxRow>)
.forEach((ch) => {
ch.changed();
});
});
},
}),
}),
}),
});
};