parent
1ce40f2c1a
commit
6ca0d7248b
329 changed files with 178 additions and 139 deletions
modules/ags/config/widgets/audio
44
modules/ags/config/widgets/audio/_index.scss
Normal file
44
modules/ags/config/widgets/audio/_index.scss
Normal file
|
@ -0,0 +1,44 @@
|
|||
@use 'sass:color';
|
||||
@use '../../style/colors';
|
||||
|
||||
.widget.audio {
|
||||
.header {
|
||||
.header-btn {
|
||||
font-size: 30px;
|
||||
margin: 5px;
|
||||
transition: background 400ms;
|
||||
|
||||
&.active {
|
||||
background: colors.$window_bg_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scrollable {
|
||||
margin: 5px;
|
||||
min-height: 400px;
|
||||
|
||||
box {
|
||||
.item-btn {
|
||||
margin: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stream {
|
||||
margin: 5px;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
background-color: color.adjust(colors.$window_bg_color, $lightness: -3%);
|
||||
|
||||
.body {
|
||||
.toggle {
|
||||
padding: 5px;
|
||||
|
||||
icon {
|
||||
font-size: 26px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
modules/ags/config/widgets/audio/binto.tsx
Normal file
18
modules/ags/config/widgets/audio/binto.tsx
Normal 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.BOTTOM}
|
||||
transition="slide bottom"
|
||||
>
|
||||
<AudioWidget />
|
||||
</PopupWindow>
|
||||
);
|
106
modules/ags/config/widgets/audio/main.tsx
Normal file
106
modules/ags/config/widgets/audio/main.tsx
Normal file
|
@ -0,0 +1,106 @@
|
|||
import { bind, Variable } from 'astal';
|
||||
import { Gtk, Widget } from 'astal/gtk3';
|
||||
|
||||
import AstalWp from 'gi://AstalWp';
|
||||
|
||||
import Separator from '../misc/separator';
|
||||
|
||||
import Streams from './streams';
|
||||
import Profiles from './profiles';
|
||||
|
||||
|
||||
export default () => {
|
||||
const audio = AstalWp.get_default()?.get_audio();
|
||||
|
||||
if (!audio) {
|
||||
throw new Error('Could not find default audio devices.');
|
||||
}
|
||||
|
||||
const Shown = Variable<string>('outputs');
|
||||
|
||||
const stack = (
|
||||
<stack
|
||||
shown={bind(Shown)}
|
||||
transitionType={Gtk.StackTransitionType.SLIDE_LEFT_RIGHT}
|
||||
>
|
||||
|
||||
<scrollable
|
||||
name="outputs"
|
||||
hscroll={Gtk.PolicyType.NEVER}
|
||||
|
||||
setup={(self) => setTimeout(() => {
|
||||
self.add((
|
||||
<box vertical>
|
||||
{bind(audio, 'speakers').as(Streams)}
|
||||
</box>
|
||||
));
|
||||
}, 1000)}
|
||||
/>
|
||||
|
||||
<scrollable
|
||||
name="inputs"
|
||||
hscroll={Gtk.PolicyType.NEVER}
|
||||
|
||||
setup={(self) => setTimeout(() => {
|
||||
self.add((
|
||||
<box vertical>
|
||||
{bind(audio, 'microphones').as(Streams)}
|
||||
</box>
|
||||
));
|
||||
}, 1000)}
|
||||
/>
|
||||
|
||||
<scrollable
|
||||
name="profiles"
|
||||
hscroll={Gtk.PolicyType.NEVER}
|
||||
|
||||
setup={(self) => setTimeout(() => {
|
||||
self.add((
|
||||
<box vertical>
|
||||
{bind(audio, 'devices').as(Profiles)}
|
||||
</box>
|
||||
));
|
||||
}, 1000)}
|
||||
/>
|
||||
|
||||
</stack>
|
||||
) as Widget.Stack;
|
||||
|
||||
const StackButton = ({ label = '', iconName = '' }) => (
|
||||
<button
|
||||
cursor="pointer"
|
||||
className={bind(Shown).as((shown) =>
|
||||
`header-btn${shown === label ? ' active' : ''}`)}
|
||||
|
||||
onButtonReleaseEvent={() => {
|
||||
Shown.set(label);
|
||||
}}
|
||||
>
|
||||
<box halign={Gtk.Align.CENTER}>
|
||||
<icon icon={iconName} />
|
||||
|
||||
<Separator size={8} />
|
||||
|
||||
{label}
|
||||
</box>
|
||||
</button>
|
||||
) as Widget.Button;
|
||||
|
||||
return (
|
||||
<box
|
||||
className="audio widget"
|
||||
vertical
|
||||
>
|
||||
<box
|
||||
className="header"
|
||||
homogeneous
|
||||
>
|
||||
<StackButton label="outputs" iconName="audio-speakers-symbolic" />
|
||||
<StackButton label="inputs" iconName="audio-input-microphone-symbolic" />
|
||||
<StackButton label="profiles" iconName="application-default-symbolic" />
|
||||
</box>
|
||||
|
||||
{stack}
|
||||
</box>
|
||||
);
|
||||
};
|
46
modules/ags/config/widgets/audio/profiles.tsx
Normal file
46
modules/ags/config/widgets/audio/profiles.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { bind } from 'astal';
|
||||
|
||||
import AstalWp from 'gi://AstalWp';
|
||||
|
||||
import { ComboBoxText } from '../misc/subclasses';
|
||||
|
||||
|
||||
export default (devices: AstalWp.Device[]) => devices
|
||||
.sort((a, b) => a.description.localeCompare(b.description))
|
||||
.map((device) => (
|
||||
<box className="stream" vertical>
|
||||
|
||||
<label label={bind(device, 'description')} />
|
||||
|
||||
<ComboBoxText
|
||||
setup={(self) => {
|
||||
const profiles = (device.get_profiles() ?? []).sort((a, b) => {
|
||||
if (a.description === 'Off') {
|
||||
return 1;
|
||||
}
|
||||
else if (b.description === 'Off') {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return a.description.localeCompare(b.description);
|
||||
}
|
||||
});
|
||||
|
||||
profiles.forEach((profile) => {
|
||||
self.append(profile.index.toString(), profile.description);
|
||||
});
|
||||
|
||||
self.set_active(
|
||||
profiles.indexOf(
|
||||
device.get_profile(device.get_active_profile())!,
|
||||
),
|
||||
);
|
||||
}}
|
||||
|
||||
onChanged={(self) => {
|
||||
device.set_active_profile(parseInt(self.activeId));
|
||||
}}
|
||||
/>
|
||||
|
||||
</box>
|
||||
));
|
96
modules/ags/config/widgets/audio/streams.tsx
Normal file
96
modules/ags/config/widgets/audio/streams.tsx
Normal file
|
@ -0,0 +1,96 @@
|
|||
import { bind } from 'astal';
|
||||
import { Gtk } from 'astal/gtk3';
|
||||
|
||||
import AstalWp from 'gi://AstalWp';
|
||||
|
||||
import { RadioButton } from '../misc/subclasses';
|
||||
import Separator from '../misc/separator';
|
||||
|
||||
|
||||
export default (streams: AstalWp.Endpoint[]) => {
|
||||
let group: RadioButton | undefined;
|
||||
|
||||
return streams
|
||||
.sort((a, b) => a.description.localeCompare(b.description))
|
||||
.map((stream) => (
|
||||
<box className="stream" vertical>
|
||||
|
||||
<box className="title">
|
||||
|
||||
<RadioButton
|
||||
cursor="pointer"
|
||||
css="margin-top: 1px;"
|
||||
|
||||
onRealize={(self) => {
|
||||
if (!group) {
|
||||
group = self;
|
||||
}
|
||||
else {
|
||||
self.group = group;
|
||||
}
|
||||
|
||||
self.active = stream.isDefault;
|
||||
self.hook(stream, 'notify::is-default', () => {
|
||||
self.active = stream.isDefault;
|
||||
});
|
||||
}}
|
||||
|
||||
onButtonReleaseEvent={() => {
|
||||
stream.isDefault = true;
|
||||
}}
|
||||
/>
|
||||
|
||||
<Separator size={8} />
|
||||
|
||||
<label label={bind(stream, 'description')} />
|
||||
|
||||
</box>
|
||||
|
||||
<Separator size={4} vertical />
|
||||
|
||||
<box className="body">
|
||||
|
||||
<button
|
||||
cursor="pointer"
|
||||
className="toggle"
|
||||
valign={Gtk.Align.END}
|
||||
|
||||
onButtonReleaseEvent={() => {
|
||||
stream.mute = !stream.mute;
|
||||
}}
|
||||
>
|
||||
<icon
|
||||
icon={bind(stream, 'mute').as((isMuted) => {
|
||||
if (stream.mediaClass === AstalWp.MediaClass.AUDIO_MICROPHONE) {
|
||||
return isMuted ?
|
||||
'audio-input-microphone-muted-symbolic' :
|
||||
'audio-input-microphone-symbolic';
|
||||
}
|
||||
else {
|
||||
return isMuted ?
|
||||
'audio-volume-muted-symbolic' :
|
||||
'audio-speakers-symbolic';
|
||||
}
|
||||
})}
|
||||
/>
|
||||
</button>
|
||||
|
||||
<Separator size={4} />
|
||||
|
||||
<slider
|
||||
hexpand
|
||||
halign={Gtk.Align.FILL}
|
||||
drawValue
|
||||
cursor="pointer"
|
||||
|
||||
value={bind(stream, 'volume')}
|
||||
onDragged={(self) => {
|
||||
stream.set_volume(self.value);
|
||||
}}
|
||||
/>
|
||||
|
||||
</box>
|
||||
|
||||
</box>
|
||||
));
|
||||
};
|
15
modules/ags/config/widgets/audio/wim.tsx
Normal file
15
modules/ags/config/widgets/audio/wim.tsx
Normal 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>
|
||||
);
|
Loading…
Add table
Add a link
Reference in a new issue