feat(config): implement configurations

This commit is contained in:
retrozinndev
2025-06-26 15:12:24 -03:00
parent 0dce6a98a9
commit dece2776fe
5 changed files with 81 additions and 59 deletions
+9 -1
View File
@@ -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`);
}
}
+4 -8
View File
@@ -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<number> = [];
#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());
+3 -3
View File
@@ -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);
}
+31 -18
View File
@@ -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<boolean>|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<Widget.Window>|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<boolean> = 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)
])
+34 -29
View File
@@ -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),