feat(notifications): retrieve history from astal's notifd file in XDG_STATE_HOME

This commit is contained in:
retrozinndev
2025-07-23 20:51:02 -03:00
parent 8074221489
commit 612dcc693f
3 changed files with 88 additions and 44 deletions
+9
View File
@@ -61,6 +61,15 @@ export function getIconByAppName(appName: string): (string|undefined) {
return appName.toLowerCase(); return appName.toLowerCase();
const nameReverseDNS = appName.split('.'); const nameReverseDNS = appName.split('.');
const lastItem = nameReverseDNS[nameReverseDNS.length - 1];
const lastPretty = `${lastItem.charAt(0).toUpperCase()}${lastItem.substring(1, lastItem.length)}`;
const uppercaseRDNS = nameReverseDNS.slice(0, nameReverseDNS.length - 1)
.concat(lastPretty).join('.');
if(lookupIcon(uppercaseRDNS))
return uppercaseRDNS;
if(lookupIcon(nameReverseDNS[nameReverseDNS.length - 1])) if(lookupIcon(nameReverseDNS[nameReverseDNS.length - 1]))
return nameReverseDNS[nameReverseDNS.length - 1]; return nameReverseDNS[nameReverseDNS.length - 1];
+66 -27
View File
@@ -4,8 +4,11 @@ import { execAsync } from "ags/process";
import GObject, { getter, property, register, signal } from "ags/gobject"; import GObject, { getter, property, register, signal } from "ags/gobject";
import AstalNotifd from "gi://AstalNotifd"; import AstalNotifd from "gi://AstalNotifd";
import Gio from "gi://Gio?version=2.0";
import AstalIO from "gi://AstalIO"; import AstalIO from "gi://AstalIO";
import { onCleanup } from "ags";
import Gio from "gi://Gio?version=2.0";
import GLib from "gi://GLib?version=2.0";
import { readFile } from "ags/file";
export interface HistoryNotification { export interface HistoryNotification {
@@ -95,11 +98,12 @@ class Notifications extends GObject.Object {
}) })
); );
this.run_dispose = () => { this.retrieveHistoryFromFile();
super.run_dispose();
this.#connections.map((id: number) => onCleanup(() => {
this.#connections.map(id =>
AstalNotifd.get_default().disconnect(id)); AstalNotifd.get_default().disconnect(id));
}; });
} }
public static getDefault(): Notifications { public static getDefault(): Notifications {
@@ -109,23 +113,59 @@ class Notifications extends GObject.Object {
return this.instance; return this.instance;
} }
private retrieveHistoryFromFile(): void {
const historyFile = Gio.File.new_for_path(`${GLib.get_user_state_dir()}/astal/notifd/notifications.json`);
if(!historyFile.query_exists(null)) return;
let content: string;
console.log("Notifications: History file found! Trying to retrieve history from JSON");
try {
content = readFile(historyFile.get_path()!);
} catch(e: any) {
console.error(`Notifications: An error occurred while trying to read the history file. Stderr:\n${
(e as Error).message}\n${(e as Error).stack}`);
return;
}
try {
const historyJSON = JSON.parse(content);
(historyJSON["notifications"] as Array<AstalNotifd.Notification>).reverse()
.forEach(n => this.addHistory(n));
} catch(e: any) {
if(e instanceof SyntaxError) {
console.error(`Notifications: Couldn't parse history JSON because of a SyntaxError:\n${e.message
}\n${e.stack}`);
return;
}
console.error(`Notifications: An error occurred while parsing the history JSON file. Stderr:\n${
e.message}\n${e.stack}`);
return;
}
}
public async sendNotification(props: { public async sendNotification(props: {
urgency?: AstalNotifd.Urgency; urgency?: AstalNotifd.Urgency;
appName?: string; appName?: string;
image?: string; image?: string;
summary: string; summary: string;
body?: string; body?: string;
replaceId?: number; replaceId?: number;
actions?: Array<{ actions?: Array<{
id?: (string|number); id?: (string|number);
text: string; text: string;
onAction?: () => void onAction?: () => void
}> }>
}): Promise<{ }): Promise<{
id?: (string|number); id?: (string|number);
text: string; text: string;
onAction?: () => void onAction?: () => void
}|null|void> { }|null|void> {
return await execAsync([ return await execAsync([
"notify-send", "notify-send",
@@ -155,7 +195,7 @@ class Notifications extends GObject.Object {
return action ?? undefined; return action ?? undefined;
} }
}).catch((err: Gio.IOErrorEnum) => { }).catch((err: Error) => {
console.error(`Notifications: Couldn't send notification! Is the daemon running? Stderr:\n${ console.error(`Notifications: Couldn't send notification! Is the daemon running? Stderr:\n${
err.message ? `${err.message}\n` : ""}Stack: ${err.stack}`); err.message ? `${err.message}\n` : ""}Stack: ${err.stack}`);
}); });
@@ -185,11 +225,11 @@ class Notifications extends GObject.Object {
this.#history.unshift({ this.#history.unshift({
id: notif.id, id: notif.id,
appName: notif.appName, appName: notif.app_name,
body: notif.body, body: notif.body,
summary: notif.summary, summary: notif.summary,
urgency: notif.urgency, urgency: notif.urgency,
appIcon: notif.appIcon, appIcon: notif.app_icon,
time: notif.time, time: notif.time,
image: notif.image ? notif.image : undefined image: notif.image ? notif.image : undefined
} as HistoryNotification); } as HistoryNotification);
@@ -236,10 +276,9 @@ class Notifications extends GObject.Object {
public removeNotification(notif: (AstalNotifd.Notification|number)): void { public removeNotification(notif: (AstalNotifd.Notification|number)): void {
const notificationId = (notif instanceof AstalNotifd.Notification) ? notif.id : notif; const notificationId = (notif instanceof AstalNotifd.Notification) ? notif.id : notif;
this.#notificationsOnHold.has(notificationId) && this.#notificationsOnHold.delete(notificationId);
this.#notificationsOnHold.delete(notificationId);
this.#notifications = this.#notifications.filter((item: AstalNotifd.Notification) => this.#notifications = this.#notifications.filter((item) =>
item.id !== notificationId); item.id !== notificationId);
AstalNotifd.get_default().get_notification(notificationId)?.dismiss(); AstalNotifd.get_default().get_notification(notificationId)?.dismiss();
+13 -17
View File
@@ -13,10 +13,7 @@ export class Stylesheet {
private static instance: Stylesheet; private static instance: Stylesheet;
#watchDelay: (AstalIO.Time|undefined); #watchDelay: (AstalIO.Time|undefined);
#outputPath = Gio.File.new_for_path(`${GLib.get_user_state_dir()}/ags/style`); #outputPath = Gio.File.new_for_path(`${GLib.get_user_state_dir()}/ags/style`);
#styles = [ #styles = [ "./style", "./style.scss" ];
"./style",
"./style.scss"
];
public async compileSass(): Promise<void> { public async compileSass(): Promise<void> {
console.log("Stylesheet: Compiling Sass"); console.log("Stylesheet: Compiling Sass");
@@ -30,7 +27,7 @@ export class Stylesheet {
const content = readFile(cssFilePath); const content = readFile(cssFilePath);
if(content) { if(content?.trim()) {
App.reset_css(); App.reset_css();
App.apply_css(content); App.apply_css(content);
@@ -43,10 +40,12 @@ export class Stylesheet {
} }
public async compileApply(): Promise<void> { public async compileApply(): Promise<void> {
await this.compileSass().catch((err: Gio.IOErrorEnum) => await this.compileSass().then(() =>
console.error(`Stylesheet: An Error occurred and Sass couldn't be compiled. Stderr:\n${err.message ? this.reapply(this.#outputPath.get_path()! + "/style.css")
`\t${err.message}\n` : ""}${err.stack}\n`) ).catch((err: Error) =>
).then(() => this.reapply(this.#outputPath.get_path()! + "/style.css")); console.error(`Stylesheet: An error occurred and Sass couldn't be compiled. Stderr:\n${
err.message}\n${err.stack}`)
);
} }
public static getDefault(): Stylesheet { public static getDefault(): Stylesheet {
@@ -77,13 +76,10 @@ export class Stylesheet {
) )
) )
monitorFile( monitorFile(`${GLib.get_user_cache_dir()}/wal/colors.scss`, (file: string) => {
`${GLib.get_user_cache_dir()}/wal/colors.scss`, execAsync(`bash -c "cp -f ${file} ./style/_wal.scss"`).catch(r => {
(file: string) => { console.error(`Stylesheet: Failed to copy pywal stylesheet to style dir. Stderr: ${r}`);
execAsync(`bash -c "cp -f ${file} ./style/_wal.scss"`).catch(r => { });
console.error(`Stylesheet: Failed to copy pywal stylesheet to style dir. Stderr: ${r}`); });
});
}
);
} }
} }