summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-03-26 22:59:28 +1100
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-03-26 22:59:28 +1100
commit17ddfc6fb1dc2ebb9b4ab0bbd3517ef7e1de97da (patch)
tree9be24d9c93d30546ce89acc4ef359ff7de672dff /src
parentsidebar: fix dashboard media types (diff)
downloadcaelestia-shell-17ddfc6fb1dc2ebb9b4ab0bbd3517ef7e1de97da.tar.gz
caelestia-shell-17ddfc6fb1dc2ebb9b4ab0bbd3517ef7e1de97da.tar.bz2
caelestia-shell-17ddfc6fb1dc2ebb9b4ab0bbd3517ef7e1de97da.zip
sidebar: media pane
Diffstat (limited to 'src')
-rw-r--r--src/modules/sidebar/audio.tsx8
-rw-r--r--src/modules/sidebar/index.tsx3
-rw-r--r--src/modules/sidebar/modules/media.tsx149
3 files changed, 159 insertions, 1 deletions
diff --git a/src/modules/sidebar/audio.tsx b/src/modules/sidebar/audio.tsx
new file mode 100644
index 0000000..2b4c6e9
--- /dev/null
+++ b/src/modules/sidebar/audio.tsx
@@ -0,0 +1,8 @@
+import Media from "./modules/media";
+
+export default () => (
+ <box vertical className="pane audio" name="audio">
+ <Media />
+ <box className="separator" />
+ </box>
+);
diff --git a/src/modules/sidebar/index.tsx b/src/modules/sidebar/index.tsx
index 5b9a3a3..5ae7670 100644
--- a/src/modules/sidebar/index.tsx
+++ b/src/modules/sidebar/index.tsx
@@ -2,6 +2,7 @@ import type { Monitor } from "@/services/monitors";
import { bind, idle, register, Variable } from "astal";
import { App, Astal, Gdk, Gtk, Widget } from "astal/gtk3";
import { sidebar as config } from "config";
+import Audio from "./audio";
import Connectivity from "./connectivity";
import Dashboard from "./dashboard";
import NotifPane from "./notifpane";
@@ -21,7 +22,7 @@ export default class SideBar extends Widget.Window {
visible: false,
});
- const panes = [<Dashboard />, <Connectivity />, <NotifPane />];
+ const panes = [<Dashboard />, <Audio />, <Connectivity />, <NotifPane />];
this.shown = Variable(panes[0].name);
this.add(
diff --git a/src/modules/sidebar/modules/media.tsx b/src/modules/sidebar/modules/media.tsx
new file mode 100644
index 0000000..4392aa7
--- /dev/null
+++ b/src/modules/sidebar/modules/media.tsx
@@ -0,0 +1,149 @@
+import Players from "@/services/players";
+import Slider from "@/widgets/slider";
+import { bind, Variable } from "astal";
+import { Gtk } from "astal/gtk3";
+import AstalMpris from "gi://AstalMpris";
+
+const lengthStr = (length: number) =>
+ `${Math.floor(length / 60)}:${Math.floor(length % 60)
+ .toString()
+ .padStart(2, "0")}`;
+
+const noNull = (s: string | null) => s ?? "-";
+
+const NoMedia = () => (
+ <box vertical className="media" name="none">
+ <box homogeneous halign={Gtk.Align.CENTER} className="cover-art">
+ <label xalign={0.4} label="" />
+ </box>
+ <box vertical className="progress">
+ <Slider value={bind(Variable(0))} />
+ <box className="time">
+ <label label="-1:-1" />
+ <box hexpand />
+ <label label="-1:-1" />
+ </box>
+ </box>
+ <box vertical className="details">
+ <label truncate className="title" label="No media" />
+ <label truncate className="artist" label="Try play some music!" />
+ <label truncate className="album" label="" />
+ </box>
+ <box vertical className="controls">
+ <box halign={Gtk.Align.CENTER} className="playback">
+ <button sensitive={false} cursor="pointer" label="󰒮" />
+ <button sensitive={false} cursor="pointer" label="󰐊" />
+ <button sensitive={false} cursor="pointer" label="󰒭" />
+ </box>
+ <box className="options">
+ <button sensitive={false} cursor="pointer" label="󰊓" />
+ <button sensitive={false} cursor="pointer" label="󰒞" />
+ <box hexpand />
+ <button className="needs-adjustment" sensitive={false} cursor="pointer" label="󰑗" />
+ <button className="needs-adjustment" sensitive={false} cursor="pointer" label="󰀽" />
+ </box>
+ </box>
+ </box>
+);
+
+const Player = ({ player }: { player: AstalMpris.Player }) => {
+ const position = Variable.derive([bind(player, "position"), bind(player, "length")], (p, l) => p / l);
+
+ return (
+ <box vertical className="media" name={player.busName} onDestroy={() => position.drop()}>
+ <box
+ homogeneous
+ halign={Gtk.Align.CENTER}
+ className="cover-art"
+ css={bind(player, "coverArt").as(a => `background-image: url("${a}");`)}
+ >
+ {bind(player, "coverArt").as(a => (a ? <box visible={false} /> : <label xalign={0.4} label="" />))}
+ </box>
+ <box vertical className="progress">
+ <Slider value={bind(position)} />
+ <box className="time">
+ <label label={bind(player, "position").as(lengthStr)} />
+ <box hexpand />
+ <label label={bind(player, "length").as(lengthStr)} />
+ </box>
+ </box>
+ <box vertical className="details">
+ <label truncate className="title" label={bind(player, "title").as(noNull)} />
+ <label truncate className="artist" label={bind(player, "artist").as(noNull)} />
+ <label truncate className="album" label={bind(player, "album").as(noNull)} />
+ </box>
+ <box vertical className="controls">
+ <box halign={Gtk.Align.CENTER} className="playback">
+ <button
+ sensitive={bind(player, "canGoPrevious")}
+ cursor="pointer"
+ onClicked={() => player.next()}
+ label="󰒮"
+ />
+ <button
+ sensitive={bind(player, "canControl")}
+ cursor="pointer"
+ onClicked={() => player.play_pause()}
+ label={bind(player, "playbackStatus").as(s =>
+ s === AstalMpris.PlaybackStatus.PLAYING ? "󰏤" : "󰐊"
+ )}
+ />
+ <button
+ sensitive={bind(player, "canGoNext")}
+ cursor="pointer"
+ onClicked={() => player.next()}
+ label="󰒭"
+ />
+ </box>
+ <box className="options">
+ <button
+ sensitive={bind(player, "canSetFullscreen")}
+ cursor="pointer"
+ onClicked={() => player.toggle_fullscreen()}
+ label={bind(player, "fullscreen").as(f => (f ? "󰊔" : "󰊓"))}
+ />
+ <button
+ sensitive={bind(player, "canControl")}
+ cursor="pointer"
+ onClicked={() => player.shuffle()}
+ label={bind(player, "shuffleStatus").as(s => (s === AstalMpris.Shuffle.ON ? "󰒝" : "󰒞"))}
+ />
+ <box hexpand />
+ <button
+ className="needs-adjustment"
+ sensitive={bind(player, "canControl")}
+ cursor="pointer"
+ onClicked={() => player.loop()}
+ label={bind(player, "loopStatus").as(l =>
+ l === AstalMpris.Loop.TRACK ? "󰑘" : l === AstalMpris.Loop.PLAYLIST ? "󰑖" : "󰑗"
+ )}
+ />
+ <button
+ className="needs-adjustment"
+ sensitive={bind(player, "canRaise")}
+ cursor="pointer"
+ onClicked={() => player.raise()}
+ label="󰀽"
+ />
+ </box>
+ </box>
+ </box>
+ );
+};
+
+export default () => {
+ const active = Variable(Players.get_default().list[0]?.busName ?? "none");
+
+ return (
+ <box vertical>
+ <stack
+ transitionType={Gtk.StackTransitionType.SLIDE_LEFT_RIGHT}
+ transitionDuration={150}
+ shown={bind(active)}
+ >
+ <NoMedia />
+ {bind(Players.get_default(), "list").as(ps => ps.map(p => <Player player={p} />))}
+ </stack>
+ </box>
+ );
+};