jroshell/widget/Overlay/EmailList.tsx
2026-06-06 13:53:38 +02:00

115 lines
No EOL
3.8 KiB
TypeScript

import { Gtk } from "ags/gtk4";
import { createState } from "ags";
import GLib from "gi://GLib";
import Gio from "gi://Gio";
import { watchFile } from "../../lib/fileMonitor";
type Email = { subject: string; sender: string; date: string };
const CACHE_FILE = GLib.build_filenamev([
GLib.get_user_cache_dir(),
"ags",
"unread-emails.json",
]);
export default function EmailList() {
const [emails, setEmails] = createState<Email[]>([]);
let listContainer: Gtk.Box | null = null; // holds the email items
function readEmailsFromCache(): Email[] {
try {
const file = Gio.File.new_for_path(CACHE_FILE);
const [ok, contents] = file.load_contents(null);
if (!ok) return [];
const data = JSON.parse(new TextDecoder("utf-8").decode(contents));
if (!Array.isArray(data)) return [];
return data.map((m: any) => ({
subject: m.subject || "(no subject)",
sender: m.from?.name || m.from?.addr || "Unknown",
date: m.date ? new Date(m.date).toLocaleString() : "Unknown date",
}));
} catch (err) {
console.error("Failed to read email cache", err);
return [];
}
}
function rebuildList() {
if (!listContainer) return;
// Clear existing children
let child = listContainer.get_first_child();
while (child) {
const next = child.get_next_sibling();
listContainer.remove(child);
child = next;
}
const currentEmails = emails();
if (currentEmails.length === 0) {
// Empty state
const emptyBox = new Gtk.Box({
halign: Gtk.Align.CENTER,
valign: Gtk.Align.START,
orientation: Gtk.Orientation.VERTICAL,
cssClasses: ["status-box"],
});
emptyBox.append(new Gtk.Label({ label: "📭", cssClasses: ["empty-icon"] }));
emptyBox.append(new Gtk.Label({ label: "No unread emails", cssClasses: ["status-text"] }));
listContainer.append(emptyBox);
} else {
// Populate emails
for (const email of currentEmails) {
const item = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
cssClasses: ["email-item"],
});
item.append(new Gtk.Label({
label: email.subject,
halign: Gtk.Align.START,
hexpand: false,
cssClasses: ["email-subject"],
}));
const meta = new Gtk.Box({ spacing: 8 });
meta.append(new Gtk.Label({ label: email.sender, cssClasses: ["email-sender"] }));
meta.append(new Gtk.Label({ label: "•", cssClasses: ["email-separator"] }));
meta.append(new Gtk.Label({ label: email.date, cssClasses: ["email-date"] }));
item.append(meta);
listContainer.append(item);
}
}
}
function updateDisplay() {
const parsed = readEmailsFromCache();
setEmails(parsed);
rebuildList();
}
const root = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
cssClasses: ["email-list-container"],
});
const scrolled = new Gtk.ScrolledWindow({
vexpand: true,
cssClasses: ["email-scroll", "grid-card"],
});
listContainer = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
spacing: 12,
hexpand: true,
cssClasses: ["email-list"],
});
scrolled.set_child(listContainer);
root.append(scrolled);
// Initial load + monitor
updateDisplay();
watchFile(CACHE_FILE, updateDisplay, root);
return root;
}