From 6b0c9af07c6c8a08ac11522e2a8c7af60c210deb Mon Sep 17 00:00:00 2001
From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>
Date: Thu, 27 Mar 2025 16:45:25 +1100
Subject: sidebar: streams module
---
scss/sidebar.scss | 66 +++++++++++++++++++
src/modules/sidebar/audio.tsx | 2 +
src/modules/sidebar/modules/streams.tsx | 111 ++++++++++++++++++++++++++++++++
3 files changed, 179 insertions(+)
create mode 100644 src/modules/sidebar/modules/streams.tsx
diff --git a/scss/sidebar.scss b/scss/sidebar.scss
index 9f72ca8..369ad25 100644
--- a/scss/sidebar.scss
+++ b/scss/sidebar.scss
@@ -443,6 +443,70 @@
}
}
+ .no-wp-prompt {
+ font-size: lib.s(16);
+ color: scheme.$error;
+ margin-top: lib.s(8);
+ }
+
+ .streams {
+ .list {
+ @include lib.spacing(10, true);
+ }
+
+ .stream {
+ @include lib.rounded(20);
+ @include lib.element-decel;
+
+ background-color: color.change(scheme.$surface1, $alpha: 0.4);
+ padding: lib.s(10) lib.s(15);
+
+ @include lib.spacing(5);
+
+ &.playing {
+ background-color: color.change(color.mix(scheme.$surface1, scheme.$primary, 50%), $alpha: 0.4);
+ }
+
+ .icon {
+ font-size: lib.s(28);
+ margin-right: lib.s(12);
+ }
+
+ .sublabel {
+ font-size: lib.s(14);
+ color: scheme.$subtext0;
+ }
+
+ trough {
+ @include lib.rounded(10);
+
+ min-width: lib.s(100);
+ min-height: lib.s(10);
+ background-color: color.change(scheme.$error, $alpha: 0.3);
+
+ fill {
+ @include lib.rounded(10);
+
+ background-color: color.change(scheme.$overlay0, $alpha: 1);
+ }
+
+ highlight {
+ @include lib.rounded(10);
+
+ background-color: scheme.$subtext1;
+ }
+ }
+
+ & > button {
+ @include media-button;
+
+ font-size: lib.s(18);
+ min-width: lib.s(20);
+ min-height: lib.s(20);
+ }
+ }
+ }
+
.networks {
.list {
@include lib.spacing(10, true);
@@ -450,6 +514,7 @@
.network {
@include lib.rounded(20);
+ @include lib.element-decel;
background-color: color.change(scheme.$surface1, $alpha: 0.4);
padding: lib.s(10) lib.s(15);
@@ -493,6 +558,7 @@
.device {
@include lib.rounded(20);
+ @include lib.element-decel;
background-color: color.change(scheme.$surface1, $alpha: 0.4);
padding: lib.s(10) lib.s(15);
diff --git a/src/modules/sidebar/audio.tsx b/src/modules/sidebar/audio.tsx
index 2b4c6e9..a5c1651 100644
--- a/src/modules/sidebar/audio.tsx
+++ b/src/modules/sidebar/audio.tsx
@@ -1,8 +1,10 @@
import Media from "./modules/media";
+import Streams from "./modules/streams";
export default () => (
+
);
diff --git a/src/modules/sidebar/modules/streams.tsx b/src/modules/sidebar/modules/streams.tsx
new file mode 100644
index 0000000..a7b27cb
--- /dev/null
+++ b/src/modules/sidebar/modules/streams.tsx
@@ -0,0 +1,111 @@
+import { bind, execAsync, Variable } from "astal";
+import { Gtk } from "astal/gtk3";
+import AstalWp from "gi://AstalWp";
+
+interface IStream {
+ stream: AstalWp.Endpoint;
+ playing: boolean;
+}
+
+const header = (audio: AstalWp.Audio, key: "streams" | "speakers" | "recorders") =>
+ `${audio[key].length} ${audio[key].length === 1 ? key.slice(0, -1) : key}`;
+
+const sortStreams = (a: IStream, b: IStream) => {
+ if (a.playing || b.playing) return a.playing ? -1 : 1;
+ return 0;
+};
+
+const Stream = ({ stream, playing }: IStream) => (
+
+
+
+
+
+
+
+);
+
+const List = ({ audio }: { audio: AstalWp.Audio }) => {
+ const streams = Variable([]);
+
+ const update = async () => {
+ const paStreams = JSON.parse(await execAsync("pactl -f json list sink-inputs"));
+ streams.set(
+ audio.streams.map(s => ({
+ stream: s,
+ playing: paStreams.find((p: any) => p.properties["object.serial"] == s.serial)?.corked === false,
+ }))
+ );
+ };
+
+ streams.watch("pactl -f json subscribe", out => {
+ if (JSON.parse(out).on === "sink-input") update().catch(console.error);
+ return streams.get();
+ });
+ audio.connect("notify::streams", () => update().catch(console.error));
+
+ return (
+ streams.drop()}>
+ {bind(streams).as(ps => ps.sort(sortStreams).map(s => ))}
+
+ );
+};
+
+const NoSources = ({ icon, label }: { icon: string; label: string }) => (
+
+
+
+
+
+
+);
+
+const NoWp = () => (
+
+
+
+
+
+
+);
+
+export default () => {
+ const audio = AstalWp.get_default()?.get_audio();
+
+ if (!audio) return ;
+
+ const label = Variable("");
+
+ label.observe(
+ ["streams", "speakers", "recorders"].map(k => [audio, `notify::${k}`]),
+ () => `${header(audio, "streams")} • ${header(audio, "speakers")} • ${header(audio, "recorders")}`
+ );
+
+ return (
+ label.drop()}>
+
+
+
+ (s.length > 0 ? "list" : "empty"))}
+ >
+
+
+
+
+
+
+ );
+};
--
cgit v1.2.3-freya