From 936e9aacb03e4c99f6d7b77424b83baf7a30035f Mon Sep 17 00:00:00 2001 From: matt1432 <matt@nelim.org> Date: Sat, 7 Dec 2024 14:17:37 -0500 Subject: [PATCH] feat(ags): add start of audio widget --- .../ags/config/configurations/binto.ts | 2 + nixosModules/ags/config/configurations/wim.ts | 2 + nixosModules/ags/config/style/common.scss | 8 ++ nixosModules/ags/config/style/main.scss | 1 + .../ags/config/widgets/audio/_index.scss | 11 ++ .../ags/config/widgets/audio/binto.tsx | 18 +++ .../ags/config/widgets/audio/main.tsx | 111 ++++++++++++++++++ nixosModules/ags/config/widgets/audio/wim.tsx | 15 +++ .../ags/config/widgets/bar/items/audio.tsx | 24 +++- .../ags/config/widgets/misc/subclasses.tsx | 24 +++- .../config/widgets/on-screen-display/main.tsx | 15 +-- 11 files changed, 214 insertions(+), 17 deletions(-) create mode 100644 nixosModules/ags/config/widgets/audio/_index.scss create mode 100644 nixosModules/ags/config/widgets/audio/binto.tsx create mode 100644 nixosModules/ags/config/widgets/audio/main.tsx create mode 100644 nixosModules/ags/config/widgets/audio/wim.tsx diff --git a/nixosModules/ags/config/configurations/binto.ts b/nixosModules/ags/config/configurations/binto.ts index 0dae2a28..3c6da082 100644 --- a/nixosModules/ags/config/configurations/binto.ts +++ b/nixosModules/ags/config/configurations/binto.ts @@ -4,6 +4,7 @@ import { App } from 'astal/gtk3'; import style from '../style/main.scss'; import AppLauncher from '../widgets/applauncher/main'; +import AudioWindow from '../widgets/audio/binto'; import Bar from '../widgets/bar/binto'; import BgLayer from '../widgets/bg-layer/main'; import Calendar from '../widgets/date/binto'; @@ -52,6 +53,7 @@ export default () => { perMonitor((monitor) => BgLayer(monitor, false)); AppLauncher(); + AudioWindow(); Bar(); Calendar(); Clipboard(); diff --git a/nixosModules/ags/config/configurations/wim.ts b/nixosModules/ags/config/configurations/wim.ts index c4be9d55..b7b44f56 100644 --- a/nixosModules/ags/config/configurations/wim.ts +++ b/nixosModules/ags/config/configurations/wim.ts @@ -4,6 +4,7 @@ import { App } from 'astal/gtk3'; import style from '../style/main.scss'; import AppLauncher from '../widgets/applauncher/main'; +import AudioWindow from '../widgets/audio/wim'; import Bar from '../widgets/bar/wim'; import BgLayer from '../widgets/bg-layer/main'; import BluetoothWindow from '../widgets/bluetooth/wim'; @@ -55,6 +56,7 @@ export default () => { perMonitor((monitor) => BgLayer(monitor, true)); AppLauncher(); + AudioWindow(); Bar(); BluetoothWindow(); Calendar(); diff --git a/nixosModules/ags/config/style/common.scss b/nixosModules/ags/config/style/common.scss index b89ec0ea..4d20f311 100644 --- a/nixosModules/ags/config/style/common.scss +++ b/nixosModules/ags/config/style/common.scss @@ -30,6 +30,14 @@ progressbar { } } +scale { + contents { + trough { + min-height: 10px; + } + } +} + circular-progress { background: #363847; min-height: 35px; diff --git a/nixosModules/ags/config/style/main.scss b/nixosModules/ags/config/style/main.scss index d31e20cd..39045afb 100644 --- a/nixosModules/ags/config/style/main.scss +++ b/nixosModules/ags/config/style/main.scss @@ -1,6 +1,7 @@ @use 'common'; @use '../widgets/applauncher'; +@use '../widgets/audio'; @use '../widgets/bar'; @use '../widgets/bluetooth'; @use '../widgets/clipboard'; diff --git a/nixosModules/ags/config/widgets/audio/_index.scss b/nixosModules/ags/config/widgets/audio/_index.scss new file mode 100644 index 00000000..49fe8ab4 --- /dev/null +++ b/nixosModules/ags/config/widgets/audio/_index.scss @@ -0,0 +1,11 @@ +@use 'sass:color'; +@use '../../style/colors'; + +.widget.audio { + .stream { + margin: 5px; + padding: 10px; + border-radius: 8px; + background-color: color.adjust(colors.$window_bg_color, $lightness: -3%); + } +} diff --git a/nixosModules/ags/config/widgets/audio/binto.tsx b/nixosModules/ags/config/widgets/audio/binto.tsx new file mode 100644 index 00000000..4be56ddf --- /dev/null +++ b/nixosModules/ags/config/widgets/audio/binto.tsx @@ -0,0 +1,18 @@ +import { Astal } from 'astal/gtk3'; + +import PopupWindow from '../misc/popup-window'; +import { get_gdkmonitor_from_desc } from '../../lib'; + +import AudioWidget from './main'; + + +export default () => ( + <PopupWindow + name="audio" + gdkmonitor={get_gdkmonitor_from_desc('desc:Acer Technologies Acer K212HQL T3EAA0014201')} + anchor={Astal.WindowAnchor.RIGHT | Astal.WindowAnchor.TOP} + transition="slide bottom" + > + <AudioWidget /> + </PopupWindow> +); diff --git a/nixosModules/ags/config/widgets/audio/main.tsx b/nixosModules/ags/config/widgets/audio/main.tsx new file mode 100644 index 00000000..277f481e --- /dev/null +++ b/nixosModules/ags/config/widgets/audio/main.tsx @@ -0,0 +1,111 @@ +import { bind } from 'astal'; +import { Gtk, Widget } from 'astal/gtk3'; + +import AstalWp from 'gi://AstalWp'; + +import { RadioButton, ToggleButton } from '../misc/subclasses'; +import Separator from '../misc/separator'; + + +export default () => { + const audio = AstalWp.get_default()?.get_audio(); + + if (!audio) { + throw new Error('Could not find default audio devices.'); + } + + // TODO: make a stack to have outputs, inputs and currently playing apps + // TODO: figure out ports and profiles + + const defaultGroup = new RadioButton(); + + return ( + <box vertical className="widget audio"> + {bind(audio, 'speakers').as((speakers) => speakers.map((speaker) => ( + <box className="stream" vertical> + <box className="title"> + <RadioButton + css="margin-top: 1px;" + + group={defaultGroup} + active={speaker.isDefault} + + setup={(self) => { + speaker.connect('notify::isDefault', () => { + self.active = speaker.isDefault; + }); + }} + + onToggled={(self) => { + speaker.isDefault = self.active; + }} + /> + + <Separator size={8} /> + + <label label={bind(speaker, 'description')} /> + </box> + + <Separator size={4} vertical /> + + <box className="body"> + <ToggleButton + cursor="pointer" + valign={Gtk.Align.END} + + active={speaker.mute} + onToggled={(self) => { + speaker.set_mute(self.active); + + (self.get_child() as Widget.Icon).icon = self.active ? + 'audio-volume-muted-symbolic' : + 'audio-speakers-symbolic'; + }} + > + <icon icon={speaker.mute ? + 'audio-volume-muted-symbolic' : + 'audio-speakers-symbolic'} + /> + </ToggleButton> + + <Separator size={4} /> + + {/* + FIXME: lockChannels not working + TODO: have two sliders when lockChannels === false + */} + <ToggleButton + cursor="pointer" + valign={Gtk.Align.END} + + active={speaker.lockChannels} + onToggled={(self) => { + speaker.set_lock_channels(self.active); + + (self.get_child() as Widget.Icon).icon = self.active ? + 'channel-secure-symbolic' : + 'channel-insecure-symbolic'; + }} + > + <icon icon={speaker.lockChannels ? + 'channel-secure-symbolic' : + 'channel-insecure-symbolic'} + /> + </ToggleButton> + + <slider + hexpand + halign={Gtk.Align.FILL} + drawValue + + value={bind(speaker, 'volume')} + onDragged={(self) => { + speaker.set_volume(self.value); + }} + /> + </box> + </box> + )))} + </box> + ); +}; diff --git a/nixosModules/ags/config/widgets/audio/wim.tsx b/nixosModules/ags/config/widgets/audio/wim.tsx new file mode 100644 index 00000000..b3327738 --- /dev/null +++ b/nixosModules/ags/config/widgets/audio/wim.tsx @@ -0,0 +1,15 @@ +import { Astal } from 'astal/gtk3'; + +import PopupWindow from '../misc/popup-window'; + +import AudioWidget from './main'; + + +export default () => ( + <PopupWindow + name="audio" + anchor={Astal.WindowAnchor.RIGHT | Astal.WindowAnchor.TOP} + > + <AudioWidget /> + </PopupWindow> +); diff --git a/nixosModules/ags/config/widgets/bar/items/audio.tsx b/nixosModules/ags/config/widgets/bar/items/audio.tsx index 63b3fcc6..a3e2a619 100644 --- a/nixosModules/ags/config/widgets/bar/items/audio.tsx +++ b/nixosModules/ags/config/widgets/bar/items/audio.tsx @@ -1,7 +1,11 @@ import { bind } from 'astal'; +import { App } from 'astal/gtk3'; import AstalWp from 'gi://AstalWp'; +import PopupWindow from '../../misc/popup-window'; + + export default () => { const speaker = AstalWp.get_default()?.audio.default_speaker; @@ -10,8 +14,22 @@ export default () => { } return ( - <box className="bar-item audio"> - <overlay> + <button + cursor="pointer" + className="bar-item audio" + + onButtonReleaseEvent={(self) => { + const win = App.get_window('win-audio') as PopupWindow; + + win.set_x_pos( + self.get_allocation(), + 'right', + ); + + win.visible = !win.visible; + }} + > + <overlay passThrough> <circularprogress startAt={0.75} endAt={0.75} @@ -23,6 +41,6 @@ export default () => { <icon icon={bind(speaker, 'volumeIcon')} /> </overlay> - </box> + </button> ); }; diff --git a/nixosModules/ags/config/widgets/misc/subclasses.tsx b/nixosModules/ags/config/widgets/misc/subclasses.tsx index 626448fc..59c5b596 100644 --- a/nixosModules/ags/config/widgets/misc/subclasses.tsx +++ b/nixosModules/ags/config/widgets/misc/subclasses.tsx @@ -13,6 +13,17 @@ export class ToggleButton extends astalify(Gtk.ToggleButton) { } } +@register() +export class RadioButton extends astalify(Gtk.RadioButton) { + constructor(props: ConstructProps< + RadioButton, + Gtk.RadioButton.ConstructorProps + > = {}) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + super(props as any); + } +} + @register() export class ListBox extends astalify(Gtk.ListBox) { override get_children() { @@ -22,7 +33,18 @@ export class ListBox extends astalify(Gtk.ListBox) { constructor(props: ConstructProps< ListBox, Gtk.ListBox.ConstructorProps - >) { + > = {}) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + super(props as any); + } +} + +@register() +export class ProgressBar extends astalify(Gtk.ProgressBar) { + constructor(props: ConstructProps< + ProgressBar, + Gtk.ProgressBar.ConstructorProps + > = {}) { // eslint-disable-next-line @typescript-eslint/no-explicit-any super(props as any); } diff --git a/nixosModules/ags/config/widgets/on-screen-display/main.tsx b/nixosModules/ags/config/widgets/on-screen-display/main.tsx index d0f161ba..23fbf15d 100644 --- a/nixosModules/ags/config/widgets/on-screen-display/main.tsx +++ b/nixosModules/ags/config/widgets/on-screen-display/main.tsx @@ -1,9 +1,9 @@ import { bind, timeout } from 'astal'; -import { register } from 'astal/gobject'; -import { App, Astal, astalify, Gtk, Widget, type ConstructProps } from 'astal/gtk3'; +import { App, Astal, Gtk, Widget } from 'astal/gtk3'; import AstalWp from 'gi://AstalWp'; +import { ProgressBar } from '../misc/subclasses'; import PopupWindow from '../misc/popup-window'; import Brightness from '../../services/brightness'; @@ -12,17 +12,6 @@ declare global { function popup_osd(osd: string): void; } -@register() -class ProgressBar extends astalify(Gtk.ProgressBar) { - constructor(props: ConstructProps< - ProgressBar, - Gtk.ProgressBar.ConstructorProps - >) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - super(props as any); - } -} - const HIDE_DELAY = 2000; const transition_duration = 300;