Start work for the media menu refactor...

This commit is contained in:
Jas Singh
2024-06-30 16:46:09 -07:00
parent 9cf5b0f5ea
commit 6b98da2145
19 changed files with 807 additions and 900 deletions

View File

@@ -1,4 +1,5 @@
const globalMousePos = Variable([]); const globalMousePos = Variable([]);
globalThis["globalMousePos"] = globalMousePos; globalThis["globalMousePos"] = globalMousePos;
export { globalMousePos }; export { globalMousePos };

View File

@@ -10,6 +10,9 @@ export const Padding = (name) =>
}); });
const moveBoxToCursor = (self, minWidth, minHeight, fixed) => { const moveBoxToCursor = (self, minWidth, minHeight, fixed) => {
if (fixed) {
return;
}
globalMousePos.connect("changed", ({ value }) => { globalMousePos.connect("changed", ({ value }) => {
let monWidth = hyprland.monitors[hyprland.active.monitor.id].width; let monWidth = hyprland.monitors[hyprland.active.monitor.id].width;
let monHeight = hyprland.monitors[hyprland.active.monitor.id].height; let monHeight = hyprland.monitors[hyprland.active.monitor.id].height;

View File

@@ -75,6 +75,10 @@ const Layout = (name, child, transition) => ({
hexpand: false, hexpand: false,
vertical: true, vertical: true,
}, },
Padding(name, {
vexpand: false,
className: "top-right-event-box_top",
}),
PopupRevealer(name, child, transition), PopupRevealer(name, child, transition),
Padding(name), Padding(name),
), ),

View File

@@ -8,9 +8,11 @@ const Devices = () => {
vertical: true, vertical: true,
children: [ children: [
label(bluetooth), label(bluetooth),
Widget.Box({ Widget.Scrollable({
class_name: "menu-items-section", class_name: "menu-items-section",
vertical: true, // vertical: true,
hscroll: 'never',
vscroll: 'always',
child: Widget.Box({ child: Widget.Box({
class_name: "menu-content", class_name: "menu-content",
vertical: true, vertical: true,

View File

@@ -1,383 +0,0 @@
const bluetooth = await Service.import("bluetooth");
import DropdownMenu from "../DropdownMenu.js";
export default () => {
const connectedDevices = (btDevices) => {
const noDevices = () => {
return Widget.Box({
hpack: "center",
hexpand: true,
child: Widget.Label({
class_name: "dim",
label: "No devices connected",
}),
});
};
const deviceList = () => {
return Widget.Box({
vertical: true,
children: btDevices.map((dev) =>
Widget.Box({
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
vertical: true,
children: [
Widget.Box({
children: [
Widget.Button({
child: Widget.Icon(`${dev["icon-name"]}-symbolic`),
}),
Widget.Label({
class_name: "menu-button-name bluetooth",
truncate: "end",
wrap: true,
label: dev.alias,
}),
],
}),
Widget.Box({
class_name: "menu-button-name-container status dim",
children: [
Widget.Label({
class_name: "menu-button-name status dim",
label: dev.connected
? "Connected"
: dev.paired
? "Paired"
: "",
}),
],
}),
],
}),
Widget.Box({
hpack: "end",
expand: true,
children: [
Widget.Button({
class_name: "menu-icon-button unpair bluetooth",
child: Widget.Label({
tooltip_text: dev.paired ? "unpair" : "pair",
class_name: "menu-icon-button-label unpair bluetooth",
label: dev.paired ? "" : "",
}),
on_primary_click: () =>
Utils.execAsync([
"bash",
"-c",
`bluetoothctl ${dev.paired ? "unpair" : "pair"} ${dev.address}`,
]).catch((err) =>
console.error(
`bluetoothctl ${dev.paired ? "unpair" : "pair"} ${dev.address}`,
err,
),
),
}),
Widget.Button({
class_name: "menu-icon-button disconnect bluetooth",
child: Widget.Label({
tooltip_text: dev.connected ? "disconnect" : "connect",
class_name:
"menu-icon-button-label disconnect bluetooth",
label: dev.connected ? "󱘖" : "",
}),
on_primary_click: () => dev.setConnection(false),
}),
Widget.Button({
class_name: "menu-icon-button untrust bluetooth",
child: Widget.Label({
tooltip_text: dev.trusted ? "untrust" : "trust",
class_name: "menu-icon-button-label untrust bluetooth",
label: dev.trusted ? "" : "󱖡",
}),
on_primary_click: () =>
Utils.execAsync([
"bash",
"-c",
`bluetoothctl ${dev.trusted ? "untrust" : "trust"} ${dev.address}`,
]).catch((err) =>
console.error(
`bluetoothctl ${dev.trusted ? "untrust" : "trust"} ${dev.address}`,
err,
),
),
}),
Widget.Button({
class_name: "menu-icon-button delete bluetooth",
child: Widget.Label({
tooltip_text: "delete",
class_name: "menu-icon-button-label delete bluetooth",
label: "󰆴",
}),
on_primary_click: () => {
Utils.execAsync([
"bash",
"-c",
`bluetoothctl remove ${dev.address}`,
]).catch((err) =>
console.error("Bluetooth Remove", err),
);
},
}),
],
}),
],
}),
}),
),
});
};
return btDevices.length === 0 ? noDevices() : deviceList();
};
const renderDevices = () => {
return Widget.Box({
class_name: "search-devices-container",
vertical: true,
setup: (self) =>
self.hook(bluetooth, () => {
const availableDevices = bluetooth.devices.filter(
(device) =>
device.name !== null &&
!bluetooth.connected_devices.find(
(dev) => dev.address === device.address,
),
);
if (availableDevices.length === 0) {
return (self.children = [
Widget.Box({
class_name: "empty-bt-devices-container dim",
vertical: true,
children: [
Widget.Label({
hexpand: true,
label: "No devices currently found",
}),
Widget.Label({
hexpand: true,
label: "Press '󰑐' to search",
}),
],
}),
]);
}
return (self.children = bluetooth.devices
.filter(
(device) =>
device.name !== null &&
!bluetooth.connected_devices.find(
(dev) => dev.address === device.address,
),
)
.map((device) => {
return Widget.Button({
hexpand: true,
class_name: `menu-button bluetooth ${device}`,
on_primary_click: () => {
device.setConnection(true);
},
child: Widget.Box({
children: [
Widget.Box({
hpack: "start",
children: [
Widget.Icon({
class_name: "menu-button-icon bluetooth",
icon: `${device["icon-name"]}-symbolic`,
}),
Widget.Label({
hexpand: true,
class_name: "menu-button-name bluetooth",
truncate: "end",
wrap: true,
label: device.alias,
}),
],
}),
Widget.Box({
hpack: "end",
children: device.connecting
? [
Widget.Label({
class_name: "bluetooth-isconnecting",
label: "󰲼",
}),
]
: [],
}),
],
}),
});
}));
}),
});
};
const bluetoothOnModule = () => {
return Widget.Box({
vertical: true,
children: [
Widget.Box({
class_name: "menu-container bluetooth",
children: [
Widget.Box({
vertical: true,
children: [
Widget.Box({
class_name: "menu-label-container bluetooth",
children: [
Widget.Box({
hpack: "start",
child: Widget.Label({
class_name: "menu-label bluetooth",
label: "Devices",
}),
}),
Widget.Box({
hexpand: true,
hpack: "end",
child: Widget.Button({
class_name: "menu-icon-button",
on_primary_click: () => {
Utils.execAsync([
"bash",
"-c",
"bluetoothctl --timeout 120 scan on",
]).catch((err) =>
console.error(
"bluetoothctl --timeout 120 scan on",
err,
),
);
},
child: Widget.Icon("view-refresh-symbolic"),
}),
}),
],
}),
Widget.Box({
child: renderDevices(),
}),
],
}),
],
}),
],
});
};
const bluetoothOffModule = () => {
return Widget.Box({
class_name: "bluetooth-disabled-menu",
vertical: true,
children: [
Widget.Label({
hexpand: true,
vexpand: true,
label: bluetooth
.bind("state")
.as((state) =>
state === "turning-off"
? "Bluetooth is turning off..."
: "Bluetooth is disabled",
),
}),
],
});
};
return DropdownMenu({
name: "bluetoothmenu",
transition: "crossfade",
minWidth: 350,
child: Widget.Box({
class_name: "menu-items",
child: Widget.Box({
vertical: true,
class_name: "menu-items-container",
children: [
Widget.Box({
class_name: "menu-dropdown-label-container",
children: [
Widget.Box({
hexpand: true,
hpack: "start",
child: Widget.Label({
class_name: "menu-dropdown-label bluetooth",
label: "Bluetooth",
}),
}),
Widget.Box({
hexpand: true,
hpack: "end",
children: [
// NOTE: Do we want to add this back to restart bluetooth service if it every hangs?
// Widget.Button({
// class_name: "menu-icon-button restart-bluetooth-service",
// tooltip_text: "Restart Bluetooth Service",
// on_primary_click: () => Utils.execAsync('systemctl restart bluetooth'),
// child: Widget.Label({
// class_name: "menu-icon-button-label",
// label: "󱄌"
// })
// }),
Widget.Switch({
class_name: "menu-switch bluetooth",
active: bluetooth.bind("enabled"),
on_activate: ({ active }) =>
Utils.execAsync([
"bash",
"-c",
`bluetoothctl power ${active ? "on" : "off"}`,
]).catch((err) =>
console.error(
`bluetoothctl power ${active ? "on" : "off"}`,
err,
),
),
}),
],
}),
],
}),
Widget.Box({
vertical: true,
children: bluetooth.bind("enabled").as((isOn) =>
isOn
? [
Widget.Box({
class_name: "menu-label-container",
child: Widget.Label({
class_name: "menu-label bluetooth",
hpack: "start",
label: "My Devices",
}),
}),
Widget.Box({
vertical: true,
class_name: "menu-item-box",
child: bluetooth
.bind("connected_devices")
.as((btConDevs) => connectedDevices(btConDevs)),
}),
]
: [],
),
}),
Widget.Box({
vertical: true,
child: bluetooth
.bind("enabled")
.as((btEnabled) =>
btEnabled ? bluetoothOnModule() : bluetoothOffModule(),
),
}),
],
}),
}),
});
};

View File

@@ -1,4 +1,3 @@
const bluetooth = await Service.import("bluetooth");
import DropdownMenu from "../DropdownMenu.js"; import DropdownMenu from "../DropdownMenu.js";
import { Devices } from "./devices/index.js"; import { Devices } from "./devices/index.js";

View File

@@ -0,0 +1,16 @@
const AlbumCover = (curPlayer) => {
if (
typeof curPlayer.track_cover_url === "string" &&
curPlayer.track_cover_url.length > 0
) {
return Widget.Box({
vexpand: false,
vpack: "center",
class_name: "media-indicator-current-album-cover",
css: `background-image: url("${curPlayer.track_cover_url}")`,
});
}
return Widget.Box();
};
export { AlbumCover };

View File

@@ -0,0 +1,61 @@
const Bar = (curPlayer) => {
return Widget.Box({
class_name: "media-indicator-current-progress-bar",
hexpand: true,
children: [
Widget.Box({
hexpand: true,
child: Widget.Slider({
hexpand: true,
tooltip_text: "yoyo",
class_name: "menu-slider media progress",
draw_value: false,
on_change: ({ value }) =>
(curPlayer.position = value * curPlayer.length),
setup: (self) => {
const update = () => {
const value = curPlayer.position / curPlayer.length;
console.log(`[value]: ${value}`);
console.log(self.value);
if (
typeof curPlayer.position === "number" &&
curPlayer.position > 0
) {
const value = curPlayer.position / curPlayer.length;
self.value = value > 0 ? value : 0;
}
return 0;
};
self.hook(curPlayer, update);
self.hook(curPlayer, update, "position");
self.poll(1000, update);
function updateTooltip() {
const curHour = Math.floor(curPlayer.position / 3600);
const curMin = Math.floor((curPlayer.position % 3600) / 60);
const curSec = Math.floor(curPlayer.position % 60);
if (
typeof curPlayer.position === "number" &&
curPlayer.position >= 0
) {
// WARN: These nested ternaries are absolutely disgusting lol
self.tooltip_text = `${
curHour > 0
? (curHour < 10 ? "0" + curHour : curHour) + ":"
: ""
}${curMin < 10 ? "0" + curMin : curMin}:${curSec < 10 ? "0" + curSec : curSec}`;
} else {
self.tooltip_text = `00:00`;
}
}
self.poll(1000, updateTooltip);
self.hook(curPlayer, updateTooltip);
},
}),
}),
],
});
};
export { Bar };

View File

@@ -0,0 +1,104 @@
import icons from "../../../icons/index.js";
const Controls = (curPlayer) => {
const isLoopActive = (player) => {
return player["loop-status"] !== null &&
["track", "playlist"].includes(player["loop-status"].toLowerCase())
? "active"
: "";
};
const isShuffleActive = (player) => {
return player["shuffle-status"] !== null && player["shuffle-status"]
? "active"
: "";
};
return Widget.Box({
class_name: "media-indicator-current-player-controls",
vertical: true,
children: [
Widget.Box({
class_name: "media-indicator-current-controls",
hpack: "center",
children: [
Widget.Box({
class_name: "media-indicator-control shuffle",
children: [
Widget.Button({
hpack: "center",
tooltip_text:
curPlayer.shuffle_status !== null
? curPlayer.shuffle_status
? "Shuffling"
: "Not Shuffling"
: null,
hasTooltip: true,
on_primary_click: () => curPlayer.shuffle(),
class_name: `media-indicator-control-button shuffle ${isShuffleActive(curPlayer)} ${curPlayer.shuffle_status !== null ? "enabled" : "disabled"}`,
child: Widget.Icon(icons.mpris.shuffle["enabled"]),
}),
],
}),
Widget.Box({
class_name: `media-indicator-control prev ${curPlayer.can_go_prev}`,
children: [
Widget.Button({
hpack: "center",
on_primary_click: () => curPlayer.previous(),
class_name: `media-indicator-control-button prev ${curPlayer.can_go_prev ? "enabled" : "disabled"}`,
child: Widget.Icon(icons.mpris.prev),
}),
],
}),
Widget.Box({
class_name: "media-indicator-control play",
children: [
Widget.Button({
hpack: "center",
on_primary_click: () => curPlayer.playPause(),
class_name: `media-indicator-control-button play ${curPlayer.can_play ? "enabled" : "disabled"}`,
child: Widget.Icon(
icons.mpris[curPlayer.play_back_status.toLowerCase()],
),
}),
],
}),
Widget.Box({
class_name: `media-indicator-control next`,
children: [
Widget.Button({
hpack: "center",
on_primary_click: () => curPlayer.next(),
class_name: `media-indicator-control-button next ${curPlayer.can_go_next ? "enabled" : "disabled"}`,
child: Widget.Icon(icons.mpris.next),
}),
],
}),
Widget.Box({
class_name: "media-indicator-control loop",
children: [
Widget.Button({
hpack: "center",
tooltip_text:
curPlayer.loop_status !== null
? `Looping: ${curPlayer.loop_status}`
: null,
hasTooltip: true,
on_primary_click: () => curPlayer.loop(),
class_name: `media-indicator-control-button loop ${isLoopActive(curPlayer)} ${curPlayer.loop_status !== null ? "enabled" : "disabled"}`,
child: Widget.Icon(
curPlayer.loop_status === null
? icons.mpris.loop["none"]
: icons.mpris.loop[curPlayer.loop_status?.toLowerCase()],
),
}),
],
}),
],
}),
],
});
};
export { Controls };

View File

@@ -0,0 +1,51 @@
const MediaInfo = (curPlayer) => {
return Widget.Box({
class_name: "media-indicator-current-media-info",
hpack: "center",
hexpand: true,
vertical: true,
children: [
Widget.Box({
class_name: "media-indicator-current-song-name",
hpack: "center",
children: [
Widget.Label({
truncate: "end",
max_width_chars: 21,
wrap: true,
class_name: "media-indicator-current-song-name-label",
label: curPlayer["track-title"],
}),
],
}),
Widget.Box({
class_name: "media-indicator-current-song-author",
hpack: "center",
children: [
Widget.Label({
truncate: "end",
wrap: true,
max_width_chars: 25,
class_name: "media-indicator-current-song-author-label",
label: curPlayer["track-artists"].join(", "),
}),
],
}),
Widget.Box({
class_name: "media-indicator-current-song-album",
hpack: "center",
children: [
Widget.Label({
truncate: "end",
wrap: true,
max_width_chars: 25,
class_name: "media-indicator-current-song-album-label",
label: curPlayer["track-album"],
}),
],
}),
],
});
};
export { MediaInfo };

View File

@@ -0,0 +1,343 @@
const media = await Service.import("mpris");
import DropdownMenu from "../DropdownMenu.js";
import icons from "../../icons/index.js";
media.cacheCoverArt = false;
export default () => {
const activePlayer = Variable(media.players[0]);
media.connect("changed", (value) => {
const statusOrder = {
Playing: 1,
Paused: 2,
Stopped: 3,
};
if (value.players.length === 0) {
activePlayer.value = media.players[0];
return;
}
const isPlaying = value.players.find(
(p) => p["play-back-status"] === "Playing",
);
if (isPlaying) {
activePlayer.value = value.players.sort(
(a, b) =>
statusOrder[a["play-back-status"]] -
statusOrder[b["play-back-status"]],
)[0];
}
});
const isLoopActive = (player) => {
return player["loop-status"] !== null &&
["track", "playlist"].includes(player["loop-status"].toLowerCase())
? "active"
: "";
};
const isShuffleActive = (player) => {
return player["shuffle-status"] !== null && player["shuffle-status"]
? "active"
: "";
};
return DropdownMenu({
name: "mediamenu",
transition: "crossfade",
fixed: true,
minWidth: 550,
child: Widget.Box({
class_name: "media-indicator-container",
vertical: true,
hexpand: true,
vexpand: true,
child: Widget.Box({
class_name: "media-indicator-items",
vexpand: true,
hexpand: true,
vertical: true,
children: [
Widget.Box({
class_name: "media-indicator-current-player-info",
vpack: "center",
hexpand: true,
setup: (self) => {
self.hook(activePlayer, () => {
self.hook(media, () => {
const curPlayer = activePlayer.value;
const albumCover = (player) => {
if (
typeof player.track_cover_url === "string" &&
player.track_cover_url.length > 0
) {
return [
Widget.Box({
vexpand: false,
vpack: "center",
class_name: "media-indicator-current-album-cover",
css: `background-image: url("${curPlayer.track_cover_url}")`,
}),
];
}
return [];
};
if (curPlayer && curPlayer.play_back_status !== "Stopped") {
return (self.children = [
...albumCover(curPlayer),
Widget.Box({
class_name: "media-indicator-right-section",
hpack: "center",
hexpand: true,
vertical: true,
children: [
Widget.Box({
class_name: "media-indicator-current-media-info",
hpack: "center",
hexpand: true,
vertical: true,
children: [
Widget.Box({
class_name: "media-indicator-current-song-name",
hpack: "center",
children: [
Widget.Label({
truncate: "end",
max_width_chars: 21,
wrap: true,
class_name:
"media-indicator-current-song-name-label",
label: curPlayer["track-title"],
}),
],
}),
Widget.Box({
class_name:
"media-indicator-current-song-author",
hpack: "center",
children: [
Widget.Label({
truncate: "end",
wrap: true,
max_width_chars: 25,
class_name:
"media-indicator-current-song-author-label",
label:
curPlayer["track-artists"].join(", "),
}),
],
}),
Widget.Box({
class_name:
"media-indicator-current-song-album",
hpack: "center",
children: [
Widget.Label({
truncate: "end",
wrap: true,
max_width_chars: 25,
class_name:
"media-indicator-current-song-album-label",
label: curPlayer["track-album"],
}),
],
}),
],
}),
Widget.Box({
class_name:
"media-indicator-current-player-controls",
vertical: true,
children: [
Widget.Box({
class_name: "media-indicator-current-controls",
hpack: "center",
children: [
Widget.Box({
class_name:
"media-indicator-control shuffle",
children: [
Widget.Button({
hpack: "center",
tooltip_text:
curPlayer.shuffle_status !== null
? curPlayer.shuffle_status
? "Shuffling"
: "Not Shuffling"
: null,
hasTooltip: true,
on_primary_click: () =>
curPlayer.shuffle(),
class_name: `media-indicator-control-button shuffle ${isShuffleActive(curPlayer)} ${curPlayer.shuffle_status !== null ? "enabled" : "disabled"}`,
child: Widget.Icon(
icons.mpris.shuffle["enabled"],
),
}),
],
}),
Widget.Box({
class_name: `media-indicator-control prev ${curPlayer.can_go_prev}`,
children: [
Widget.Button({
hpack: "center",
on_primary_click: () =>
curPlayer.previous(),
class_name: `media-indicator-control-button prev ${curPlayer.can_go_prev ? "enabled" : "disabled"}`,
child: Widget.Icon(icons.mpris.prev),
}),
],
}),
Widget.Box({
class_name: "media-indicator-control play",
children: [
Widget.Button({
hpack: "center",
on_primary_click: () =>
curPlayer.playPause(),
class_name: `media-indicator-control-button play ${curPlayer.can_play ? "enabled" : "disabled"}`,
child: Widget.Icon(
icons.mpris[
curPlayer.play_back_status.toLowerCase()
],
),
}),
],
}),
Widget.Box({
class_name: `media-indicator-control next`,
children: [
Widget.Button({
hpack: "center",
on_primary_click: () =>
curPlayer.next(),
class_name: `media-indicator-control-button next ${curPlayer.can_go_next ? "enabled" : "disabled"}`,
child: Widget.Icon(icons.mpris.next),
}),
],
}),
Widget.Box({
class_name: "media-indicator-control loop",
children: [
Widget.Button({
hpack: "center",
tooltip_text:
curPlayer.loop_status !== null
? `Looping: ${curPlayer.loop_status}`
: null,
hasTooltip: true,
on_primary_click: () =>
curPlayer.loop(),
class_name: `media-indicator-control-button loop ${isLoopActive(curPlayer)} ${curPlayer.loop_status !== null ? "enabled" : "disabled"}`,
child: Widget.Icon(
curPlayer.loop_status === null
? icons.mpris.loop["none"]
: icons.mpris.loop[
curPlayer.loop_status?.toLowerCase()
],
),
}),
],
}),
],
}),
],
}),
Widget.Box({
class_name: "media-indicator-current-progress-bar",
hexpand: true,
children: [
Widget.Box({
hexpand: true,
child: Widget.Slider({
hexpand: true,
tooltip_text: "yoyo",
class_name: "menu-slider media progress",
draw_value: false,
on_change: ({ value }) =>
(curPlayer.position =
value * curPlayer.length),
visible: curPlayer
.bind("length")
.as((l) => l > 0),
setup: (self) => {
const update = () => {
if (
typeof curPlayer.position ===
"number" &&
curPlayer.position > 0
) {
const value =
curPlayer.position / curPlayer.length;
self.value = value > 0 ? value : 0;
}
return 0;
};
self.hook(curPlayer, update);
self.hook(curPlayer, update, "position");
self.poll(1000, update);
function updateTooltip() {
const curHour = Math.floor(
curPlayer.position / 3600,
);
const curMin = Math.floor(
(curPlayer.position % 3600) / 60,
);
const curSec = Math.floor(
curPlayer.position % 60,
);
if (
typeof curPlayer.position ===
"number" &&
curPlayer.position >= 0
) {
// WARN: These nested ternaries are absolutely disgusting lol
self.tooltip_text = `${
curHour > 0
? (curHour < 10
? "0" + curHour
: curHour) + ":"
: ""
}${curMin < 10 ? "0" + curMin : curMin}:${curSec < 10 ? "0" + curSec : curSec}`;
} else {
self.tooltip_text = `00:00`;
}
}
self.poll(1000, updateTooltip);
self.hook(curPlayer, updateTooltip);
},
}),
}),
],
}),
],
}),
]);
}
return (self.children = [
Widget.Box({
class_name: "media-indicator-none",
hpack: "center",
vpack: "center",
expand: true,
child: Widget.Label({
class_name: "media-indicator-none-label dim",
label: "No Media Is Currently Playing",
}),
}),
]);
});
});
},
}),
],
}),
}),
});
};

View File

@@ -1,342 +1,21 @@
const media = await Service.import("mpris"); import PopupWindow from "../PopupWindow.js";
import DropdownMenu from "../DropdownMenu.js"; import { Media } from "./media.js";
import icons from "../../icons/index.js";
media.cacheCoverArt = false;
export default () => { export default () => {
const activePlayer = Variable(media.players[0]); return PopupWindow({
media.connect("changed", (value) => {
const statusOrder = {
Playing: 1,
Paused: 2,
Stopped: 3,
};
if (value.players.length === 0) {
activePlayer.value = media.players[0];
return;
}
const isPlaying = value.players.find(
(p) => p["play-back-status"] === "Playing",
);
if (isPlaying) {
activePlayer.value = value.players.sort(
(a, b) =>
statusOrder[a["play-back-status"]] -
statusOrder[b["play-back-status"]],
)[0];
}
});
const isLoopActive = (player) => {
return player["loop-status"] !== null &&
["track", "playlist"].includes(player["loop-status"].toLowerCase())
? "active"
: "";
};
const isShuffleActive = (player) => {
return player["shuffle-status"] !== null && player["shuffle-status"]
? "active"
: "";
};
return DropdownMenu({
name: "mediamenu", name: "mediamenu",
layout: "top-center",
visible: false,
transition: "crossfade", transition: "crossfade",
fixed: true,
minWidth: 550,
child: Widget.Box({ child: Widget.Box({
class_name: "media-indicator-container", class_name: "menu-items",
vertical: true, hpack: "fill",
hexpand: true, hexpand: true,
vexpand: true,
child: Widget.Box({ child: Widget.Box({
class_name: "media-indicator-items", class_name: "menu-items-container media",
vexpand: true, hpack: "fill",
hexpand: true, hexpand: true,
vertical: true, child: Media(),
children: [
Widget.Box({
class_name: "media-indicator-current-player-info",
vpack: "center",
hexpand: true,
setup: (self) => {
self.hook(activePlayer, () => {
self.hook(media, () => {
const curPlayer = activePlayer.value;
const albumCover = (player) => {
if (
typeof player.track_cover_url === "string" &&
player.track_cover_url.length > 0
) {
return [
Widget.Box({
vexpand: false,
vpack: "center",
class_name: "media-indicator-current-album-cover",
css: `background-image: url("${curPlayer.track_cover_url}")`,
}),
];
}
return [];
};
if (curPlayer && curPlayer.play_back_status !== "Stopped") {
return (self.children = [
...albumCover(curPlayer),
Widget.Box({
class_name: "media-indicator-right-section",
hpack: "center",
hexpand: true,
vertical: true,
children: [
Widget.Box({
class_name: "media-indicator-current-media-info",
hpack: "center",
hexpand: true,
vertical: true,
children: [
Widget.Box({
class_name: "media-indicator-current-song-name",
hpack: "center",
children: [
Widget.Label({
truncate: "end",
max_width_chars: 21,
wrap: true,
class_name:
"media-indicator-current-song-name-label",
label: curPlayer["track-title"],
}),
],
}),
Widget.Box({
class_name:
"media-indicator-current-song-author",
hpack: "center",
children: [
Widget.Label({
truncate: "end",
wrap: true,
max_width_chars: 25,
class_name:
"media-indicator-current-song-author-label",
label:
curPlayer["track-artists"].join(", "),
}),
],
}),
Widget.Box({
class_name:
"media-indicator-current-song-album",
hpack: "center",
children: [
Widget.Label({
truncate: "end",
wrap: true,
max_width_chars: 25,
class_name:
"media-indicator-current-song-album-label",
label: curPlayer["track-album"],
}),
],
}),
],
}),
Widget.Box({
class_name:
"media-indicator-current-player-controls",
vertical: true,
children: [
Widget.Box({
class_name: "media-indicator-current-controls",
hpack: "center",
children: [
Widget.Box({
class_name:
"media-indicator-control shuffle",
children: [
Widget.Button({
hpack: "center",
tooltip_text:
curPlayer.shuffle_status !== null
? curPlayer.shuffle_status
? "Shuffling"
: "Not Shuffling"
: null,
hasTooltip: true,
on_primary_click: () =>
curPlayer.shuffle(),
class_name: `media-indicator-control-button shuffle ${isShuffleActive(curPlayer)} ${curPlayer.shuffle_status !== null ? "enabled" : "disabled"}`,
child: Widget.Icon(
icons.mpris.shuffle["enabled"],
),
}),
],
}),
Widget.Box({
class_name: `media-indicator-control prev ${curPlayer.can_go_prev}`,
children: [
Widget.Button({
hpack: "center",
on_primary_click: () =>
curPlayer.previous(),
class_name: `media-indicator-control-button prev ${curPlayer.can_go_prev ? "enabled" : "disabled"}`,
child: Widget.Icon(icons.mpris.prev),
}),
],
}),
Widget.Box({
class_name: "media-indicator-control play",
children: [
Widget.Button({
hpack: "center",
on_primary_click: () =>
curPlayer.playPause(),
class_name: `media-indicator-control-button play ${curPlayer.can_play ? "enabled" : "disabled"}`,
child: Widget.Icon(
icons.mpris[
curPlayer.play_back_status.toLowerCase()
],
),
}),
],
}),
Widget.Box({
class_name: `media-indicator-control next`,
children: [
Widget.Button({
hpack: "center",
on_primary_click: () =>
curPlayer.next(),
class_name: `media-indicator-control-button next ${curPlayer.can_go_next ? "enabled" : "disabled"}`,
child: Widget.Icon(icons.mpris.next),
}),
],
}),
Widget.Box({
class_name: "media-indicator-control loop",
children: [
Widget.Button({
hpack: "center",
tooltip_text:
curPlayer.loop_status !== null
? `Looping: ${curPlayer.loop_status}`
: null,
hasTooltip: true,
on_primary_click: () =>
curPlayer.loop(),
class_name: `media-indicator-control-button loop ${isLoopActive(curPlayer)} ${curPlayer.loop_status !== null ? "enabled" : "disabled"}`,
child: Widget.Icon(
curPlayer.loop_status === null
? icons.mpris.loop["none"]
: icons.mpris.loop[
curPlayer.loop_status?.toLowerCase()
],
),
}),
],
}),
],
}),
],
}),
Widget.Box({
class_name: "media-indicator-current-progress-bar",
hexpand: true,
children: [
Widget.Box({
hexpand: true,
child: Widget.Slider({
hexpand: true,
tooltip_text: "yoyo",
class_name: "menu-slider media progress",
draw_value: false,
on_change: ({ value }) =>
(curPlayer.position =
value * curPlayer.length),
visible: curPlayer
.bind("length")
.as((l) => l > 0),
setup: (self) => {
const update = () => {
if (
typeof curPlayer.position ===
"number" &&
curPlayer.position > 0
) {
const value =
curPlayer.position / curPlayer.length;
self.value = value > 0 ? value : 0;
}
return 0;
};
self.hook(curPlayer, update);
self.hook(curPlayer, update, "position");
self.poll(1000, update);
function updateTooltip() {
const curHour = Math.floor(
curPlayer.position / 3600,
);
const curMin = Math.floor(
(curPlayer.position % 3600) / 60,
);
const curSec = Math.floor(
curPlayer.position % 60,
);
if (
typeof curPlayer.position ===
"number" &&
curPlayer.position >= 0
) {
// WARN: These nested ternaries are absolutely disgusting lol
self.tooltip_text = `${
curHour > 0
? (curHour < 10
? "0" + curHour
: curHour) + ":"
: ""
}${curMin < 10 ? "0" + curMin : curMin}:${curSec < 10 ? "0" + curSec : curSec}`;
} else {
self.tooltip_text = `00:00`;
}
}
self.poll(1000, updateTooltip);
self.hook(curPlayer, updateTooltip);
},
}),
}),
],
}),
],
}),
]);
}
return (self.children = [
Widget.Box({
class_name: "media-indicator-none",
hpack: "center",
vpack: "center",
expand: true,
child: Widget.Label({
class_name: "media-indicator-none-label dim",
label: "No Media Is Currently Playing",
}),
}),
]);
});
});
},
}),
],
}), }),
}), }),
}); });

View File

@@ -0,0 +1,77 @@
const media = await Service.import("mpris");
import { AlbumCover } from "./components/albumcover.js";
import { MediaInfo } from "./components/mediainfo.js";
import { Controls } from "./components/controls.js";
import { Bar } from "./components/bar.js";
const Media = () => {
return Widget.Box({
class_name: "menu-section-container",
children: [
Widget.Box({
class_name: "menu-items-section",
vertical: false,
child: Widget.Box({
class_name: "menu-content",
// children: [
// Bar(),
// ],
setup: (self) => {
let curPlayer = media.players[0];
self.hook(media, () => {
const statusOrder = {
Playing: 1,
Paused: 2,
Stopped: 3,
};
const isPlaying = media.players.find(
(p) => p["play-back-status"] === "Playing",
);
if (isPlaying) {
curPlayer = media.players.sort(
(a, b) =>
statusOrder[a["play-back-status"]] -
statusOrder[b["play-back-status"]],
)[0];
}
if (curPlayer && curPlayer.play_back_status !== "Stopped") {
return (self.children = [
AlbumCover(curPlayer),
Widget.Box({
class_name: "media-indicator-right-section",
hpack: "center",
hexpand: true,
vertical: true,
children: [
MediaInfo(curPlayer),
Controls(curPlayer),
Bar(curPlayer),
],
}),
]);
}
return (self.children = [
Widget.Box({
class_name: "media-indicator-none",
hpack: "center",
hexpand: true,
vpack: "center",
child: Widget.Label({
class_name: "media-indicator-none-label dim",
label: "No Media Is Currently Playing",
}),
}),
]);
});
},
}),
}),
],
});
};
export { Media };

View File

@@ -2,11 +2,12 @@ const notifs = await Service.import("notifications");
import icons from "../icons/index.js"; import icons from "../icons/index.js";
export default () => { export default () => {
notifs.popupTimeout = 5000; notifs.popupTimeout = 7000;
return Widget.Window({ return Widget.Window({
name: "notifications-window", name: "notifications-window",
class_name: "notifications-window", class_name: "notifications-window",
monitor: 2,
layer: "top", layer: "top",
anchor: ["top", "right"], anchor: ["top", "right"],
exclusivity: "ignore", exclusivity: "ignore",

View File

@@ -12,9 +12,10 @@ html, body {
background-color: $primary_bg; background-color: $primary_bg;
} }
::-webkit-scrollbar { // scrollbar {
display: none; // background-color: red;
} // min-width: 5em;
// }
.code { .code {
background: $light-background; background: $light-background;

View File

@@ -75,7 +75,7 @@
.connection-status { .connection-status {
font-size: 0.9em; font-size: 0.9em;
margin-left: 0.8em; margin-left: 1em;
} }
} }

View File

@@ -1,137 +1,110 @@
@import "../colors"; @import "../colors";
.media-indicator-container { .menu-items-container.media {
min-width: 35rem; min-width: 36.5em;
min-height: 10rem; min-height: 18em;
background: $mantle;
border: 0.13em solid $surface0;
border-radius: 0.4rem;
}
.media-indicator-items { .menu-section-container {
margin: 1rem; margin: 1.3em 0em;
margin-bottom: 1.3rem;
}
.media-indicator-current-album-cover {
border: 0.2em solid $surface0;
background-color: $surface0;
border-radius: 0.25em;
min-width: 8.5em;
min-height: 8.5em;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.media-indicator-current-song-name {
margin-bottom: 0.75rem;
}
.media-indicator-current-song-author {
margin-bottom: 0.5rem;
}
.media-indicator-current-song-name-label {
color: $lavender;
font-size: 1.35em;
}
.media-indicator-current-song-author-label {
color: $teal;
font-size: 1em;
}
.media-indicator-current-song-album-label {
color: $pink;
font-size: 1em;
}
.media-indicator-current-controls {
margin-top: 1.5rem;
margin-bottom: 0.2rem;
}
.media-indicator-control {
margin: 0rem 0.5rem;
}
.media-indicator-control-button {
background: $lavender;
color: $crust;
min-height: 1.8em;
min-width: 2em;
border-radius: 0.2rem;
&.disabled {
background: $surface0;
} }
&.enabled { .media-indicator-items {
margin: 1rem;
margin-bottom: 1.3rem;
}
.media-indicator-current-album-cover {
border-radius: 0.25em;
min-width: 8.5em;
min-height: 8.5em;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.media-indicator-right-section {
margin-left: 2em;
}
.media-indicator-current-song-name {
margin-bottom: 0.75rem;
}
.media-indicator-current-song-author {
margin-bottom: 0.5rem;
}
.media-indicator-current-song-name-label {
color: $lavender;
font-size: 1.35em;
}
.media-indicator-current-song-author-label {
color: $teal;
font-size: 1em;
}
.media-indicator-current-song-album-label {
color: $pink;
font-size: 1em;
}
.media-indicator-current-controls {
margin-top: 1.5rem;
margin-bottom: 0.2rem;
}
.media-indicator-control {
margin: 0rem 0.5rem;
}
.media-indicator-control-button {
background: $lavender; background: $lavender;
color: $crust;
&:hover { min-height: 1.8em;
background: $pink; min-width: 2em;
} border-radius: 0.2rem;
&.active { &.disabled {
background: $pink;
}
}
}
image {
font-size: 1.3em;
}
.menu-slider.media.progress {
margin-top: 1rem;
min-height: 2em;
min-width: 12em;
trough {
background: $base;
border-radius: 0.3rem;
highlight,
progress {
min-height: 1rem;
background: $lavender;
border-radius: 0.3rem;
}
}
slider {
box-shadow: none;
background-color: transparent;
min-height: 1.2rem;
min-width: 1.2rem;
border: 0rem solid transparent;
border-radius: 0.3rem;
}
&:hover {
trough {
background: $surface0; background: $surface0;
} }
slider { &.enabled {
background: $overlay0; background: $lavender;
box-shadow: none;
&:hover {
background: $pink;
}
&.active {
background: $pink;
}
} }
} }
&:disabled { image {
font-size: 1.1em;
highlight,
progress {
}
} }
trough:focus { .menu-slider.media.progress {
margin-top: 1rem;
slider { trough {
background: $surface0;
border-radius: 0.3rem;
highlight,
progress {
min-height: 1rem;
background: $lavender;
}
}
&:hover {
trough {
background: $surface1;
}
} }
} }
} }

View File

@@ -960,7 +960,7 @@ window#powermenu .powermenu.box {
} }
.menu-items-container.bluetooth .bluetooth-element-item .connection-status { .menu-items-container.bluetooth .bluetooth-element-item .connection-status {
font-size: 0.9em; font-size: 0.9em;
margin-left: 0.8em; margin-left: 1em;
} }
.menu-items-container.bluetooth spinner { .menu-items-container.bluetooth spinner {
min-height: 1.3em; min-height: 1.3em;
@@ -971,22 +971,18 @@ window#powermenu .powermenu.box {
margin: 0em 1em; margin: 0em 1em;
} }
.media-indicator-container { .menu-items-container.media {
min-width: 35rem; min-width: 36.5em;
min-height: 10rem; min-height: 18em;
background: #181825;
border: 0.13em solid #313244;
border-radius: 0.4rem;
} }
.menu-items-container.media .menu-section-container {
.media-indicator-items { margin: 1.3em 0em;
}
.menu-items-container.media .media-indicator-items {
margin: 1rem; margin: 1rem;
margin-bottom: 1.3rem; margin-bottom: 1.3rem;
} }
.menu-items-container.media .media-indicator-current-album-cover {
.media-indicator-current-album-cover {
border: 0.2em solid #313244;
background-color: #313244;
border-radius: 0.25em; border-radius: 0.25em;
min-width: 8.5em; min-width: 8.5em;
min-height: 8.5em; min-height: 8.5em;
@@ -994,93 +990,72 @@ window#powermenu .powermenu.box {
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
} }
.menu-items-container.media .media-indicator-right-section {
.media-indicator-current-song-name { margin-left: 2em;
}
.menu-items-container.media .media-indicator-current-song-name {
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
} }
.menu-items-container.media .media-indicator-current-song-author {
.media-indicator-current-song-author {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.menu-items-container.media .media-indicator-current-song-name-label {
.media-indicator-current-song-name-label {
color: #b4befe; color: #b4befe;
font-size: 1.35em; font-size: 1.35em;
} }
.menu-items-container.media .media-indicator-current-song-author-label {
.media-indicator-current-song-author-label {
color: #94e2d5; color: #94e2d5;
font-size: 1em; font-size: 1em;
} }
.menu-items-container.media .media-indicator-current-song-album-label {
.media-indicator-current-song-album-label {
color: #f5c2e7; color: #f5c2e7;
font-size: 1em; font-size: 1em;
} }
.menu-items-container.media .media-indicator-current-controls {
.media-indicator-current-controls {
margin-top: 1.5rem; margin-top: 1.5rem;
margin-bottom: 0.2rem; margin-bottom: 0.2rem;
} }
.menu-items-container.media .media-indicator-control {
.media-indicator-control {
margin: 0rem 0.5rem; margin: 0rem 0.5rem;
} }
.menu-items-container.media .media-indicator-control-button {
.media-indicator-control-button {
background: #b4befe; background: #b4befe;
color: #11111b; color: #11111b;
min-height: 1.8em; min-height: 1.8em;
min-width: 2em; min-width: 2em;
border-radius: 0.2rem; border-radius: 0.2rem;
} }
.media-indicator-control-button.disabled { .menu-items-container.media .media-indicator-control-button.disabled {
background: #313244; background: #313244;
} }
.media-indicator-control-button.enabled { .menu-items-container.media .media-indicator-control-button.enabled {
background: #b4befe; background: #b4befe;
} }
.media-indicator-control-button.enabled:hover { .menu-items-container.media .media-indicator-control-button.enabled:hover {
background: #f5c2e7; background: #f5c2e7;
} }
.media-indicator-control-button.enabled.active { .menu-items-container.media .media-indicator-control-button.enabled.active {
background: #f5c2e7; background: #f5c2e7;
} }
.menu-items-container.media image {
image { font-size: 1.1em;
font-size: 1.3em;
} }
.menu-items-container.media .menu-slider.media.progress {
.menu-slider.media.progress {
margin-top: 1rem; margin-top: 1rem;
min-height: 2em;
min-width: 12em;
} }
.menu-slider.media.progress trough { .menu-items-container.media .menu-slider.media.progress trough {
background: #1e1e2e; background: #313244;
border-radius: 0.3rem; border-radius: 0.3rem;
} }
.menu-slider.media.progress trough highlight, .menu-items-container.media .menu-slider.media.progress trough highlight,
.menu-slider.media.progress trough progress { .menu-items-container.media .menu-slider.media.progress trough progress {
min-height: 1rem; min-height: 1rem;
background: #b4befe; background: #b4befe;
border-radius: 0.3rem;
} }
.menu-slider.media.progress slider { .menu-items-container.media .menu-slider.media.progress:hover trough {
box-shadow: none; background: #45475a;
background-color: transparent;
min-height: 1.2rem;
min-width: 1.2rem;
border: 0rem solid transparent;
border-radius: 0.3rem;
}
.menu-slider.media.progress:hover trough {
background: #313244;
}
.menu-slider.media.progress:hover slider {
background: #6c7086;
box-shadow: none;
} }
.notification-card-container.menu { .notification-card-container.menu {
margin: 0em; margin: 0em;
min-width: 28.6em; min-width: 28.6em;

File diff suppressed because one or more lines are too long