import { timeout } from "ags/time"; import { Astal, Gtk } from "ags/gtk4"; import { Clipboard } from "../../modules/clipboard"; import { getMediaUrl } from "../bar/Media"; import { player, setPlayer } from "../../modules/media"; import { createBinding, For } from "ags"; import { pathToURI, variableToBoolean } from "../../modules/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 = () => { 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 {carousel} pls.length > 1)} transitionDuration={300} transitionType={Gtk.RevealerTransitionType.SLIDE_UP}> as Gtk.Box; } @register({ GTypeName: "PlayerWidget" }) class PlayerWidget extends Gtk.Box { #player!: AstalMpris.Player; get player() { return this.#player; } constructor({ player }: { player: AstalMpris.Player }) { super(); 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; } }