sidebar: player switching
This commit is contained in:
parent
17ddfc6fb1
commit
97296d304a
2 changed files with 142 additions and 77 deletions
|
|
@ -171,7 +171,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard .media {
|
.media {
|
||||||
@include lib.spacing(15);
|
@include lib.spacing(15);
|
||||||
|
|
||||||
.cover-art {
|
.cover-art {
|
||||||
|
|
@ -316,91 +316,129 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.audio .media {
|
.players {
|
||||||
@include lib.spacing(40, true);
|
.player {
|
||||||
|
@include lib.spacing(40, true);
|
||||||
|
|
||||||
.cover-art {
|
.cover-art {
|
||||||
@include lib.rounded(10);
|
@include lib.rounded(10);
|
||||||
@include lib.element-decel;
|
@include lib.element-decel;
|
||||||
@include lib.shadow(scheme.$mantle, $blur: 5, $spread: 2);
|
@include lib.shadow(scheme.$mantle, $blur: 5, $spread: 2);
|
||||||
|
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
min-width: lib.s(256);
|
min-width: lib.s(256);
|
||||||
min-height: lib.s(256);
|
min-height: lib.s(256);
|
||||||
font-size: lib.s(96);
|
font-size: lib.s(96);
|
||||||
font-weight: bold;
|
|
||||||
background-color: scheme.$base;
|
|
||||||
color: scheme.$subtext0;
|
|
||||||
margin-top: lib.s(20);
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress {
|
|
||||||
margin: 0 lib.s(40);
|
|
||||||
|
|
||||||
.slider {
|
|
||||||
@include lib.rounded(8);
|
|
||||||
@include lib.fluent-decel(1000ms);
|
|
||||||
|
|
||||||
min-height: lib.s(15);
|
|
||||||
background-color: scheme.$overlay0;
|
|
||||||
color: scheme.$subtext1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time {
|
|
||||||
margin-top: lib.s(5);
|
|
||||||
font-size: lib.s(13);
|
|
||||||
color: scheme.$subtext1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.details {
|
|
||||||
font-size: lib.s(14);
|
|
||||||
margin-top: lib.s(20);
|
|
||||||
|
|
||||||
@include lib.spacing(3, true);
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: lib.s(18);
|
|
||||||
color: scheme.$text;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
background-color: scheme.$base;
|
||||||
|
|
||||||
.artist {
|
|
||||||
color: scheme.$green;
|
|
||||||
}
|
|
||||||
|
|
||||||
.album {
|
|
||||||
color: scheme.$subtext0;
|
color: scheme.$subtext0;
|
||||||
|
margin-top: lib.s(20);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.controls {
|
.progress {
|
||||||
margin-top: lib.s(-20);
|
margin: 0 lib.s(40);
|
||||||
margin-bottom: lib.s(5);
|
|
||||||
|
|
||||||
button {
|
.slider {
|
||||||
@include media-button;
|
@include lib.rounded(8);
|
||||||
|
@include lib.fluent-decel(1000ms);
|
||||||
|
|
||||||
// Cause some nerd font icons don't have the correct width
|
min-height: lib.s(15);
|
||||||
&.needs-adjustment {
|
background-color: scheme.$overlay0;
|
||||||
padding-right: lib.s(5);
|
color: scheme.$subtext1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
margin-top: lib.s(5);
|
||||||
|
font-size: lib.s(13);
|
||||||
|
color: scheme.$subtext1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.playback {
|
.details {
|
||||||
font-size: lib.s(32);
|
font-size: lib.s(14);
|
||||||
|
margin-top: lib.s(20);
|
||||||
|
|
||||||
@include lib.spacing(40);
|
@include lib.spacing(3, true);
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: lib.s(18);
|
||||||
|
color: scheme.$text;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.artist {
|
||||||
|
color: scheme.$green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album {
|
||||||
|
color: scheme.$subtext0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.options {
|
.controls {
|
||||||
margin: 0 lib.s(40);
|
margin-top: lib.s(-20);
|
||||||
margin-top: lib.s(-10);
|
margin-bottom: lib.s(5);
|
||||||
font-size: lib.s(20);
|
|
||||||
|
|
||||||
@include lib.spacing(20);
|
button {
|
||||||
|
@include media-button;
|
||||||
|
|
||||||
|
// Cause some nerd font icons don't have the correct width
|
||||||
|
&.needs-adjustment {
|
||||||
|
padding-right: lib.s(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.playback {
|
||||||
|
font-size: lib.s(32);
|
||||||
|
|
||||||
|
@include lib.spacing(40);
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
margin: 0 lib.s(40);
|
||||||
|
margin-top: lib.s(-10);
|
||||||
|
font-size: lib.s(20);
|
||||||
|
|
||||||
|
@include lib.spacing(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue