mirror of
https://github.com/Theaninova/TheaninovOS.git
synced 2026-02-20 15:32:05 +00:00
feat: update ags
This commit is contained in:
16
home/desktops/hyprland/ags/js/misc/Avatar.js
Normal file
16
home/desktops/hyprland/ags/js/misc/Avatar.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import options from "../options.js";
|
||||
|
||||
/** @param {import('types/widgets/box').BoxProps=} props */
|
||||
export default (props) =>
|
||||
Widget.Box({ ...props, class_name: "avatar" })
|
||||
.hook(options.desktop.avatar, (box) =>
|
||||
box.setCss(`
|
||||
background-image: url('${options.desktop.avatar.value}');
|
||||
background-size: cover;
|
||||
`),
|
||||
)
|
||||
.on("size-allocate", (box) => {
|
||||
const h = box.get_allocated_height();
|
||||
box.set_size_request(Math.ceil(h * 1.1), -1);
|
||||
});
|
||||
18
home/desktops/hyprland/ags/js/misc/BatteryIcon.js
Normal file
18
home/desktops/hyprland/ags/js/misc/BatteryIcon.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import Battery from "resource:///com/github/Aylur/ags/service/battery.js";
|
||||
|
||||
export default () =>
|
||||
Widget.Icon({
|
||||
class_name: "battery",
|
||||
binds: [["icon", Battery, "icon-name"]],
|
||||
connections: [
|
||||
[
|
||||
Battery,
|
||||
(icon) => {
|
||||
icon.toggleClassName("charging", Battery.charging);
|
||||
icon.toggleClassName("charged", Battery.charged);
|
||||
icon.toggleClassName("low", Battery.percent < 30);
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
26
home/desktops/hyprland/ags/js/misc/Clock.js
Normal file
26
home/desktops/hyprland/ags/js/misc/Clock.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import GLib from "gi://GLib";
|
||||
|
||||
/**
|
||||
* @param {import('types/widgets/label').Props & {
|
||||
* format?: string,
|
||||
* interval?: number,
|
||||
* }} o
|
||||
*/
|
||||
export default ({
|
||||
format = "%H:%M:%S %B %e. %A",
|
||||
interval = 1000,
|
||||
...rest
|
||||
} = {}) =>
|
||||
Widget.Label({
|
||||
class_name: "clock",
|
||||
...rest,
|
||||
connections: [
|
||||
[
|
||||
interval,
|
||||
(label) =>
|
||||
(label.label =
|
||||
GLib.DateTime.new_now_local().format(format) || "wrong format"),
|
||||
],
|
||||
],
|
||||
});
|
||||
49
home/desktops/hyprland/ags/js/misc/FontIcon.js
Normal file
49
home/desktops/hyprland/ags/js/misc/FontIcon.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import Gtk from "gi://Gtk";
|
||||
import { createCtor } from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import AgsLabel from "resource:///com/github/Aylur/ags/widgets/label.js";
|
||||
import GObject from "gi://GObject";
|
||||
|
||||
export default createCtor(
|
||||
class FontIcon extends AgsLabel {
|
||||
static {
|
||||
GObject.registerClass(this);
|
||||
}
|
||||
|
||||
/** @param {string | import('types/widgets/label').Props & { icon?: string }} params */
|
||||
constructor(params = "") {
|
||||
// @ts-expect-error
|
||||
const { icon = "", ...rest } = params;
|
||||
|
||||
super(typeof params === "string" ? {} : rest);
|
||||
this.toggleClassName("font-icon");
|
||||
|
||||
if (typeof params === "object") this.icon = icon;
|
||||
|
||||
if (typeof params === "string") this.icon = params;
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return this.label;
|
||||
}
|
||||
set icon(icon) {
|
||||
this.label = icon;
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this.get_style_context().get_property(
|
||||
"font-size",
|
||||
Gtk.StateFlags.NORMAL,
|
||||
);
|
||||
}
|
||||
|
||||
/** @returns {[number, number]} */
|
||||
vfunc_get_preferred_height() {
|
||||
return [this.size, this.size];
|
||||
}
|
||||
|
||||
/** @returns {[number, number]} */
|
||||
vfunc_get_preferred_width() {
|
||||
return [this.size, this.size];
|
||||
}
|
||||
},
|
||||
);
|
||||
64
home/desktops/hyprland/ags/js/misc/HoverRevealer.js
Normal file
64
home/desktops/hyprland/ags/js/misc/HoverRevealer.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import * as Utils from "resource:///com/github/Aylur/ags/utils.js";
|
||||
|
||||
/**
|
||||
* @typedef {import('types/widgets/eventbox').EventBoxProps & {
|
||||
* indicator?: import('types/widgets/box').BoxProps['child']
|
||||
* direction?: 'left' | 'right' | 'down' | 'up'
|
||||
* duration?: number
|
||||
* eventboxConnections?: import('types/widgets/box').BoxProps['connections']
|
||||
* connections?: import('types/widgets/revealer').RevealerProps['connections']
|
||||
* }} HoverRevealProps
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {HoverRevealProps} props
|
||||
*/
|
||||
export default ({
|
||||
indicator,
|
||||
child,
|
||||
direction = "left",
|
||||
duration = 300,
|
||||
connections = [],
|
||||
eventboxConnections = [],
|
||||
binds = [],
|
||||
...rest
|
||||
}) => {
|
||||
let open = false;
|
||||
const vertical = direction === "down" || direction === "up";
|
||||
const posStart = direction === "down" || direction === "right";
|
||||
const posEnd = direction === "up" || direction === "left";
|
||||
|
||||
const revealer = Widget.Revealer({
|
||||
transition: `slide_${direction}`,
|
||||
connections,
|
||||
binds,
|
||||
transition_duration: duration,
|
||||
child,
|
||||
});
|
||||
|
||||
const eventbox = Widget.EventBox({
|
||||
...rest,
|
||||
connections: eventboxConnections,
|
||||
on_hover: () => {
|
||||
if (open) return;
|
||||
|
||||
revealer.reveal_child = true;
|
||||
Utils.timeout(duration, () => (open = true));
|
||||
},
|
||||
on_hover_lost: () => {
|
||||
if (!open) return;
|
||||
|
||||
revealer.reveal_child = false;
|
||||
open = false;
|
||||
},
|
||||
child: Widget.Box({
|
||||
vertical,
|
||||
children: [posStart && indicator, revealer, posEnd && indicator],
|
||||
}),
|
||||
});
|
||||
|
||||
return Widget.Box({
|
||||
children: [eventbox],
|
||||
});
|
||||
};
|
||||
63
home/desktops/hyprland/ags/js/misc/IconBrowser.js
Normal file
63
home/desktops/hyprland/ags/js/misc/IconBrowser.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import RegularWindow from "./RegularWindow.js";
|
||||
import Gtk from "gi://Gtk";
|
||||
|
||||
export default () => {
|
||||
const selected = Widget.Label({
|
||||
css: "font-size: 1.2em;",
|
||||
});
|
||||
|
||||
const flowbox = Widget.FlowBox({
|
||||
min_children_per_line: 10,
|
||||
setup: (self) => {
|
||||
self.connect("child-activated", (_, child) => {
|
||||
selected.label = child.get_child().iconName;
|
||||
});
|
||||
|
||||
Gtk.IconTheme.get_default()
|
||||
.list_icons(null)
|
||||
.sort()
|
||||
.map((icon) => {
|
||||
!icon.endsWith(".symbolic") &&
|
||||
self.insert(
|
||||
Widget.Icon({
|
||||
icon,
|
||||
size: 38,
|
||||
}),
|
||||
-1,
|
||||
);
|
||||
});
|
||||
|
||||
self.show_all();
|
||||
},
|
||||
});
|
||||
|
||||
const entry = Widget.Entry({
|
||||
on_change: ({ text }) =>
|
||||
flowbox.get_children().forEach((child) => {
|
||||
child.visible = child.get_child().iconName.includes(text);
|
||||
}),
|
||||
});
|
||||
|
||||
return RegularWindow({
|
||||
name: "icons",
|
||||
visible: true,
|
||||
child: Widget.Box({
|
||||
css: "padding: 30px;",
|
||||
spacing: 20,
|
||||
vertical: true,
|
||||
children: [
|
||||
entry,
|
||||
Widget.Scrollable({
|
||||
hscroll: "never",
|
||||
vscroll: "always",
|
||||
hexpand: true,
|
||||
vexpand: true,
|
||||
css: "min-width: 500px;" + "min-height: 500px;",
|
||||
child: flowbox,
|
||||
}),
|
||||
selected,
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
132
home/desktops/hyprland/ags/js/misc/Notification.js
Normal file
132
home/desktops/hyprland/ags/js/misc/Notification.js
Normal file
@@ -0,0 +1,132 @@
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import * as Utils from "resource:///com/github/Aylur/ags/utils.js";
|
||||
import GLib from "gi://GLib";
|
||||
|
||||
/** @param {import('types/service/notifications').Notification} n */
|
||||
const NotificationIcon = ({ app_entry, app_icon, image }) => {
|
||||
if (image) {
|
||||
return Widget.Box({
|
||||
vpack: "start",
|
||||
hexpand: false,
|
||||
class_name: "icon img",
|
||||
css: `
|
||||
background-image: url("${image}");
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
min-width: 78px;
|
||||
min-height: 78px;
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
let icon = "dialog-information-symbolic";
|
||||
if (Utils.lookUpIcon(app_icon)) icon = app_icon;
|
||||
|
||||
if (Utils.lookUpIcon(app_entry || "")) icon = app_entry || "";
|
||||
|
||||
return Widget.Box({
|
||||
vpack: "start",
|
||||
hexpand: false,
|
||||
class_name: "icon",
|
||||
css: `
|
||||
min-width: 78px;
|
||||
min-height: 78px;
|
||||
`,
|
||||
child: Widget.Icon({
|
||||
icon,
|
||||
size: 58,
|
||||
hpack: "center",
|
||||
hexpand: true,
|
||||
vpack: "center",
|
||||
vexpand: true,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
/** @param {import('types/service/notifications').Notification} notification */
|
||||
export default (notification) => {
|
||||
const content = Widget.Box({
|
||||
class_name: "content",
|
||||
children: [
|
||||
NotificationIcon(notification),
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "title",
|
||||
xalign: 0,
|
||||
justification: "left",
|
||||
hexpand: true,
|
||||
max_width_chars: 24,
|
||||
truncate: "end",
|
||||
wrap: true,
|
||||
label: notification.summary,
|
||||
use_markup: true,
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "time",
|
||||
vpack: "start",
|
||||
label: GLib.DateTime.new_from_unix_local(
|
||||
notification.time,
|
||||
).format("%H:%M"),
|
||||
}),
|
||||
Widget.Button({
|
||||
class_name: "close-button",
|
||||
vpack: "start",
|
||||
child: Widget.Icon("window-close-symbolic"),
|
||||
on_clicked: () => notification.close(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "description",
|
||||
hexpand: true,
|
||||
use_markup: true,
|
||||
xalign: 0,
|
||||
justification: "left",
|
||||
label: notification.body,
|
||||
wrap: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const actionsbox = Widget.Revealer({
|
||||
transition: "slide_down",
|
||||
child: Widget.EventBox({
|
||||
child: Widget.Box({
|
||||
class_name: "actions horizontal",
|
||||
children: notification.actions.map((action) =>
|
||||
Widget.Button({
|
||||
class_name: "action-button",
|
||||
on_clicked: () => notification.invoke(action.id),
|
||||
hexpand: true,
|
||||
child: Widget.Label(action.label),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
return Widget.EventBox({
|
||||
class_name: `notification ${notification.urgency}`,
|
||||
vexpand: false,
|
||||
on_primary_click: () => notification.dismiss(),
|
||||
on_hover() {
|
||||
actionsbox.reveal_child = true;
|
||||
},
|
||||
on_hover_lost() {
|
||||
actionsbox.reveal_child = true;
|
||||
notification.dismiss();
|
||||
},
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
children: [content, notification.actions.length > 0 && actionsbox],
|
||||
}),
|
||||
});
|
||||
};
|
||||
65
home/desktops/hyprland/ags/js/misc/PopupWindow.js
Normal file
65
home/desktops/hyprland/ags/js/misc/PopupWindow.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import AgsWindow from "resource:///com/github/Aylur/ags/widgets/window.js";
|
||||
import App from "resource:///com/github/Aylur/ags/app.js";
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import options from "../options.js";
|
||||
import GObject from "gi://GObject";
|
||||
|
||||
class PopupWindow extends AgsWindow {
|
||||
static {
|
||||
GObject.registerClass(this);
|
||||
}
|
||||
|
||||
/** @param {import('types/widgets/window').WindowProps & {
|
||||
* name: string
|
||||
* child: import('types/widgets/box').default
|
||||
* transition?: import('types/widgets/revealer').RevealerProps['transition']
|
||||
* }} o
|
||||
*/
|
||||
constructor({ name, child, transition = "none", visible = false, ...rest }) {
|
||||
super({
|
||||
...rest,
|
||||
name,
|
||||
popup: true,
|
||||
focusable: true,
|
||||
class_names: ["popup-window", name],
|
||||
});
|
||||
|
||||
child.toggleClassName("window-content");
|
||||
this.revealer = Widget.Revealer({
|
||||
transition,
|
||||
child,
|
||||
transitionDuration: options.transition.value,
|
||||
connections: [
|
||||
[
|
||||
App,
|
||||
(_, wname, visible) => {
|
||||
if (wname === name) this.revealer.reveal_child = visible;
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
this.child = Widget.Box({
|
||||
css: "padding: 1px;",
|
||||
child: this.revealer,
|
||||
});
|
||||
|
||||
this.show_all();
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
set transition(dir) {
|
||||
this.revealer.transition = dir;
|
||||
}
|
||||
get transition() {
|
||||
return this.revealer.transition;
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {import('types/widgets/window').WindowProps & {
|
||||
* name: string
|
||||
* child: import('types/widgets/box').default
|
||||
* transition?: import('types/widgets/revealer').RevealerProps['transition']
|
||||
* }} config
|
||||
*/
|
||||
export default (config) => new PopupWindow(config);
|
||||
57
home/desktops/hyprland/ags/js/misc/Progress.js
Normal file
57
home/desktops/hyprland/ags/js/misc/Progress.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import * as Utils from "resource:///com/github/Aylur/ags/utils.js";
|
||||
|
||||
export default ({
|
||||
height = 18,
|
||||
width = 180,
|
||||
vertical = false,
|
||||
child,
|
||||
...props
|
||||
}) => {
|
||||
const fill = Widget.Box({
|
||||
class_name: "fill",
|
||||
hexpand: vertical,
|
||||
vexpand: !vertical,
|
||||
hpack: vertical ? "fill" : "start",
|
||||
vpack: vertical ? "end" : "fill",
|
||||
children: [child],
|
||||
});
|
||||
|
||||
let fill_size = 0;
|
||||
|
||||
return Widget.Box({
|
||||
...props,
|
||||
class_name: "progress",
|
||||
css: `
|
||||
min-width: ${width}px;
|
||||
min-height: ${height}px;
|
||||
`,
|
||||
children: [fill],
|
||||
setup: (progress) =>
|
||||
(progress.setValue = (value) => {
|
||||
if (value < 0) return;
|
||||
|
||||
const axis = vertical ? "height" : "width";
|
||||
const axisv = vertical ? height : width;
|
||||
const min = vertical ? width : height;
|
||||
const preferred = (axisv - min) * value + min;
|
||||
|
||||
if (!fill_size) {
|
||||
fill_size = preferred;
|
||||
fill.setCss(`min-${axis}: ${preferred}px;`);
|
||||
return;
|
||||
}
|
||||
|
||||
const frames = 10;
|
||||
const goal = preferred - fill_size;
|
||||
const step = goal / frames;
|
||||
|
||||
for (let i = 0; i < frames; ++i) {
|
||||
Utils.timeout(5 * i, () => {
|
||||
fill_size += step;
|
||||
fill.setCss(`min-${axis}: ${fill_size}px`);
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
};
|
||||
19
home/desktops/hyprland/ags/js/misc/RegularWindow.js
Normal file
19
home/desktops/hyprland/ags/js/misc/RegularWindow.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import Widget from "resource:///com/github/Aylur/ags/widget.js";
|
||||
import Gtk from "gi://Gtk";
|
||||
import AgsWidget from "resource:///com/github/Aylur/ags/widgets/widget.js";
|
||||
|
||||
class RegularWindow extends AgsWidget(Gtk.Window, "RegularWindow") {
|
||||
static {
|
||||
AgsWidget.register(this);
|
||||
}
|
||||
/**
|
||||
* @param {import('types/widgets/widget').BaseProps<
|
||||
* RegularWindow, Gtk.Window.ConstructorProperties
|
||||
* >} params */
|
||||
constructor(params) {
|
||||
// @ts-expect-error
|
||||
super(params);
|
||||
}
|
||||
}
|
||||
|
||||
export default Widget.createCtor(RegularWindow);
|
||||
321
home/desktops/hyprland/ags/js/misc/mpris.js
Normal file
321
home/desktops/hyprland/ags/js/misc/mpris.js
Normal file
@@ -0,0 +1,321 @@
|
||||
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",
|
||||
binds: [
|
||||
[
|
||||
"css",
|
||||
player,
|
||||
"cover-path",
|
||||
(path) => `background-image: url("${path}")`,
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
/**
|
||||
* @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",
|
||||
connections: [
|
||||
[
|
||||
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",
|
||||
binds: [["label", player, "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",
|
||||
binds: [["label", player, "track-artists", (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 || "",
|
||||
connections: [
|
||||
[
|
||||
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;
|
||||
},
|
||||
properties: [
|
||||
[
|
||||
"update",
|
||||
(slider) => {
|
||||
if (slider.dragging) return;
|
||||
|
||||
slider.visible = player.length > 0;
|
||||
if (player.length > 0) slider.value = player.position / player.length;
|
||||
},
|
||||
],
|
||||
],
|
||||
connections: [
|
||||
[player, (s) => s._update(s)],
|
||||
[player, (s) => s._update(s), "position"],
|
||||
[1000, (s) => s._update(s)],
|
||||
],
|
||||
});
|
||||
|
||||
/** @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({
|
||||
properties: [
|
||||
[
|
||||
"update",
|
||||
(label, time) => {
|
||||
player.length > 0
|
||||
? (label.label = lengthStr(time || player.position))
|
||||
: (label.visible = !!player);
|
||||
},
|
||||
],
|
||||
],
|
||||
connections: [
|
||||
[player, (l, time) => l._update(l, time), "position"],
|
||||
[1000, (l) => l._update(l)],
|
||||
],
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const LengthLabel = (player) =>
|
||||
Widget.Label({
|
||||
connections: [
|
||||
[
|
||||
player,
|
||||
(label) => {
|
||||
player.length > 0
|
||||
? (label.label = lengthStr(player.length))
|
||||
: (label.visible = !!player);
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const Slash = (player) =>
|
||||
Widget.Label({
|
||||
label: "/",
|
||||
connections: [
|
||||
[
|
||||
player,
|
||||
(label) => {
|
||||
label.visible = player.length > 0;
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {Object} o
|
||||
* @param {import('types/service/mpris').MprisPlayer} o.player
|
||||
* @param {import('types/widgets/stack').StackProps['items']} o.items
|
||||
* @param {'shuffle' | 'loop' | 'playPause' | 'previous' | 'next'} o.onClick
|
||||
* @param {string} o.prop
|
||||
* @param {string} o.canProp
|
||||
* @param {any} o.cantValue
|
||||
*/
|
||||
const PlayerButton = ({ player, items, onClick, prop, canProp, cantValue }) =>
|
||||
Widget.Button({
|
||||
child: Widget.Stack({
|
||||
items,
|
||||
binds: [["shown", player, prop, (p) => `${p}`]],
|
||||
}),
|
||||
on_clicked: player[onClick].bind(player),
|
||||
binds: [["visible", player, canProp, (c) => c !== cantValue]],
|
||||
});
|
||||
|
||||
/** @param {import('types/service/mpris').MprisPlayer} player */
|
||||
export const ShuffleButton = (player) =>
|
||||
PlayerButton({
|
||||
player,
|
||||
items: [
|
||||
[
|
||||
"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,
|
||||
items: [
|
||||
[
|
||||
"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,
|
||||
items: [
|
||||
[
|
||||
"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,
|
||||
items: [
|
||||
[
|
||||
"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,
|
||||
items: [
|
||||
[
|
||||
"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