home/natto/ags: init
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
183
home/natto/ags/windows/music-box/index.js
Normal file
183
home/natto/ags/windows/music-box/index.js
Normal file
@@ -0,0 +1,183 @@
|
||||
// Mostly taken from https://github.com/Aylur/ags/blob/11150225e62462bcd431d1e55185e810190a730a/example/media-widget/Media.js
|
||||
|
||||
import Popup, { Padding, Revealer } from "../../utils/popup.js";
|
||||
import { shrinkText } from "../../utils/text.js";
|
||||
import { lengthStr, blurBg } from "../../utils/music.js";
|
||||
import { findPlayer } from "../../utils/music.js";
|
||||
import { WindowNames } from "../../constants.js";
|
||||
import Controls from "./music-controls.js";
|
||||
|
||||
const FALLBACK_ICON = "audio-x-generic-symbolic";
|
||||
const { MUSIC_BOX } = WindowNames;
|
||||
|
||||
const mpris = await Service.import("mpris");
|
||||
|
||||
const Player = (player) => {
|
||||
const img = Widget.Box({
|
||||
visible: player.bind("cover_path"),
|
||||
className: "cover-art",
|
||||
vpack: "start",
|
||||
css: player
|
||||
.bind("cover_path")
|
||||
.as(
|
||||
(p) =>
|
||||
(p ? "min-width: 200px; min-height: 200px;" : "") +
|
||||
`background-image: url('${p}');`,
|
||||
),
|
||||
});
|
||||
|
||||
const title = Widget.Label({
|
||||
className: "title",
|
||||
wrap: true,
|
||||
hpack: "start",
|
||||
label: player.bind("track_title").as((t) => shrinkText(t, 40)),
|
||||
});
|
||||
|
||||
const artist = Widget.Label({
|
||||
className: "artist",
|
||||
wrap: true,
|
||||
hpack: "start",
|
||||
label: player.bind("track_artists").as((a) => shrinkText(a.join(", "), 80)),
|
||||
});
|
||||
|
||||
const positionSlider = Widget.Slider({
|
||||
className: "position",
|
||||
drawValue: false,
|
||||
onChange: ({ value }) => (player.position = value * player.length),
|
||||
visible: player.bind("length").as((l) => l > 0),
|
||||
setup: (self) => {
|
||||
const update = () => {
|
||||
if (self.dragging) return;
|
||||
|
||||
const value = player.position / player.length;
|
||||
self.value = value > 0 ? value : 0;
|
||||
};
|
||||
|
||||
self
|
||||
.hook(player, update)
|
||||
.hook(player, update, "position")
|
||||
.poll(1000, update);
|
||||
},
|
||||
});
|
||||
|
||||
const positionLabel = Widget.Label({
|
||||
ypad: 0,
|
||||
hpack: "start",
|
||||
className: "position-label",
|
||||
setup: (self) => {
|
||||
const update = (_, time) => {
|
||||
self.label = lengthStr(time || player.position);
|
||||
self.visible = player.length > 0;
|
||||
};
|
||||
|
||||
self.hook(player, update, "position");
|
||||
self.poll(1000, update);
|
||||
},
|
||||
});
|
||||
|
||||
const lengthLabel = Widget.Label({
|
||||
ypad: 0,
|
||||
hpack: "end",
|
||||
className: "length-label",
|
||||
visible: player.bind("length").as((l) => l > 0),
|
||||
label: player.bind("length").as(lengthStr),
|
||||
});
|
||||
|
||||
const icon = Widget.Icon({
|
||||
className: "icon",
|
||||
hexpand: true,
|
||||
hpack: "end",
|
||||
vpack: "start",
|
||||
tooltipText: player.identity || "",
|
||||
icon: player.bind("entry").as((entry) => {
|
||||
const name = `${entry}-symbolic`;
|
||||
return Utils.lookUpIcon(name) ? name : FALLBACK_ICON;
|
||||
}),
|
||||
});
|
||||
|
||||
return Widget.Box(
|
||||
{
|
||||
className: "music-player",
|
||||
visible: player.bus_name === findPlayer(mpris.players).bus_name,
|
||||
css: player.bind("cover_path").as(blurBg),
|
||||
},
|
||||
img,
|
||||
Widget.CenterBox({
|
||||
className: "music-details",
|
||||
vertical: true,
|
||||
hexpand: true,
|
||||
spacing: 25,
|
||||
startWidget: Widget.Box(
|
||||
{
|
||||
vertical: true,
|
||||
spacing: 6,
|
||||
},
|
||||
title,
|
||||
Widget.Box({
|
||||
className: "icon-wrapper",
|
||||
spacing: 10,
|
||||
children: [artist, icon],
|
||||
}),
|
||||
),
|
||||
centerWidget: positionSlider,
|
||||
endWidget: Widget.CenterBox({
|
||||
spacing: 6,
|
||||
startWidget: positionLabel,
|
||||
centerWidget: Controls(player),
|
||||
endWidget: lengthLabel,
|
||||
}),
|
||||
}),
|
||||
)
|
||||
.hook(
|
||||
mpris,
|
||||
(self, bus_name) => {
|
||||
self.visible = player.bus_name === bus_name;
|
||||
},
|
||||
"player-changed",
|
||||
)
|
||||
.hook(
|
||||
mpris,
|
||||
(self) => {
|
||||
self.visible = player.bus_name === findPlayer(mpris.players).bus_name;
|
||||
},
|
||||
"player-closed",
|
||||
);
|
||||
};
|
||||
|
||||
const PlayerBox = () =>
|
||||
Widget.Box({
|
||||
className: `${MUSIC_BOX}-unwrapped`,
|
||||
vertical: true,
|
||||
css: "padding: 1px;",
|
||||
children: mpris.bind("players").as((ps) => ps.map(Player)),
|
||||
});
|
||||
|
||||
export default (monitor = 0) => {
|
||||
const name = `${MUSIC_BOX}-${monitor}`;
|
||||
|
||||
return Popup({
|
||||
name,
|
||||
className: MUSIC_BOX,
|
||||
monitor,
|
||||
layout: Widget.Box({
|
||||
children: [
|
||||
Padding(name), // left
|
||||
Widget.Box({
|
||||
hexpand: false,
|
||||
vexpand: false,
|
||||
vertical: true,
|
||||
children: [
|
||||
Revealer({
|
||||
name,
|
||||
child: PlayerBox(),
|
||||
transition: "slide_down",
|
||||
transitionDuration: 400,
|
||||
}),
|
||||
Padding(name), // down
|
||||
],
|
||||
}),
|
||||
Padding(name), // right
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
47
home/natto/ags/windows/music-box/music-controls.js
Normal file
47
home/natto/ags/windows/music-box/music-controls.js
Normal file
@@ -0,0 +1,47 @@
|
||||
const PLAY_ICON = "media-playback-start-symbolic";
|
||||
const PAUSE_ICON = "media-playback-pause-symbolic";
|
||||
const PREV_ICON = "go-previous-symbolic";
|
||||
const NEXT_ICON = "go-next-symbolic";
|
||||
|
||||
export default (player) => {
|
||||
const playPause = Widget.Button({
|
||||
class_name: "play-pause",
|
||||
on_clicked: () => player.playPause(),
|
||||
visible: player.bind("can_play"),
|
||||
cursor: "pointer",
|
||||
child: Widget.Icon({
|
||||
icon: player.bind("play_back_status").transform((s) => {
|
||||
switch (s) {
|
||||
case "Playing":
|
||||
return PAUSE_ICON;
|
||||
case "Paused":
|
||||
case "Stopped":
|
||||
return PLAY_ICON;
|
||||
}
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
const prev = Widget.Button({
|
||||
yalign: 0.5,
|
||||
onClicked: () => player.previous(),
|
||||
visible: player.bind("can_go_prev"),
|
||||
child: Widget.Icon(PREV_ICON),
|
||||
cursor: "pointer",
|
||||
});
|
||||
|
||||
const next = Widget.Button({
|
||||
onClicked: () => player.next(),
|
||||
visible: player.bind("can_go_next"),
|
||||
child: Widget.Icon(NEXT_ICON),
|
||||
cursor: "pointer",
|
||||
});
|
||||
|
||||
return Widget.CenterBox({
|
||||
vertical: true,
|
||||
centerWidget: Widget.Box({
|
||||
className: "music-controls",
|
||||
children: [prev, playPause, next],
|
||||
}),
|
||||
});
|
||||
};
|
Reference in New Issue
Block a user