nixos-configs/modules/ags/config/widgets/media-player/player.tsx
matt1432 2e15e10fd5
All checks were successful
Discord / discord commits (push) Has been skipped
feat(ags): finish migrating v1 to v2
2025-02-28 21:56:54 -05:00

183 lines
4.9 KiB
TypeScript

import { Variable } from 'astal';
import { Gtk } from 'astal/gtk3';
import { Box, CenterBox } from 'astal/gtk3/widget';
import Mpris from 'gi://AstalMpris';
import Separator from '../misc/separator';
import * as mpris from './mpris';
import PlayerGesture, {
PlayerGesture as PlayerGestureClass,
PlayerBox as PlayerBoxClass,
} from './gesture';
const FAVE_PLAYER = 'org.mpris.MediaPlayer2.spotify';
const SPACING = 8;
const Top = (
player: Mpris.Player,
overlay: PlayerGestureClass,
) => new Box({
className: 'top',
halign: Gtk.Align.START,
valign: Gtk.Align.START,
children: [
mpris.PlayerIcon(player, overlay),
],
});
const Center = (
player: Mpris.Player,
colors: Variable<mpris.Colors>,
) => new Box({
className: 'center',
children: [
(new CenterBox({
vertical: true,
start_widget: new Box({
className: 'metadata',
vertical: true,
halign: Gtk.Align.START,
valign: Gtk.Align.CENTER,
hexpand: true,
children: [
mpris.TitleLabel(player),
mpris.ArtistLabel(player),
],
}),
})),
(new CenterBox({
vertical: true,
center_widget: mpris.PlayPauseButton(player, colors),
})),
],
});
const Bottom = (
player: Mpris.Player,
colors: Variable<mpris.Colors>,
) => new Box({
className: 'bottom',
children: [
mpris.PreviousButton(player, colors),
Separator({ size: SPACING }),
mpris.PositionSlider(player, colors),
Separator({ size: SPACING }),
mpris.NextButton(player, colors),
Separator({ size: SPACING }),
mpris.ShuffleButton(player, colors),
Separator({ size: SPACING }),
mpris.LoopButton(player, colors),
],
});
const PlayerBox = (
player: Mpris.Player,
colors: Variable<mpris.Colors>,
overlay: PlayerGestureClass,
) => {
const widget = mpris.CoverArt(player, colors, {
className: `player ${player.identity}`,
hexpand: true,
start_widget: Top(player, overlay),
center_widget: Center(player, colors),
end_widget: Bottom(player, colors),
});
widget.visible = false;
return widget;
};
export default () => {
const content = PlayerGesture({
setup: (self) => {
const addPlayer = (player: Mpris.Player) => {
if (!player || self.players.has(player.bus_name)) {
return;
}
// Get the one on top so we can move it up later
const previousFirst = self.overlays.at(-1) as PlayerBoxClass;
// Make the new player
const colorsVar = Variable({
imageAccent: '#6b4fa2',
buttonAccent: '#ecdcff',
buttonText: '#25005a',
hoverAccent: '#d4baff',
});
self.players.set(
player.bus_name,
PlayerBox(player, colorsVar, self),
);
self.add_overlay(self.players.get(player.bus_name));
// Select favorite player at startup
if (!self.setup && self.players.has(FAVE_PLAYER)) {
self.moveToTop(self.players.get(FAVE_PLAYER));
self.setup = true;
}
// Move previousFirst on top again
else {
self.moveToTop(previousFirst);
}
};
const removePlayer = (player: Mpris.Player) => {
if (!player || !self.players.has(player.bus_name)) {
return;
}
const toDelete = self.players.get(player.bus_name);
// Get the one on top so we can move it up later
const previousFirst = self.overlays.at(-1) as PlayerBoxClass;
// Move previousFirst on top again
if (previousFirst !== toDelete) {
self.moveToTop(previousFirst);
}
else {
self.moveToTop(self.players.has(FAVE_PLAYER) ?
self.players.get(FAVE_PLAYER) :
self.overlays[0]);
}
// Remake overlays without deleted one
self.remove(toDelete);
self.players.delete(player.bus_name);
};
const mprisDefault = Mpris.get_default();
self.hook(mprisDefault, 'player-added', (_, player) => addPlayer(player));
self.hook(mprisDefault, 'player-closed', (_, player) => removePlayer(player));
mprisDefault.players.forEach(addPlayer);
},
});
return new Box({
className: 'media-player',
child: content,
});
};