mirror of
https://github.com/Theaninova/TheaninovOS.git
synced 2025-12-12 11:36:20 +00:00
159 lines
4.4 KiB
JavaScript
159 lines
4.4 KiB
JavaScript
import Audio from "resource:///com/github/Aylur/ags/service/audio.js";
|
|
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
|
import * as Utils from "resource:///com/github/Aylur/ags/utils.js";
|
|
import icons from "../../icons.js";
|
|
import FontIcon from "../../misc/FontIcon.js";
|
|
import { getAudioTypeIcon } from "../../utils.js";
|
|
import { Arrow } from "../ToggleButton.js";
|
|
import { Menu } from "../ToggleButton.js";
|
|
|
|
/** @param {'speaker' | 'microphone'=} type */
|
|
const VolumeIndicator = (type = "speaker") =>
|
|
Widget.Button({
|
|
on_clicked: () => (Audio[type].is_muted = !Audio[type].is_muted),
|
|
child: Widget.Icon().hook(Audio[type], (icon) => {
|
|
icon.icon =
|
|
type === "speaker"
|
|
? getAudioTypeIcon(Audio[type].icon_name || "")
|
|
: icons.audio.mic.high;
|
|
|
|
icon.tooltip_text = `Volume ${Math.floor(Audio[type].volume * 100)}%`;
|
|
}),
|
|
});
|
|
|
|
/** @param {'speaker' | 'microphone'=} type */
|
|
const VolumeSlider = (type = "speaker") =>
|
|
Widget.Slider({
|
|
hexpand: true,
|
|
draw_value: false,
|
|
on_change: ({ value }) => (Audio[type].volume = value),
|
|
setup: (self) =>
|
|
self.hook(Audio[type], () => {
|
|
self.value = Audio[type].volume || 0;
|
|
}),
|
|
});
|
|
|
|
export const Volume = () =>
|
|
Widget.Box({
|
|
children: [
|
|
VolumeIndicator("speaker"),
|
|
VolumeSlider("speaker"),
|
|
Widget.Box({
|
|
vpack: "center",
|
|
child: Arrow("sink-selector"),
|
|
}),
|
|
Widget.Box({
|
|
vpack: "center",
|
|
child: Arrow("app-mixer"),
|
|
visible: Audio.bind("apps").transform((a) => a.length > 0),
|
|
}),
|
|
],
|
|
});
|
|
|
|
export const Microhone = () =>
|
|
Widget.Box({
|
|
class_name: "slider horizontal",
|
|
visible: Audio.bind("recorders").transform((a) => a.length > 0),
|
|
children: [VolumeIndicator("microphone"), VolumeSlider("microphone")],
|
|
});
|
|
|
|
/** @param {import('types/service/audio').Stream} stream */
|
|
const MixerItem = (stream) =>
|
|
Widget.Box({
|
|
hexpand: true,
|
|
class_name: "mixer-item horizontal",
|
|
children: [
|
|
Widget.Icon({
|
|
tooltip_text: stream.bind("name").transform((n) => n || ""),
|
|
icon: stream.bind("name").transform((n) => {
|
|
return Utils.lookUpIcon(n || "") ? n || "" : icons.mpris.fallback;
|
|
}),
|
|
}),
|
|
Widget.Box({
|
|
vertical: true,
|
|
children: [
|
|
Widget.Label({
|
|
xalign: 0,
|
|
truncate: "end",
|
|
label: stream.bind("description").transform((d) => d || ""),
|
|
}),
|
|
Widget.Slider({
|
|
hexpand: true,
|
|
draw_value: false,
|
|
value: stream.bind("volume"),
|
|
on_change: ({ value }) => (stream.volume = value),
|
|
}),
|
|
],
|
|
}),
|
|
Widget.Label({
|
|
xalign: 1,
|
|
label: stream.bind("volume").transform((v) => `${Math.floor(v * 100)}`),
|
|
}),
|
|
],
|
|
});
|
|
|
|
/** @param {import('types/service/audio').Stream} stream */
|
|
const SinkItem = (stream) =>
|
|
Widget.Button({
|
|
hexpand: true,
|
|
on_clicked: () => (Audio.speaker = stream),
|
|
child: Widget.Box({
|
|
children: [
|
|
Widget.Icon({
|
|
icon: getAudioTypeIcon(stream.icon_name || ""),
|
|
tooltip_text: stream.icon_name,
|
|
}),
|
|
Widget.Label(
|
|
(stream.description || "").split(" ").slice(0, 4).join(" "),
|
|
),
|
|
Widget.Icon({
|
|
icon: icons.ui.tick,
|
|
hexpand: true,
|
|
hpack: "end",
|
|
visible: Audio.speaker
|
|
.bind("stream")
|
|
.transform((s) => s === stream.stream),
|
|
}),
|
|
],
|
|
}),
|
|
});
|
|
|
|
const SettingsButton = () =>
|
|
Widget.Button({
|
|
on_clicked: () => Utils.execAsync("pavucontrol"),
|
|
hexpand: true,
|
|
child: Widget.Box({
|
|
children: [Widget.Icon(icons.ui.settings), Widget.Label("Settings")],
|
|
}),
|
|
});
|
|
|
|
export const AppMixer = () =>
|
|
Menu({
|
|
name: "app-mixer",
|
|
icon: FontIcon(icons.audio.mixer),
|
|
title: Widget.Label("App Mixer"),
|
|
content: [
|
|
Widget.Box({
|
|
vertical: true,
|
|
children: Audio.bind("apps").transform((a) => a.map(MixerItem)),
|
|
}),
|
|
Widget.Separator(),
|
|
SettingsButton(),
|
|
],
|
|
});
|
|
|
|
export const SinkSelector = () =>
|
|
Menu({
|
|
name: "sink-selector",
|
|
icon: Widget.Icon(icons.audio.type.headset),
|
|
title: Widget.Label("Sink Selector"),
|
|
content: [
|
|
Widget.Box({
|
|
vertical: true,
|
|
children: Audio.bind("speakers").transform((a) => a.map(SinkItem)),
|
|
}),
|
|
Widget.Separator(),
|
|
SettingsButton(),
|
|
],
|
|
});
|