From da656f0b04fc1481ec1af3d1142d99742ab5b3d3 Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 31 Jul 2024 05:37:59 +0300 Subject: [PATCH] insane ags rework --- src/.config/ags/config.js | 18 ++- src/.config/ags/status.js | 252 ++++++++++++++++++++++++++++++++++ src/.config/ags/style.css | 82 ++++++----- src/.config/ags/tsconfig.json | 18 +++ src/.config/ags/types | 1 + 5 files changed, 332 insertions(+), 39 deletions(-) create mode 100644 src/.config/ags/status.js create mode 100644 src/.config/ags/tsconfig.json create mode 120000 src/.config/ags/types diff --git a/src/.config/ags/config.js b/src/.config/ags/config.js index 30debe8..aa12002 100644 --- a/src/.config/ags/config.js +++ b/src/.config/ags/config.js @@ -1,4 +1,5 @@ import { NotificationPopups } from "./notificationPopups.js"; +import { StatusWidget } from "./status.js"; const hyprland = await Service.import("hyprland"); const notifications = await Service.import("notifications"); @@ -22,7 +23,7 @@ function Workspaces(monitor) { .as((ws) => { const g = ws.filter((z) => z.monitorID == monitor); - g.sort((a,b) => a.id - b.id) + g.sort((a, b) => a.id - b.id); return g.map(({ id }) => Widget.Button({ on_clicked: () => hyprland.messageAsync(`dispatch workspace ${id}`), @@ -55,8 +56,13 @@ function Clock() { function Media() { const label = Utils.watch("", mpris, "player-changed", () => { const player = mpris.players.find((z) => z.entry == "spotify"); + if (player) { - const ms = player.metadata["mpris:length"] / 1000; + let length = player.metadata["mpris:length"]; + + if(!length) length = 0; + + const ms = length / 1000; const minutes = Math.floor(ms / 1000 / 60); const seconds = Math.floor((ms / 1000) % 60); @@ -194,7 +200,13 @@ function Bar(monitor = 0) { App.config({ style: "./style.css", - windows: [Bar(0), Bar(1), NotificationPopups(0), NotificationPopups(1)], + windows: [ + StatusWidget(1), + Bar(0), + Bar(1), + NotificationPopups(0), + NotificationPopups(1), + ], }); export {}; diff --git a/src/.config/ags/status.js b/src/.config/ags/status.js new file mode 100644 index 0000000..c1094c4 --- /dev/null +++ b/src/.config/ags/status.js @@ -0,0 +1,252 @@ +function humanFileSize(size) { + var i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024)); + return ( + +(size / Math.pow(1024, i)).toFixed(2) * 1 + + " " + + ["B", "kB", "MB", "GB", "TB"][i] + ); +} + +const uptimeVar = Variable("", { + poll: [60000, "uptime -p"], +}); +const loadAverage = Variable("", { + poll: [ + 1000, + "uptime", + (e) => { + const a = e.split(" ").at(-1); + if (!a) return "Incorrect uptime command!"; + + return a + .replace("load average: ", "") + .split(" ") + .map((z) => z.replace(",", ".")) + .join(" "); + }, + ], +}); + +const processCount = Variable(0, { + poll: [5000, "ps -Al", (e) => e.split("\n").length], +}); + +const freeKBMemory = Variable(0, { + poll: [1000, "awk '/MemFree/ { printf $2 }' /proc/meminfo", (e) => +e], +}); + +const psStats = Variable([], { + poll: [ + 2000, + "ps wwxo comm,pid,%cpu,%mem --sort -%mem", + (e) => { + return e + .split("\n") + .slice(1, 5) + .map((z) => { + return z + .replace(/^([^ ]*) *([^ ]*) *([^ ]*) *([^ ]*)$/gm, "$1,$2,$3,$4") + .split(","); + }); + }, + ], +}); +export function StatusWidget(monitor = 0) { + const totalKBMem = +Utils.exec( + "awk '/MemTotal/ { printf $2 }' /proc/meminfo" + ); + + const unameR = Utils.exec("uname -r"); + + let df = Utils.exec("df") + .split("\n") + .filter((z) => z.startsWith("/dev/")) + .map((z) => { + const data = z + .replace(/^(\/dev\/[^ ]*) +(\d*) +(\d*) +(\d*).*$/gm, "$1,$2,$3,$4") + .split(","); + return { + file: data[0], + total: +data[1], + used: +data[2], + available: +data[3], + }; + }); + const linuxLabel = Widget.Label({ + label: "Linux " + unameR, + hpack: "start" + }); + + const uptime = Widget.Box({ + children: [ + Widget.Label({ + label: "Uptime: ", + class_name: "gray" + }), + Widget.Label({ + label: uptimeVar.bind(), + }), + ], + }); + + const ramUsage = Widget.Box({ + vertical: true, + children: [ + Widget.Box({ + children: [ + Widget.Label({ + label: "RAM Usage: ", + class_name: "gray" + }), + Widget.Label({ + label: freeKBMemory.bind().as((freeKb) => { + const used = totalKBMem - freeKb; + return ( + humanFileSize(used * 1000) + + "/" + + humanFileSize(totalKBMem * 1000) + + " - " + ); + }), + }), + Widget.Label({ + label: freeKBMemory.bind().as((freeKb) => { + const used = totalKBMem - freeKb; + + return Math.floor((used / totalKBMem) * 100) + "% "; + }), + }), + ], + }), + Widget.LevelBar({ + widthRequest: 100, + className: "levelbar", + value: freeKBMemory.bind().as((freeKb) => { + const used = totalKBMem - freeKb; + + return +used / totalKBMem; + }), + }), + ], + }); + + const cpuUsage = Widget.Box({ + children: [ + Widget.Label({ + label: "Average CPU load: ", + class_name: "gray" + }), + Widget.Label({ + label: loadAverage.bind(), + }), + ], + }); + + const processCountWidget = Widget.Box({ + children: [ + Widget.Label({ + label: "Processes: ", + class_name: "gray" + }), + Widget.Label({ + label: processCount.bind().as((z) => z.toString()), + }), + ], + }); + + const storageWidget = Widget.Box({ + vertical: true, + children: [ + ...df + .map((z) => { + return [ + Widget.Label({ + label: z.file, + hpack: "start", + class_name: "gray" + }), + Widget.Box({ + vertical: true, + children: [ + Widget.Label({ + hpack: "start", + label: + " " + + humanFileSize(z.used * 1000) + + "/" + + humanFileSize(z.total * 1000), + }), + Widget.LevelBar({ + className: "levelbar", + widthRequest: 100, + value: z.used / z.total, + }), + ], + }), + ]; + }) + .flat(), + ], + }); + + const psWidget = Widget.Box({ + vertical: true, + hpack: "center", + children: psStats.bind().as((z) => { + return [ + Widget.Label({ + label: + "Name" + + " ".repeat(15 - 4) + + "PID" + + " ".repeat(7 - 3) + + "%Mem " + + "%Cpu ", + class_name: "gray" + + }), + ...z.map((proc) => { + return Widget.Box({ + children: proc.map((j) => + Widget.Label({ + hexpand: true, + label: j + "", + }) + ), + }); + }), + ]; + }), + }); + return Widget.Window({ + name: `status-${monitor}`, // name has to be unique + class_name: "statusjs", + monitor, + anchor: ["top", "right"], + exclusivity: "exclusive", + layer: "background", // secret sauce + margins: [6, 6, 6, 6], + child: Widget.Box({ + class_name: "status", + children: [ + linuxLabel, + Widget.Label({ + label: "-".repeat(40), + }), + uptime, + ramUsage, + cpuUsage, + processCountWidget, + Widget.Label({ + label: "-".repeat(40), + }), + storageWidget, + Widget.Label({ + label: "-".repeat(40), + }), + psWidget, + ], + vertical: true, + }), + }); +} diff --git a/src/.config/ags/style.css b/src/.config/ags/style.css index 80b3a5a..4fe6a5e 100644 --- a/src/.config/ags/style.css +++ b/src/.config/ags/style.css @@ -1,86 +1,96 @@ window.bar { - background-color: @theme_bg_color; - color: @theme_fg_color; + background-color: @theme_bg_color; + color: @theme_fg_color; } button { - min-width: 0; - padding-top: 0; - padding-bottom: 0; - background-color: transparent; - border: 0; + min-width: 0; + padding-top: 0; + padding-bottom: 0; + background-color: transparent; + border: 0; } button:active { - background-color: @theme_selected_bg_color; + background-color: @theme_selected_bg_color; } button:hover { - border-bottom: 3px solid @theme_fg_color; + border-bottom: 3px solid @theme_fg_color; } label { - font-weight: bold; + font-weight: bold; } window.notification-popups box.notifications { - padding: .5em; + padding: 0.5em; } .body { - color: @theme_unfocused_fg_color; + color: @theme_unfocused_fg_color; } .actions .action-button { - margin: 0 .4em; - margin-top: .8em; + margin: 0 0.4em; + margin-top: 0.8em; } .actions .action-button:first-child { - margin-left: 0; + margin-left: 0; } .actions .action-button:last-child { - margin-right: 0; + margin-right: 0; } .icon { - min-width: 68px; - min-height: 68px; - margin-right: 1em; + min-width: 68px; + min-height: 68px; + margin-right: 1em; } .icon image { - font-size: 58px; - /* to center the icon */ - margin: 5px; - color: @theme_fg_color; + font-size: 58px; + /* to center the icon */ + margin: 5px; + color: @theme_fg_color; } .icon box { - min-width: 68px; - min-height: 68px; - border-radius: 7px; + min-width: 68px; + min-height: 68px; + border-radius: 7px; } .workspaces button.focused { - border-bottom: 3px solid @theme_selected_bg_color; + border-bottom: 3px solid @theme_selected_bg_color; } .notification { - min-width: 350px; - border-radius: 11px; - padding: 1em; - margin: .5em; - border: 1px solid @wm_borders_edge; - background-color: @theme_bg_color; + min-width: 350px; + border-radius: 11px; + padding: 1em; + margin: 0.5em; + border: 1px solid @wm_borders_edge; + background-color: @theme_bg_color; } .client-title { - color: @theme_selected_bg_color; + color: @theme_selected_bg_color; } +.status { + background-color: @theme_bg_color; + padding: 10px; + border-radius: 5px; + color: @theme_fg_color; +} + +.gray { + color: @theme_unfocused_fg_color; +} levelbar block, highlight { - min-height: 10px; -} \ No newline at end of file + min-height: 10px; +} diff --git a/src/.config/ags/tsconfig.json b/src/.config/ags/tsconfig.json new file mode 100644 index 0000000..f03f2d1 --- /dev/null +++ b/src/.config/ags/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "lib": [ + "ES2022" + ], + "allowJs": true, + "checkJs": true, + "strict": true, + "noImplicitAny": false, + "baseUrl": ".", + "typeRoots": [ + "./types" + ], + "skipLibCheck": true + } +} \ No newline at end of file diff --git a/src/.config/ags/types b/src/.config/ags/types new file mode 120000 index 0000000..a8e3f04 --- /dev/null +++ b/src/.config/ags/types @@ -0,0 +1 @@ +/usr/share/com.github.Aylur.ags/types \ No newline at end of file