sidebar: player switching

This commit is contained in:
2 * r + 2 * t 2025-03-26 23:31:59 +11:00
parent 17ddfc6fb1
commit 97296d304a
2 changed files with 142 additions and 77 deletions

View file

@ -171,7 +171,7 @@
} }
} }
.dashboard .media { .media {
@include lib.spacing(15); @include lib.spacing(15);
.cover-art { .cover-art {
@ -316,7 +316,8 @@
} }
} }
.audio .media { .players {
.player {
@include lib.spacing(40, true); @include lib.spacing(40, true);
.cover-art { .cover-art {
@ -405,6 +406,43 @@
} }
} }
.indicators {
@include lib.spacing(10);
& > button {
@include lib.rounded(1000);
@include lib.element-decel;
min-width: lib.s(10);
min-height: lib.s(10);
background-color: color.change(scheme.$overlay0, $alpha: 0.5);
&:hover,
&:focus {
background-color: color.change(scheme.$overlay1, $alpha: 0.5);
}
&:active {
background-color: color.change(scheme.$overlay2, $alpha: 0.5);
}
&.active {
background-color: color.change(scheme.$primary, $alpha: 0.9);
&:hover,
&:focus {
background-color: color.change(scheme.$primary, $alpha: 0.7);
}
&:active {
background-color: color.change(scheme.$primary, $alpha: 0.6);
}
}
}
}
}
.networks { .networks {
.list { .list {
@include lib.spacing(10, true); @include lib.spacing(10, true);

View file

@ -1,6 +1,6 @@
import Players from "@/services/players"; import Players from "@/services/players";
import Slider from "@/widgets/slider"; import Slider from "@/widgets/slider";
import { bind, Variable } from "astal"; import { bind, timeout, Variable } from "astal";
import { Gtk } from "astal/gtk3"; import { Gtk } from "astal/gtk3";
import AstalMpris from "gi://AstalMpris"; import AstalMpris from "gi://AstalMpris";
@ -12,7 +12,7 @@ const lengthStr = (length: number) =>
const noNull = (s: string | null) => s ?? "-"; const noNull = (s: string | null) => s ?? "-";
const NoMedia = () => ( const NoMedia = () => (
<box vertical className="media" name="none"> <box vertical className="player" name="none">
<box homogeneous halign={Gtk.Align.CENTER} className="cover-art"> <box homogeneous halign={Gtk.Align.CENTER} className="cover-art">
<label xalign={0.4} label="" /> <label xalign={0.4} label="" />
</box> </box>
@ -50,7 +50,7 @@ const Player = ({ player }: { player: AstalMpris.Player }) => {
const position = Variable.derive([bind(player, "position"), bind(player, "length")], (p, l) => p / l); const position = Variable.derive([bind(player, "position"), bind(player, "length")], (p, l) => p / l);
return ( return (
<box vertical className="media" name={player.busName} onDestroy={() => position.drop()}> <box vertical className="player" name={player.busName} onDestroy={() => position.drop()}>
<box <box
homogeneous homogeneous
halign={Gtk.Align.CENTER} halign={Gtk.Align.CENTER}
@ -131,19 +131,46 @@ const Player = ({ player }: { player: AstalMpris.Player }) => {
); );
}; };
const Indicator = ({ active, player }: { active: Variable<string>; player: AstalMpris.Player }) => (
<button
className={bind(active).as(a => (a === player.busName ? "active" : ""))}
cursor="pointer"
onClicked={() => active.set(player.busName)}
/>
);
export default () => { export default () => {
const active = Variable(Players.get_default().list[0]?.busName ?? "none"); const players = Players.get_default();
const active = Variable(players.lastPlayer?.busName ?? "none");
active.observe(players, "notify::list", () => {
const prev = active.get();
timeout(10, () => {
if (players.list.some(p => p.busName === prev)) active.set(prev);
else active.set(players.lastPlayer?.busName ?? "none");
});
return "none";
});
return ( return (
<box vertical> <box vertical className="players" onDestroy={() => active.drop()}>
<stack <stack
transitionType={Gtk.StackTransitionType.SLIDE_LEFT_RIGHT} transitionType={Gtk.StackTransitionType.SLIDE_LEFT_RIGHT}
transitionDuration={150} transitionDuration={150}
shown={bind(active)} shown={bind(active)}
> >
<NoMedia /> <NoMedia />
{bind(Players.get_default(), "list").as(ps => ps.map(p => <Player player={p} />))} {bind(players, "list").as(ps => ps.map(p => <Player player={p} />))}
</stack> </stack>
<revealer
transitionType={Gtk.RevealerTransitionType.SLIDE_DOWN}
transitionDuration={120}
revealChild={bind(players, "list").as(l => l.length > 1)}
>
<box halign={Gtk.Align.CENTER} className="indicators">
{bind(players, "list").as(ps => ps.map(p => <Indicator active={active} player={p} />))}
</box>
</revealer>
</box> </box>
); );
}; };