183 lines
4.9 KiB
TypeScript
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,
|
|
});
|
|
};
|