media: make popdown window
5
assets/icons/caelestia-consecutive-symbolic.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 12 1 v 2 h -12 v 2 h 12 v 2 h 1 v -0.007812 c 0.265625 0.003906 0.519531 -0.101563 0.707031 -0.285157 l 2 -2 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 l -2 -2 c -0.1875 -0.183594 -0.441406 -0.289063 -0.707031 -0.285157 v -0.007812 z m 0 8 v 2 h -12 v 2 h 12 v 2 h 1 v -0.007812 c 0.265625 0.003906 0.519531 -0.101563 0.707031 -0.285157 l 2 -2 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 l -2 -2 c -0.1875 -0.183594 -0.441406 -0.289063 -0.707031 -0.285157 v -0.007812 z m 0 0" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 746 B |
6
assets/icons/caelestia-no-repeat-symbolic.svg
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
8
assets/icons/caelestia-pause-symbolic.svg
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#000000">
|
||||
<path d="m 3 1 h 3 c 0.550781 0 1 0.449219 1 1 v 12 c 0 0.550781 -0.449219 1 -1 1 h -3 c -0.550781 0 -1 -0.449219 -1 -1 v -12 c 0 -0.550781 0.449219 -1 1 -1 z m 0 0"/>
|
||||
<path d="m 10 1 h 3 c 0.550781 0 1 0.449219 1 1 v 12 c 0 0.550781 -0.449219 1 -1 1 h -3 c -0.550781 0 -1 -0.449219 -1 -1 v -12 c 0 -0.550781 0.449219 -1 1 -1 z m 0 0"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 608 B |
5
assets/icons/caelestia-play-symbolic.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 2 2.5 v 11 c 0 1.5 1.269531 1.492188 1.269531 1.492188 h 0.128907 c 0.246093 0.003906 0.488281 -0.050782 0.699218 -0.171876 l 9.796875 -5.597656 c 0.433594 -0.242187 0.65625 -0.734375 0.65625 -1.226562 c 0 -0.492188 -0.222656 -0.984375 -0.65625 -1.222656 l -9.796875 -5.597657 c -0.210937 -0.121093 -0.453125 -0.175781 -0.699218 -0.175781 h -0.128907 s -1.269531 0 -1.269531 1.5 z m 0 0" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 640 B |
5
assets/icons/caelestia-repeat-one-symbolic.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 7 1 v 2 h -3 c -2.199219 0 -4 1.800781 -4 4 v 2 c 0 1.019531 0.386719 1.964844 1.019531 2.671875 c 0.367188 0.410156 1 0.445313 1.410157 0.078125 c 0.414062 -0.367188 0.449218 -1 0.078124 -1.414062 c -0.316406 -0.351563 -0.507812 -0.8125 -0.507812 -1.335938 v -2 c 0 -1.125 0.875 -2 2 -2 h 3 v 2 h 1 v -0.007812 c 0.265625 0.003906 0.519531 -0.101563 0.707031 -0.285157 l 2 -2 c 0.207031 -0.207031 0.3125 -0.496093 0.289063 -0.789062 c 0 -0.015625 -0.003906 -0.03125 -0.007813 -0.046875 c -0.007812 -0.070313 -0.023437 -0.136719 -0.046875 -0.203125 c -0.011718 -0.035157 -0.023437 -0.070313 -0.042968 -0.101563 c 0 -0.007812 -0.003907 -0.011718 -0.007813 -0.019531 c -0.011719 -0.023437 -0.027344 -0.046875 -0.039063 -0.070313 c -0.007812 -0.011718 -0.019531 -0.027343 -0.027343 -0.039062 c -0.015625 -0.019531 -0.027344 -0.042969 -0.042969 -0.0625 c -0.007812 -0.007812 -0.015625 -0.015625 -0.023438 -0.023438 c -0.015624 -0.019531 -0.03125 -0.039062 -0.050781 -0.058593 l -2 -2 c -0.1875 -0.183594 -0.441406 -0.289063 -0.707031 -0.285157 v -0.007812 z m 7 1 c -1.105469 0 -2 0.894531 -2 2 s 0.894531 2 2 2 s 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 1 5 c -0.550781 0 -1 0.449219 -1 1 v 1.007812 c 0 1.125 -0.875 2 -2 2 h -4 v -2.007812 h -1 v 0.007812 c -0.265625 -0.003906 -0.519531 0.101563 -0.707031 0.285157 l -2 2 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 l 2 2 c 0.1875 0.183594 0.441406 0.289063 0.707031 0.285157 v 0.007812 h 1 v -1.992188 h 4 c 2.199219 0 4 -1.804687 4 -4 v -1.007812 c 0 -0.550781 -0.449219 -1 -1 -1 z m 0 0" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
5
assets/icons/caelestia-repeat-symbolic.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 8 1 v 2 h -4 c -2.199219 0 -4 1.800781 -4 4 v 2 c 0 1.019531 0.386719 1.964844 1.019531 2.671875 c 0.367188 0.410156 1 0.445313 1.410157 0.078125 c 0.414062 -0.367188 0.449218 -1 0.078124 -1.414062 c -0.316406 -0.351563 -0.507812 -0.8125 -0.507812 -1.335938 v -2 c 0 -1.125 0.875 -2 2 -2 h 4 v 2 h 1 v -0.007812 c 0.265625 0.003906 0.519531 -0.101563 0.707031 -0.285157 l 2 -2 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 l -2 -2 c -0.1875 -0.183594 -0.441406 -0.289063 -0.707031 -0.285157 v -0.007812 z m 6.289062 3 c -0.265624 -0.011719 -0.523437 0.078125 -0.71875 0.257812 c -0.414062 0.367188 -0.449218 1 -0.078124 1.410157 c 0.316406 0.355469 0.507812 0.816406 0.507812 1.339843 v 2 c 0 1.125 -0.875 2 -2 2 h -4 v -2.007812 h -1 v 0.007812 c -0.265625 -0.003906 -0.519531 0.101563 -0.707031 0.285157 l -2 2 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 l 2 2 c 0.1875 0.183594 0.441406 0.289063 0.707031 0.285157 v 0.007812 h 1 v -1.992188 h 4 c 2.199219 0 4 -1.804687 4 -4 v -2 c 0 -1.023437 -0.386719 -1.96875 -1.019531 -2.675781 c -0.175781 -0.199219 -0.425781 -0.316406 -0.691407 -0.332031 z m 0 0" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
5
assets/icons/caelestia-shuffle-symbolic.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 12 1 v 2 h -3 c -0.859375 0 -1.59375 0.480469 -2.011719 1.007812 c -0.417969 0.523438 -0.648437 1.074219 -0.882812 1.542969 l -0.105469 0.210938 l -0.105469 -0.210938 c -0.191406 -0.382812 -0.386719 -0.816406 -0.671875 -1.25 c -0.414062 -0.632812 -1.207031 -1.300781 -2.222656 -1.300781 h -3 v 2 h 3 c 0.296875 0 0.316406 0.039062 0.550781 0.398438 c 0.164063 0.246093 0.34375 0.625 0.554688 1.050781 l 0.777343 1.550781 l -0.777343 1.550781 c -0.261719 0.523438 -0.476563 0.96875 -0.65625 1.199219 c -0.183594 0.226562 -0.199219 0.25 -0.449219 0.25 h -3 v 2 h 3 c 0.859375 0 1.59375 -0.480469 2.011719 -1.007812 c 0.417969 -0.523438 0.648437 -1.074219 0.882812 -1.542969 l 0.105469 -0.210938 l 0.105469 0.210938 c 0.164062 0.328125 0.335937 0.703125 0.5625 1.078125 c 0.414062 0.6875 1.222656 1.472656 2.332031 1.472656 h 3 v 2 h 1 v -0.007812 c 0.265625 0.003906 0.519531 -0.101563 0.707031 -0.285157 l 2 -2 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 l -2 -2 c -0.1875 -0.183594 -0.441406 -0.289063 -0.707031 -0.285157 v -0.007812 h -1 v 2 h -3 c -0.324219 0 -0.351562 -0.058594 -0.617188 -0.503906 c -0.148437 -0.242188 -0.304687 -0.574219 -0.488281 -0.945313 l -0.777343 -1.550781 l 0.777343 -1.550781 c 0.261719 -0.523438 0.476563 -0.96875 0.65625 -1.199219 c 0.183594 -0.226562 0.199219 -0.25 0.449219 -0.25 h 3 v 2 h 1 v -0.007812 c 0.265625 0.003906 0.519531 -0.101563 0.707031 -0.285157 l 2 -2 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 l -2 -2 c -0.1875 -0.183594 -0.441406 -0.289063 -0.707031 -0.285157 v -0.007812 z m 0 0" fill="#000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
8
assets/icons/caelestia-skip-next-symbolic.svg
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#000000">
|
||||
<path d="m 1 3 v 10 c 0 1 1.085938 1 1.085938 1 h 0.113281 c 0.210937 0 0.417969 -0.046875 0.601562 -0.148438 l 8.398438 -4.800781 c 0.375 -0.207031 0.5625 -0.628906 0.5625 -1.050781 s -0.1875 -0.84375 -0.5625 -1.050781 l -8.398438 -4.800781 c -0.183593 -0.101563 -0.390625 -0.148438 -0.601562 -0.148438 h -0.113281 s -1.085938 0 -1.085938 1 z m 0 0"/>
|
||||
<path d="m 14.5 2 h -1 c -0.277344 0 -0.5 0.222656 -0.5 0.5 v 11 c 0 0.277344 0.222656 0.5 0.5 0.5 h 1 c 0.277344 0 0.5 -0.222656 0.5 -0.5 v -11 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 z m 0 0"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 819 B |
8
assets/icons/caelestia-skip-previous-symbolic.svg
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#000000">
|
||||
<path d="m 15 3 v 10 c 0 1 -1.085938 1 -1.085938 1 h -0.113281 c -0.210937 0 -0.417969 -0.046875 -0.601562 -0.148438 l -8.398438 -4.800781 c -0.375 -0.207031 -0.5625 -0.628906 -0.5625 -1.050781 s 0.1875 -0.84375 0.5625 -1.050781 l 8.398438 -4.800781 c 0.183593 -0.101563 0.390625 -0.148438 0.601562 -0.148438 h 0.113281 s 1.085938 0 1.085938 1 z m 0 0"/>
|
||||
<path d="m 1.5 2 h 1 c 0.277344 0 0.5 0.222656 0.5 0.5 v 11 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -1 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -11 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 820 B |
|
|
@ -2,3 +2,4 @@
|
|||
@forward "updates";
|
||||
@forward "bluetoothdevices";
|
||||
@forward "networks";
|
||||
@forward "media";
|
||||
|
|
|
|||
113
scss/popdowns/media.scss
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
@use "sass:color";
|
||||
@use "../scheme";
|
||||
@use "../lib";
|
||||
@use "../font";
|
||||
|
||||
$-accent: scheme.$lavender;
|
||||
$-accent2: scheme.$pink;
|
||||
|
||||
.media {
|
||||
@include lib.rounded(8);
|
||||
@include lib.border($-accent, 0.4, 2);
|
||||
@include lib.shadow;
|
||||
@include font.mono;
|
||||
|
||||
background-color: scheme.$base;
|
||||
color: $-accent;
|
||||
padding: lib.s(12);
|
||||
font-size: lib.s(14);
|
||||
min-width: lib.s(500);
|
||||
min-height: lib.s(220);
|
||||
|
||||
.icon {
|
||||
font-size: lib.s(32);
|
||||
}
|
||||
|
||||
.overlay {
|
||||
@include lib.rounded(5);
|
||||
|
||||
background-color: color.change(scheme.$base, $alpha: 0.8);
|
||||
}
|
||||
|
||||
.background {
|
||||
@include lib.rounded(5);
|
||||
|
||||
transition: background 300ms ease-in-out;
|
||||
background-color: scheme.$surface0;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.player {
|
||||
padding: lib.s(35) lib.s(12);
|
||||
font-weight: bold;
|
||||
|
||||
@include lib.spacing(10, true);
|
||||
|
||||
.title {
|
||||
font-size: lib.s(18);
|
||||
}
|
||||
|
||||
.artist {
|
||||
color: scheme.$green;
|
||||
}
|
||||
|
||||
.album {
|
||||
color: $-accent2;
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin-top: lib.s(3);
|
||||
|
||||
@include lib.spacing(10);
|
||||
|
||||
button {
|
||||
@include lib.rounded(4);
|
||||
@include lib.element-decel;
|
||||
@include lib.border(scheme.$base, 0.7);
|
||||
|
||||
padding: lib.s(5) lib.s(12);
|
||||
font-size: lib.s(18);
|
||||
background-color: $-accent;
|
||||
color: scheme.$base;
|
||||
|
||||
&:disabled {
|
||||
background-color: scheme.$overlay2;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: color.change($-accent, $alpha: 0.8);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: color.change($-accent, $alpha: 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Progress bar
|
||||
trough {
|
||||
@include lib.rounded(3);
|
||||
|
||||
margin-top: lib.s(10);
|
||||
background-color: scheme.$surface0;
|
||||
|
||||
highlight {
|
||||
@include lib.rounded(3);
|
||||
|
||||
background-color: $-accent2;
|
||||
padding: lib.s(3) 0;
|
||||
}
|
||||
|
||||
slider {
|
||||
@include lib.rounded(3);
|
||||
|
||||
background-color: scheme.$overlay0;
|
||||
min-width: lib.s(15);
|
||||
min-height: lib.s(15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -87,9 +87,9 @@ const MediaPlaying = () => {
|
|||
players.lastPlayer ? `${players.lastPlayer.title} - ${players.lastPlayer.artist}` : fallback;
|
||||
return (
|
||||
<button
|
||||
onClick={(_, event) => {
|
||||
onClick={(self, event) => {
|
||||
if (event.button === Astal.MouseButton.PRIMARY) {
|
||||
// TODO: media panel
|
||||
togglePopup(self, event, "media");
|
||||
} else if (event.button === Astal.MouseButton.SECONDARY) players.lastPlayer?.play_pause();
|
||||
else if (event.button === Astal.MouseButton.MIDDLE) players.lastPlayer?.raise();
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import BluetoothDevices from "./bluetoothdevices";
|
||||
import Media from "./media";
|
||||
import Networks from "./networks";
|
||||
import Notifications from "./notifications";
|
||||
import Updates from "./updates";
|
||||
|
|
@ -8,6 +9,7 @@ export default () => {
|
|||
<Updates />;
|
||||
<BluetoothDevices />;
|
||||
<Networks />;
|
||||
<Media />;
|
||||
|
||||
return null;
|
||||
};
|
||||
|
|
|
|||
140
src/modules/popdowns/media.tsx
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import { bind, Variable } from "astal";
|
||||
import { Astal, Gtk } from "astal/gtk3";
|
||||
import AstalMpris from "gi://AstalMpris";
|
||||
import Players from "../../services/players";
|
||||
import { isRealPlayer } from "../../utils/mpris";
|
||||
import PopupWindow from "../../widgets/popupwindow";
|
||||
|
||||
const shuffleToIcon = (s: AstalMpris.Shuffle) =>
|
||||
`caelestia-${s === AstalMpris.Shuffle.ON ? "shuffle" : "consecutive"}-symbolic`;
|
||||
|
||||
const playbackToIcon = (s: AstalMpris.PlaybackStatus) =>
|
||||
`caelestia-${s === AstalMpris.PlaybackStatus.PLAYING ? "pause" : "play"}-symbolic`;
|
||||
|
||||
const loopToIcon = (s: AstalMpris.Loop) => {
|
||||
if (s === AstalMpris.Loop.PLAYLIST) return "caelestia-repeat-symbolic";
|
||||
if (s === AstalMpris.Loop.TRACK) return "caelestia-repeat-one-symbolic";
|
||||
return "caelestia-no-repeat-symbolic";
|
||||
};
|
||||
|
||||
const lengthStr = (length: number) =>
|
||||
`${Math.floor(length / 60)}:${Math.floor(length % 60)
|
||||
.toString()
|
||||
.padStart(2, "0")}`;
|
||||
|
||||
const Player = ({ player }: { player: AstalMpris.Player }) => {
|
||||
const background = (
|
||||
<box className="background" css={bind(player, "artUrl").as(u => u && `background-image: url("${u}");`)} />
|
||||
);
|
||||
return (
|
||||
<overlay
|
||||
overlays={[
|
||||
<box className="overlay" />,
|
||||
<box
|
||||
vertical
|
||||
className="player"
|
||||
setup={self =>
|
||||
self.connect("size-allocate", () =>
|
||||
background.set_size_request(self.get_preferred_width()[1], self.get_preferred_height()[1])
|
||||
)
|
||||
}
|
||||
>
|
||||
<label className="title" label={bind(player, "title").as(t => t ?? "")} />
|
||||
<label className="artist" label={bind(player, "artist").as(a => a ?? "")} />
|
||||
<label className="album" label={bind(player, "album").as(a => a ?? "")} />
|
||||
<box className="controls" halign={Gtk.Align.CENTER}>
|
||||
<button cursor="pointer" onClicked={() => player.shuffle()} sensitive={player.canControl}>
|
||||
<icon icon={bind(player, "shuffleStatus").as(shuffleToIcon)} />
|
||||
</button>
|
||||
<button cursor="pointer" onClicked={() => player.previous()} sensitive={player.canGoPrevious}>
|
||||
<icon icon="caelestia-skip-previous-symbolic" />
|
||||
</button>
|
||||
<button cursor="pointer" onClicked={() => player.play_pause()} sensitive={player.canControl}>
|
||||
<icon icon={bind(player, "playbackStatus").as(playbackToIcon)} />
|
||||
</button>
|
||||
<button cursor="pointer" onClicked={() => player.next()} sensitive={player.canGoNext}>
|
||||
<icon icon="caelestia-skip-next-symbolic" />
|
||||
</button>
|
||||
<button cursor="pointer" onClicked={() => player.loop()} sensitive={player.canControl}>
|
||||
<icon icon={bind(player, "loopStatus").as(loopToIcon)} />
|
||||
</button>
|
||||
</box>
|
||||
<slider
|
||||
hexpand
|
||||
onDragged={self => player.set_position(self.value * player.length)}
|
||||
setup={self => {
|
||||
const update = () => {
|
||||
self.set_tooltip_text(`${lengthStr(player.position)}/${lengthStr(player.length)}`);
|
||||
self.set_value(player.position / player.length);
|
||||
};
|
||||
self.hook(player, "notify::position", update);
|
||||
self.hook(player, "notify::length", update);
|
||||
update();
|
||||
}}
|
||||
/>
|
||||
</box>,
|
||||
]}
|
||||
>
|
||||
{background}
|
||||
</overlay>
|
||||
);
|
||||
};
|
||||
|
||||
export default () => {
|
||||
const shown = Variable("none");
|
||||
return (
|
||||
<PopupWindow name="media">
|
||||
<box className="media">
|
||||
<eventbox
|
||||
onClick={(_, event) => {
|
||||
if (event.button === Astal.MouseButton.SECONDARY) {
|
||||
const current = Players.get_default().list.find(p => p.busName === shown.get());
|
||||
if (current) Players.get_default().makeCurrent(current);
|
||||
}
|
||||
}}
|
||||
onScroll={(_, event) => {
|
||||
const players = AstalMpris.get_default().players.filter(isRealPlayer);
|
||||
const idx = players.findIndex(p => p.busName === shown.get());
|
||||
if (idx === -1) return;
|
||||
if (event.delta_y < 0) {
|
||||
if (idx > 0) shown.set(players[idx - 1].busName);
|
||||
} else if (idx < players.length - 1) shown.set(players[idx + 1].busName);
|
||||
}}
|
||||
>
|
||||
<stack
|
||||
expand
|
||||
transitionType={Gtk.StackTransitionType.SLIDE_LEFT_RIGHT}
|
||||
transitionDuration={150}
|
||||
shown={bind(shown)}
|
||||
setup={self => {
|
||||
const players = new Map<string, JSX.Element>();
|
||||
|
||||
const addPlayer = (player: AstalMpris.Player) => {
|
||||
if (!isRealPlayer(player) || players.has(player.busName)) return;
|
||||
const widget = <Player player={player} />;
|
||||
self.add_named(widget, player.busName);
|
||||
if (players.size === 0) shown.set(player.busName);
|
||||
players.set(player.busName, widget);
|
||||
};
|
||||
|
||||
for (const player of Players.get_default().list) addPlayer(player);
|
||||
|
||||
self.hook(AstalMpris.get_default(), "player-added", (_, player) => addPlayer(player));
|
||||
self.hook(AstalMpris.get_default(), "player-closed", (_, player) => {
|
||||
players.get(player.busName)?.destroy();
|
||||
players.delete(player.busName);
|
||||
if (shown.get() === player.busName)
|
||||
shown.set(AstalMpris.get_default().players.find(isRealPlayer)?.busName ?? "none");
|
||||
});
|
||||
}}
|
||||
>
|
||||
<box vertical valign={Gtk.Align.CENTER} name="none">
|
||||
<label className="icon" label="music_note" />
|
||||
<label label="No media playing" />
|
||||
</box>
|
||||
</stack>
|
||||
</eventbox>
|
||||
</box>
|
||||
</PopupWindow>
|
||||
);
|
||||
};
|
||||