From dece2776fe0c747f69550bada255f352b56e1545 Mon Sep 17 00:00:00 2001 From: retrozinndev Date: Thu, 26 Jun 2025 15:12:24 -0300 Subject: [PATCH] :sparkles: feat(config): implement configurations --- ags/scripts/nightlight.ts | 10 +++++- ags/scripts/notifications.ts | 12 +++---- ags/widget/bar/Clock.ts | 6 ++-- ags/widget/bar/Workspaces.ts | 49 +++++++++++++++++----------- ags/window/LogoutMenu.ts | 63 +++++++++++++++++++----------------- 5 files changed, 81 insertions(+), 59 deletions(-) diff --git a/ags/scripts/nightlight.ts b/ags/scripts/nightlight.ts index b60f6d1..63e7e67 100644 --- a/ags/scripts/nightlight.ts +++ b/ags/scripts/nightlight.ts @@ -1,4 +1,4 @@ -import { AstalIO, execAsync, GObject, interval, property, register } from "astal"; +import { AstalIO, exec, execAsync, GLib, GObject, interval, property, register } from "astal"; export { NightLight }; @@ -134,4 +134,12 @@ class NightLight extends GObject.Object { this.#prevTemperature = null; this.#prevGamma = null; } + + public saveData(): void { + exec(`sh ${GLib.get_user_config_dir()}/hypr/scripts/save-hyprsunset.sh`); + } + + public loadData(): void { + exec(`sh ${GLib.get_user_config_dir()}/hypr/scripts/load-hyprsunset.sh`); + } } diff --git a/ags/scripts/notifications.ts b/ags/scripts/notifications.ts index d3bc8f7..2996f38 100644 --- a/ags/scripts/notifications.ts +++ b/ags/scripts/notifications.ts @@ -1,5 +1,6 @@ import { AstalIO, execAsync, Gio, GObject, property, register, signal, timeout } from "astal"; import AstalNotifd from "gi://AstalNotifd"; +import { Config } from "./config"; export interface HistoryNotification { @@ -23,11 +24,6 @@ class Notifications extends GObject.Object { #connections: Array = []; #historyLimit: number = 10; - public static NOTIFICATION_TIMEOUT_CRITICAL: number = 0; - public static NOTIFICATION_TIMEOUT_NORMAL: number = 6000; - public static NOTIFICATION_TIMEOUT_LOW: number = 4000; - - @property() public get notifications() { return this.#notifications }; @@ -65,9 +61,9 @@ class Notifications extends GObject.Object { this.#connections.push( AstalNotifd.get_default().connect("notified", (notifd, id) => { const notification = notifd.get_notification(id); - const notifTimeout = Notifications[`NOTIFICATION_TIMEOUT_${ - this.getUrgencyString(notification.urgency).toUpperCase() - }` as keyof typeof Notifications] as number; + const notifTimeout = Config.getDefault().getProperty( + `notifications.timeout_${this.getUrgencyString(notification.urgency).toLowerCase()}`, + "number") as number; if(this.getNotifd().dontDisturb) { this.addHistory(notification, () => notification.dismiss()); diff --git a/ags/widget/bar/Clock.ts b/ags/widget/bar/Clock.ts index e9c7585..e137dd7 100644 --- a/ags/widget/bar/Clock.ts +++ b/ags/widget/bar/Clock.ts @@ -2,6 +2,7 @@ import { Gtk, Widget } from "astal/gtk3"; import { getDateTime } from "../../scripts/time"; import { bind, GLib } from "astal"; import { Windows } from "../../windows"; +import { Config } from "../../scripts/config"; export function Clock(): Gtk.Widget { return new Widget.Box({ @@ -9,9 +10,8 @@ export function Clock(): Gtk.Widget { Object.hasOwn(openWins, "center-window") ? "open clock" : "clock"), child: new Widget.Button({ onClick: () => Windows.toggle("center-window"), - label: getDateTime().as((dateTime: GLib.DateTime) => { - return dateTime.format("%A %d, %H:%M") - }) + label: getDateTime().as((dateTime: GLib.DateTime) => + dateTime.format(Config.getDefault().getProperty("clock.date_format", "string") as string)) } as Widget.ButtonProps) } as Widget.BoxProps); } diff --git a/ags/widget/bar/Workspaces.ts b/ags/widget/bar/Workspaces.ts index c40be2e..d7da499 100644 --- a/ags/widget/bar/Workspaces.ts +++ b/ags/widget/bar/Workspaces.ts @@ -1,7 +1,9 @@ import { bind, Variable } from "astal"; import { Gtk, Widget } from "astal/gtk3"; import AstalHyprland from "gi://AstalHyprland"; -import { getSymbolicIcon } from "../../scripts/apps"; +import { getAppIcon, getSymbolicIcon } from "../../scripts/apps"; +import { Windows } from "../../windows"; +import { Config } from "../../scripts/config"; let showWsNum: (Variable|undefined); export const showWorkspaceNumber = (show: boolean) => @@ -19,35 +21,45 @@ export function Workspaces(): Gtk.Widget { onHover: () => showWorkspaceNumber(true), onHoverLost: () => showWorkspaceNumber(false), onDestroy: () => { - showWsNum?.drop(); - showWsNum = undefined; + // check if the current widgets is from the only bar + if((Windows.openWindows["bar"] as (Array|undefined))?.length === 1) { + showWsNum?.drop(); + showWsNum = undefined; + } }, child: new Widget.Box({ className: "workspaces", spacing: 4, children: bind(AstalHyprland.get_default(), "workspaces").as((workspaces) => workspaces.filter((ws) => ws.id > 0).sort((a, b) => a.id - b.id).map((workspace, wsIndex, workspaces) => { + + const showIds: Variable = Variable.derive([ + Config.getDefault().bindProperty("workspaces.always_show_id", "boolean").as(Boolean), + Config.getDefault().bindProperty("workspaces.enable_helper", "boolean").as(Boolean), + showWsNum!() + ], (alwaysShowIds, enableHelper, showIds) => { + if(enableHelper && !alwaysShowIds) { + const previousWorkspace = workspaces[wsIndex-1]; + const nextWorkspace = workspaces[wsIndex+1]; - const transformFn = (showNum: boolean) => { - const previousWorkspace = workspaces[wsIndex-1]; - const nextWorkspace = workspaces[wsIndex+1]; + if((workspaces.filter((_, i) => i < wsIndex).length > 0 && + previousWorkspace?.id < (workspace.id-1)) || + (workspaces.filter((_, i) => i > wsIndex).length > 0 && + nextWorkspace?.id > (workspace.id+1))) { - if((workspaces.filter((_, i) => i < wsIndex).length > 0 && - previousWorkspace?.id < (workspace.id-1)) || - (workspaces.filter((_, i) => i > wsIndex).length > 0 && - nextWorkspace?.id > (workspace.id+1))) { - - return true; + return true; + } } - return showNum; - } + return alwaysShowIds || showIds; + }); const className = Variable.derive([ bind(AstalHyprland.get_default(), "focusedWorkspace"), - showWsNum!(transformFn) + showIds!() ], (focusedWs, showWsNumbers) => - `${focusedWs.id === workspace.id ? "focus" : ""} ${showWsNumbers ? "show" : ""}` + `${focusedWs.id === workspace.id ? "focus" : ""} ${ + showWsNumbers ? "show" : ""}` ); const tooltipText = Variable.derive([ @@ -66,6 +78,7 @@ export function Workspaces(): Gtk.Widget { onClickRelease: () => workspace.focus(), tooltipText: tooltipText(), onDestroy: () => { + showIds.drop(); className.drop(); tooltipText.drop(); }, @@ -74,7 +87,7 @@ export function Workspaces(): Gtk.Widget { new Widget.Revealer({ transitionDuration: 200, transitionType: Gtk.RevealerTransitionType.SLIDE_LEFT, - revealChild: showWsNum!(transformFn), + revealChild: showIds!(), child: new Widget.Label({ label: bind(workspace, "id").as(String), className: "id", @@ -89,7 +102,7 @@ export function Workspaces(): Gtk.Widget { : Boolean(lastClient)), icon: lastClient ? bind(lastClient, "class").as((clss) => - getSymbolicIcon(clss) ?? "application-x-executable-symbolic") + getSymbolicIcon(clss) ?? getAppIcon(clss) ?? "application-x-executable-symbolic") : undefined } as Widget.IconProps) ]) diff --git a/ags/window/LogoutMenu.ts b/ags/window/LogoutMenu.ts index e4254a6..8b505c2 100644 --- a/ags/window/LogoutMenu.ts +++ b/ags/window/LogoutMenu.ts @@ -1,10 +1,12 @@ import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; import { getDateTime } from "../scripts/time"; -import { exec, execAsync, Gio, GLib } from "astal"; +import { execAsync, Gio, GLib } from "astal"; import { AskPopup } from "../widget/AskPopup"; import { Windows } from "../windows"; import { Notifications } from "../scripts/notifications"; import AstalNotifd from "gi://AstalNotifd"; +import { NightLight } from "../scripts/nightlight"; +import { Config } from "../scripts/config"; const { TOP, LEFT, RIGHT, BOTTOM } = Astal.WindowAnchor; @@ -62,7 +64,9 @@ export const LogoutMenu = (mon: number) => new Widget.Window({ title: "Power Off", text: "Are you sure you want to power off? Unsaved work will be lost.", onAccept: () => { - exec(`sh "${GLib.getenv("XDG_CONFIG_HOME")}/hypr/scripts/save-hyprsunset.sh"`); + Config.getDefault().getProperty("night_light.save_on_shutdown", "boolean") && + NightLight.getDefault().saveData(); + execAsync("systemctl poweroff"); } }) @@ -76,7 +80,9 @@ export const LogoutMenu = (mon: number) => new Widget.Window({ title: "Reboot", text: "Are you sure you want to Reboot? Unsaved work will be lost.", onAccept: () => { - exec(`sh "${GLib.getenv("XDG_CONFIG_HOME")}/hypr/scripts/save-hyprsunset.sh"`); + Config.getDefault().getProperty("night_light.save_on_shutdown", "boolean") && + NightLight.getDefault().saveData(); + execAsync("systemctl reboot"); } }) @@ -101,32 +107,31 @@ export const LogoutMenu = (mon: number) => new Widget.Window({ title: "Log out", text: "Are you sure you want to log out? Your session will be ended.", onAccept: () => { - execAsync( - `sh "${GLib.getenv("XDG_CONFIG_HOME")}/hypr/scripts/save-hyprsunset.sh"` - ).finally(() => - execAsync(`hyprctl dispatch exit`).catch((err: Gio.IOErrorEnum) => - Notifications.getDefault().sendNotification({ - appName: "colorshell", - summary: "Couldn't exit Hyprland", - body: `An error occurred and colorshell couldn't exit Hyprland. Stderr: \n${ - err.message ? `${err.message}\n` : ""}${err.stack}`, - urgency: AstalNotifd.Urgency.NORMAL, - actions: [{ - text: "Report Issue on colorshell", - onAction: () => execAsync( - `xdg-open https://github.com/retrozinndev/colorshell/issues/new` - ).catch((err: Gio.IOErrorEnum) => - Notifications.getDefault().sendNotification({ - appName: "colorshell", - summary: "Couldn't open link", - body: `Do you have \`xdg-utils\` installed? Stderr: \n${ - err.message ? `${err.message}\n` : ""}${err.stack}` - }) - ) - }] - }) - ) - ); + Config.getDefault().getProperty("night_light.save_on_shutdown", "boolean") && + NightLight.getDefault().saveData(); + + execAsync(`hyprctl dispatch exit`).catch((err: Gio.IOErrorEnum) => + Notifications.getDefault().sendNotification({ + appName: "colorshell", + summary: "Couldn't exit Hyprland", + body: `An error occurred and colorshell couldn't exit Hyprland. Stderr: \n${ + err.message ? `${err.message}\n` : ""}${err.stack}`, + urgency: AstalNotifd.Urgency.NORMAL, + actions: [{ + text: "Report Issue on colorshell", + onAction: () => execAsync( + `xdg-open https://github.com/retrozinndev/colorshell/issues/new` + ).catch((err: Gio.IOErrorEnum) => + Notifications.getDefault().sendNotification({ + appName: "colorshell", + summary: "Couldn't open link", + body: `Do you have \`xdg-utils\` installed? Stderr: \n${ + err.message ? `${err.message}\n` : ""}${err.stack}` + }) + ) + }] + }) + ) } }) } as Widget.ButtonProps),