feat(ags): add start of audio widget
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-12-07 14:17:37 -05:00
parent 9c01cbd74c
commit 936e9aacb0
11 changed files with 214 additions and 17 deletions

View file

@ -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();

View file

@ -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();

View file

@ -30,6 +30,14 @@ progressbar {
}
}
scale {
contents {
trough {
min-height: 10px;
}
}
}
circular-progress {
background: #363847;
min-height: 35px;

View file

@ -1,6 +1,7 @@
@use 'common';
@use '../widgets/applauncher';
@use '../widgets/audio';
@use '../widgets/bar';
@use '../widgets/bluetooth';
@use '../widgets/clipboard';

View file

@ -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%);
}
}

View file

@ -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>
);

View file

@ -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>
);
};

View file

@ -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>
);

View file

@ -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>
);
};

View file

@ -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);
}

View file

@ -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;