feat(ags): transfer remaining bar stuff from v1

This commit is contained in:
matt1432 2025-02-28 00:59:30 -05:00
parent f0704cba04
commit 7d64a1fe25
8 changed files with 177 additions and 264 deletions
modules/ags/config/widgets

View file

@ -20,6 +20,8 @@
}
&.bluetooth icon,
&.heart-toggle label,
&.keyboard icon,
&.network icon,
&.tablet-mode icon {
min-width: 30px;

View file

@ -0,0 +1,29 @@
import { Variable } from 'astal';
import Persist from '../../misc/persist';
const HeartState = Variable('');
Persist({
name: 'heart',
variable: HeartState,
condition: '',
whenFalse: '󰣐',
});
export default () => (
<button
className="bar-item heart-toggle"
cursor="pointer"
onButtonReleaseEvent={() => {
HeartState.set(HeartState.get() === '' ? '󰣐' : '');
}}
>
<label
label={HeartState()}
css="margin-left: -6px; margin-right: 4px; font-size: 28px;"
/>
</button>
);

View file

@ -0,0 +1,87 @@
import { Variable } from 'astal';
import { Label } from 'astal/gtk3/widget';
import AstalHyprland from 'gi://AstalHyprland';
import { hyprMessage } from '../../../lib';
import { Gtk } from 'astal/gtk3';
/* Types */
interface Keyboard {
address: string
name: string
rules: string
model: string
layout: string
variant: string
options: string
active_keymap: string
main: boolean
}
const DEFAULT_KB = 'at-translated-set-2-keyboard';
export default () => {
const Hovered = Variable(false);
const hyprland = AstalHyprland.get_default();
const getKbdLayout = (self: Label, _: string, layout?: string) => {
if (layout) {
if (layout === 'error') {
return;
}
const shortName = layout.match(/\(([A-Za-z]+)\)/);
self.label = shortName ? shortName[1] : layout;
}
else {
// At launch, kb layout is undefined
hyprMessage('j/devices').then((obj) => {
const keyboards = Array.from(JSON.parse(obj)
.keyboards) as Keyboard[];
const kb = keyboards.find((v) => v.name === DEFAULT_KB);
if (kb) {
layout = kb.active_keymap;
const shortName = layout
.match(/\(([A-Za-z]+)\)/);
self.label = shortName ? shortName[1] : layout;
}
else {
self.label = 'None';
}
}).catch(print);
}
};
return (
<button
className="bar-item keyboard"
cursor="pointer"
onHover={() => Hovered.set(true)}
onHoverLost={() => Hovered.set(false)}
>
<box>
<icon icon="input-keyboard-symbolic" />
<revealer
revealChild={Hovered()}
transitionType={Gtk.RevealerTransitionType.SLIDE_LEFT}
>
<label
setup={(self) => {
self.hook(hyprland, 'keyboard-layout', getKbdLayout);
getKbdLayout(self, '');
}}
/>
</revealer>
</box>
</button>
);
};

View file

@ -7,6 +7,8 @@ import Bluetooth from './items/bluetooth';
import Brightness from './items/brightness';
import Clock from './items/clock';
import CurrentClient from './items/current-client';
import Heart from './items/heart';
import Keyboard from './items/keyboard-layout';
import Network from './items/network';
import NotifButton from './items/notif-button';
import SysTray from './items/tray';
@ -52,6 +54,10 @@ export default () => (
/>
</button>
<Separator size={8} />
<Heart />
<CurrentClient />
<Separator size={8} />
@ -70,6 +76,10 @@ export default () => (
<Separator size={8} />
<Keyboard />
<Separator size={8} />
<NotifButton />
<Separator size={8} />

View file

@ -0,0 +1,49 @@
import { execAsync, readFileAsync, timeout, GLib, type Variable } from 'astal';
const { get_home_dir } = GLib;
export default <T>({
name,
variable,
condition = true,
whenTrue = condition,
whenFalse = false,
}: {
name: string
variable: Variable<T>
condition?: boolean | string
whenTrue?: boolean | string
whenFalse?: boolean | string
}) => {
const cacheFile = `${get_home_dir()}/.cache/ags/.${name}`;
const stateCmd = () => ['bash', '-c',
`echo ${variable.get() === condition} > ${cacheFile}`];
const monitorState = () => {
variable.subscribe(() => {
execAsync(stateCmd()).catch(print);
});
};
readFileAsync(cacheFile)
.then((content) => {
// JSON.parse was the only way I found to reliably
// convert a string of 'true' or 'false' into a bool
const value = (JSON.parse(content) ? whenTrue : whenFalse) as T;
variable.set(value);
timeout(1000, () => {
monitorState();
});
})
.catch(() => {
execAsync(stateCmd())
.then(() => {
monitorState();
})
.catch(print);
});
};