mirror of
https://github.com/Theaninova/TheaninovOS.git
synced 2025-12-12 11:36:20 +00:00
refactor: make the whole thing more generic
This commit is contained in:
263
modules/home-manager/desktops/hyprland/ags/js/misc/mpris.js
Normal file
263
modules/home-manager/desktops/hyprland/ags/js/misc/mpris.js
Normal file
@@ -0,0 +1,263 @@
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import * as Utils from "resource:///com/github/Aylur/ags/utils.js";
|
||||
import icons from "../icons.js";
|
||||
import { blurImg } from "../utils.js";
|
||||
|
||||
/**
|
||||
* @param {import('types/service/mpris').MprisPlayer} player
|
||||
* @param {import('types/widgets/box').BoxProps=} props
|
||||
*/
|
||||
export const CoverArt = (player, props) =>
|
||||
Widget.Box({
|
||||
...props,
|
||||
class_name: "cover",
|
||||
css: player
|
||||
.bind("cover_path")
|
||||
.transform((p) => `background-image: url("${p}")`),
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {import('types/service/mpris').MprisPlayer} player
|
||||
* @param {import('types/widgets/box').BoxProps=} props
|
||||
*/
|
||||
export const BlurredCoverArt = (player, props) =>
|
||||
Widget.Box({
|
||||
...props,
|
||||
class_name: "blurred-cover",
|
||||
setup: (self) =>
|
||||
self.hook(
|
||||
player,
|
||||
(box) =>
|
||||
blurImg(player.cover_path).then((img) => {
|
||||
img && box.setCss(`background-image: url("${img}")`);
|
||||
}),
|
||||
"notify::cover-path",
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {import('types/service/mpris').MprisPlayer} player
|
||||
* @param {import('types/widgets/label').Props=} props
|
||||
*/
|
||||
export const TitleLabel = (player, props) =>
|
||||
Widget.Label({
|
||||
...props,
|
||||
class_name: "title",
|
||||
label: player.bind("track_title"),
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {import('types/service/mpris').MprisPlayer} player
|
||||
* @param {import('types/widgets/label').Props=} props
|
||||
*/
|
||||
export const ArtistLabel = (player, props) =>
|
||||
Widget.Label({
|
||||
...props,
|
||||
class_name: "artist",
|
||||
label: player.bind("track_artists").transform((a) => a.join(", ") || ""),
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {import('types/service/mpris').MprisPlayer} player
|
||||
* @param {import('types/widgets/icon').Props & { symbolic?: boolean }=} props
|
||||
*/
|
||||
export const PlayerIcon = (player, { symbolic = true, ...props } = {}) =>
|
||||
Widget.Icon({
|
||||
...props,
|
||||
class_name: "player-icon",
|
||||
tooltip_text: player.identity || "",
|
||||
setup: (self) =>
|
||||
self.hook(player, (icon) => {
|
||||
const name = `${player.entry}${symbolic ? "-symbolic" : ""}`;
|
||||
Utils.lookUpIcon(name)
|
||||
? (icon.icon = name)
|
||||
: (icon.icon = icons.mpris.fallback);
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {import('types/service/mpris').MprisPlayer} player
|
||||
* @param {import('types/widgets/slider').SliderProps=} props
|
||||
*/
|
||||
export const PositionSlider = (player, props) =>
|
||||
Widget.Slider({
|
||||
...props,
|
||||
class_name: "position-slider",
|
||||
draw_value: false,
|
||||
on_change: ({ value }) => (player.position = player.length * value),
|
||||
setup: (self) => {
|
||||
const update = () => {
|
||||
if (self.dragging) return;
|
||||
|
||||
self.visible = player.length > 0;
|
||||
if (player.length > 0) self.value = player.position / player.length;
|
||||
};
|
||||
self.hook(player, update);
|
||||
self.hook(player, update, "position");
|
||||
self.poll(1000, update);
|
||||
},
|
||||
});
|
||||
|
||||
/** @param {number} length */
|
||||
function lengthStr(length) {
|
||||
const min = Math.floor(length / 60);
|
||||
const sec = Math.floor(length % 60);
|
||||
const sec0 = sec < 10 ? "0" : "";
|
||||
return `${min}:${sec0}${sec}`;
|
||||
}
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const PositionLabel = (player) =>
|
||||
Widget.Label({
|
||||
setup: (self) => {
|
||||
const update = (_, time) => {
|
||||
player.length > 0
|
||||
? (self.label = lengthStr(time || player.position))
|
||||
: (self.visible = !!player);
|
||||
};
|
||||
self.hook(player, update, "position");
|
||||
self.poll(1000, update);
|
||||
},
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const LengthLabel = (player) =>
|
||||
Widget.Label({
|
||||
label: player.bind("length").transform((l) => lengthStr(l)),
|
||||
visible: player.bind("length").transform((l) => l > 0),
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const Slash = (player) =>
|
||||
Widget.Label({
|
||||
label: "/",
|
||||
visible: player.bind("length").transform((l) => l > 0),
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {Object} o
|
||||
* @param {import('types/service/mpris').MprisPlayer} o.player
|
||||
* @param {import('types/widgets/stack').StackProps['children']} o.children
|
||||
* @param {'shuffle' | 'loop' | 'playPause' | 'previous' | 'next'} o.onClick
|
||||
* @param {string} o.prop
|
||||
* @param {string} o.canProp
|
||||
* @param {any} o.cantValue
|
||||
*/
|
||||
const PlayerButton = ({
|
||||
player,
|
||||
children,
|
||||
onClick,
|
||||
prop,
|
||||
canProp,
|
||||
cantValue,
|
||||
}) =>
|
||||
Widget.Button({
|
||||
child: Widget.Stack({ children }).bind(
|
||||
"shown",
|
||||
player,
|
||||
prop,
|
||||
(p) => `${p}`,
|
||||
),
|
||||
on_clicked: () => player[onClick](),
|
||||
visible: player.bind(canProp).transform((c) => c !== cantValue),
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const ShuffleButton = (player) =>
|
||||
PlayerButton({
|
||||
player,
|
||||
children: {
|
||||
true: Widget.Label({
|
||||
class_name: "shuffle enabled",
|
||||
label: icons.mpris.shuffle.enabled,
|
||||
}),
|
||||
false: Widget.Label({
|
||||
class_name: "shuffle disabled",
|
||||
label: icons.mpris.shuffle.disabled,
|
||||
}),
|
||||
},
|
||||
onClick: "shuffle",
|
||||
prop: "shuffle-status",
|
||||
canProp: "shuffle-status",
|
||||
cantValue: null,
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const LoopButton = (player) =>
|
||||
PlayerButton({
|
||||
player,
|
||||
children: {
|
||||
None: Widget.Label({
|
||||
class_name: "loop none",
|
||||
label: icons.mpris.loop.none,
|
||||
}),
|
||||
Track: Widget.Label({
|
||||
class_name: "loop track",
|
||||
label: icons.mpris.loop.track,
|
||||
}),
|
||||
Playlist: Widget.Label({
|
||||
class_name: "loop playlist",
|
||||
label: icons.mpris.loop.playlist,
|
||||
}),
|
||||
},
|
||||
onClick: "loop",
|
||||
prop: "loop-status",
|
||||
canProp: "loop-status",
|
||||
cantValue: null,
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const PlayPauseButton = (player) =>
|
||||
PlayerButton({
|
||||
player,
|
||||
children: {
|
||||
Playing: Widget.Label({
|
||||
class_name: "playing",
|
||||
label: icons.mpris.playing,
|
||||
}),
|
||||
Paused: Widget.Label({
|
||||
class_name: "paused",
|
||||
label: icons.mpris.paused,
|
||||
}),
|
||||
Stopped: Widget.Label({
|
||||
class_name: "stopped",
|
||||
label: icons.mpris.stopped,
|
||||
}),
|
||||
},
|
||||
onClick: "playPause",
|
||||
prop: "play-back-status",
|
||||
canProp: "can-play",
|
||||
cantValue: false,
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const PreviousButton = (player) =>
|
||||
PlayerButton({
|
||||
player,
|
||||
children: {
|
||||
true: Widget.Label({
|
||||
class_name: "previous",
|
||||
label: icons.mpris.prev,
|
||||
}),
|
||||
},
|
||||
onClick: "previous",
|
||||
prop: "can-go-prev",
|
||||
canProp: "can-go-prev",
|
||||
cantValue: false,
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const NextButton = (player) =>
|
||||
PlayerButton({
|
||||
player,
|
||||
children: {
|
||||
true: Widget.Label({
|
||||
class_name: "next",
|
||||
label: icons.mpris.next,
|
||||
}),
|
||||
},
|
||||
onClick: "next",
|
||||
prop: "can-go-next",
|
||||
canProp: "can-go-next",
|
||||
cantValue: false,
|
||||
});
|
||||
Reference in New Issue
Block a user