diff --git a/ags/widget/center-window/BigMedia.tsx b/ags/widget/center-window/BigMedia.tsx
index 6c1bb95..804d450 100644
--- a/ags/widget/center-window/BigMedia.tsx
+++ b/ags/widget/center-window/BigMedia.tsx
@@ -2,239 +2,192 @@ import { timeout } from "ags/time";
import { Astal, Gtk } from "ags/gtk4";
import { Clipboard } from "../../scripts/clipboard";
import { getMediaUrl, player, setPlayer } from "../bar/Media";
-import { Accessor, createBinding, createConnection, For, With } from "ags";
-import { getPlayerIconFromBusName, pathToURI, variableToBoolean } from "../../scripts/utils";
+import { createBinding, For } from "ags";
+import { pathToURI, variableToBoolean } from "../../scripts/utils";
import AstalMpris from "gi://AstalMpris";
import AstalIO from "gi://AstalIO";
import Pango from "gi://Pango?version=1.0";
+import Adw from "gi://Adw?version=1";
+import { register } from "ags/gobject";
+let dragTimer: (AstalIO.Time|undefined);
+
export const BigMedia = () => {
- let dragTimer: (AstalIO.Time|undefined);
+ const availablePlayers = createBinding(AstalMpris.get_default(), "players").as(pls =>
+ pls.filter(p => p.available));
+
+ const carousel = {
+ const page = self.get_nth_page(num);
+ if(page instanceof PlayerWidget && player.get().busName !== page.player.busName)
+ setPlayer(page.player);
+ }}>
+ players.sort(pl =>
+ pl.busName === player.get().busName ? -1 : 1))}>
+
+ {(player: AstalMpris.Player) => }
+
+ as Adw.Carousel;
return pl.available)}>
+ visible={variableToBoolean(availablePlayers)}>
-
- {(player: AstalMpris.Player) => player.available &&
-
+ {carousel}
+ pls.length > 1)} transitionDuration={300}
+ transitionType={Gtk.RevealerTransitionType.SLIDE_UP}>
-
-
-
- `background-image: url("${pathToURI(art)}");`)}
- hexpand={false} vexpand={false} widthRequest={132} heightRequest={128}
- valign={Gtk.Align.START} halign={Gtk.Align.CENTER}>
-
-
-
-
-
-
-
- title ?? "No Title")
- } label={
- createBinding(player, "title").as(title => title ?? "No Title")
- } ellipsize={Pango.EllipsizeMode.END} maxWidthChars={25}
- />
- artist ?? "No Artist")
- } label={
- createBinding(player, "artist").as(artist => artist ?? "No Artist")
- } ellipsize={Pango.EllipsizeMode.END} maxWidthChars={28}
- />
-
-
-
-
- {(hasAlbumArt) => !hasAlbumArt &&
-
- }
-
-
-
-
- {
- if(type === undefined || type === null)
- return;
-
- if(!dragTimer) {
- dragTimer = timeout(200, () =>
- player.position = Math.floor(value));
-
- return;
- }
-
- dragTimer.cancel();
- dragTimer = timeout(200, () =>
- player.position = Math.floor(value));
- }}
- />
-
-
-
- {
- const sec = Math.floor(pos % 60);
- return pos > 0 && player.length > 0 ?
- `${Math.floor(pos / 60)}:${sec < 10 ? "0" : ""}${sec}`
- : "0:00";
- })} $type="start"
- />
-
-
- {
- const url = getMediaUrl(player).get();
- url && Clipboard.getDefault().copyAsync(url);
- }}
- />
-
- status !== AstalMpris.Shuffle.UNSUPPORTED)} iconName={
- createBinding(player, "shuffleStatus").as(status => status === AstalMpris.Shuffle.ON ?
- "media-playlist-shuffle-symbolic"
- : "media-playlist-consecutive-symbolic")} tooltipText={
- createBinding(player, "shuffleStatus").as(status => status === AstalMpris.Shuffle.ON ?
- "Shuffle"
- : "No shuffle")} onClicked={() => player.shuffle()}
- />
- player.canGoPrevious && player.previous()}
- />
-
- status === AstalMpris.PlaybackStatus.PLAYING ? "Pause" : "Play")}
- iconName={createBinding(player, "playbackStatus").as(status =>
- status === AstalMpris.PlaybackStatus.PLAYING ?
- "media-playback-pause-symbolic"
- : "media-playback-start-symbolic")} onClicked={() => player.play_pause()}
- />
- player.canGoNext && player.next()}
- />
- {
- if(status === AstalMpris.Loop.TRACK)
- return "media-playlist-repeat-song-symbolic";
-
- if(status === AstalMpris.Loop.PLAYLIST)
- return "media-playlist-repeat-symbolic";
-
- return "loop-arrow-symbolic";
- })} visible={createBinding(player, "loopStatus").as(status =>
- status !== AstalMpris.Loop.UNSUPPORTED)}
- tooltipText={createBinding(player, "loopStatus").as(status => {
- if(status === AstalMpris.Loop.TRACK)
- return "Loop song";
-
- if(status === AstalMpris.Loop.PLAYLIST)
- return "Loop playlist";
-
- return "No loop";
- })} onClicked={() => player.loop()}
- />
-
- { /* bananananananana */
- const sec = Math.floor(len % 60);
- return (len > 0 && Number.isFinite(len)) ?
- `${Math.floor(len / 60)}:${sec < 10 ? "0" : ""}${sec}`
- : "0:00";
- })} $type="end"
- />
-
-
- }
-
+
+
as Gtk.Box;
}
-export function PlayerSelectButton({ player, reveal, halign = Gtk.Align.CENTER, valign = Gtk.Align.CENTER }: {
- player: AstalMpris.Player,
- reveal?: Accessor|boolean,
- halign?: Gtk.Align;
- valign?: Gtk.Align;
-}) {
- const availablePlayers = createBinding(AstalMpris.get_default(), "players").as(players =>
- players.filter(p => p.available));
+@register({ GTypeName: "PlayerWidget" })
+class PlayerWidget extends Gtk.Box {
+ #player!: AstalMpris.Player;
- return
- apls.length > 1)}>
- {(show: boolean) => show &&
-
-
-
- {(pl: AstalMpris.Player) =>
- setPlayer(pl)}>
-
-
-
-
-
- }
-
-
- as Gtk.Popover
- } $={(self) => {
- const controllerMotion = Gtk.EventControllerMotion.new();
- self.add_controller(controllerMotion);
+ get player() { return this.#player; }
- self.set_child(
-
-
- {
- self.add_css_class("reveal");
- return true;
- }],
- [controllerMotion, "leave", () => {
- self.remove_css_class("reveal");
- return false;
- }]
- )
- }>
+ constructor({ player }: { player: AstalMpris.Player }) {
+ super();
-
-
- "go-down-symbolic"],
- [self.popover, "closed", () => "go-next-symbolic"]
- )
- } class={"arrow"} iconSize={Gtk.IconSize.NORMAL}
- />
-
-
- as Gtk.Box
- );
+ this.setPlayer(player);
+ this.set_orientation(Gtk.Orientation.VERTICAL);
+ this.set_hexpand(true);
+
+ this.append(
+
+
+
+ `background-image: url("${pathToURI(art)}");`)}
+ hexpand={false} vexpand={false} widthRequest={132} heightRequest={128}
+ valign={Gtk.Align.START} halign={Gtk.Align.CENTER}
+ />
+ as Gtk.Revealer
+ );
+
+ this.append(
+
+
+ title ?? "No Title")
+ } label={
+ createBinding(player, "title").as(title => title ?? "No Title")
+ } ellipsize={Pango.EllipsizeMode.END} maxWidthChars={25}
+ />
+ artist ?? "No Artist")
+ } label={
+ createBinding(player, "artist").as(artist => artist ?? "No Artist")
+ } ellipsize={Pango.EllipsizeMode.END} maxWidthChars={28}
+ />
+ as Gtk.Box
+ );
+
+ this.append(
+
+ {
+ if(type === undefined || type === null)
+ return;
+
+ if(!dragTimer) {
+ dragTimer = timeout(200, () =>
+ player.position = Math.floor(value));
+
+ return;
+ }
+
+ dragTimer.cancel();
+ dragTimer = timeout(200, () =>
+ player.position = Math.floor(value));
}}
/>
- }
-
- ;
+ as Gtk.Box
+ );
+
+ this.append(
+
+ {
+ const sec = Math.floor(pos % 60);
+ return pos > 0 && player.length > 0 ?
+ `${Math.floor(pos / 60)}:${sec < 10 ? "0" : ""}${sec}`
+ : "0:00";
+ })} $type="start"
+ />
+
+
+ {
+ const url = getMediaUrl(player).get();
+ url && Clipboard.getDefault().copyAsync(url);
+ }}
+ />
+
+ status !== AstalMpris.Shuffle.UNSUPPORTED)} iconName={
+ createBinding(player, "shuffleStatus").as(status => status === AstalMpris.Shuffle.ON ?
+ "media-playlist-shuffle-symbolic"
+ : "media-playlist-consecutive-symbolic")} tooltipText={
+ createBinding(player, "shuffleStatus").as(status => status === AstalMpris.Shuffle.ON ?
+ "Shuffle"
+ : "No shuffle")} onClicked={() => player.shuffle()}
+ />
+ player.canGoPrevious && player.previous()}
+ />
+
+ status === AstalMpris.PlaybackStatus.PLAYING ? "Pause" : "Play")}
+ iconName={createBinding(player, "playbackStatus").as(status =>
+ status === AstalMpris.PlaybackStatus.PLAYING ?
+ "media-playback-pause-symbolic"
+ : "media-playback-start-symbolic")} onClicked={() => player.play_pause()}
+ />
+ player.canGoNext && player.next()}
+ />
+ {
+ if(status === AstalMpris.Loop.TRACK)
+ return "media-playlist-repeat-song-symbolic";
+
+ if(status === AstalMpris.Loop.PLAYLIST)
+ return "media-playlist-repeat-symbolic";
+
+ return "loop-arrow-symbolic";
+ })} visible={createBinding(player, "loopStatus").as(status =>
+ status !== AstalMpris.Loop.UNSUPPORTED)}
+ tooltipText={createBinding(player, "loopStatus").as(status => {
+ if(status === AstalMpris.Loop.TRACK)
+ return "Loop song";
+
+ if(status === AstalMpris.Loop.PLAYLIST)
+ return "Loop playlist";
+
+ return "No loop";
+ })} onClicked={() => player.loop()}
+ />
+
+ { /* bananananananana */
+ const sec = Math.floor(len % 60);
+ return (len > 0 && Number.isFinite(len)) ?
+ `${Math.floor(len / 60)}:${sec < 10 ? "0" : ""}${sec}`
+ : "0:00";
+ })} $type="end"
+ />
+ as Gtk.CenterBox
+ );
+ }
+
+ setPlayer(player: AstalMpris.Player) {
+ this.#player = player;
+ }
}