115 lines
No EOL
3.8 KiB
TypeScript
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;
|
|
} |