127 lines
4.5 KiB
TypeScript
127 lines
4.5 KiB
TypeScript
import { bind } from "astal";
|
|
import { Gtk } from "astal/gtk4";
|
|
import Notifd from "gi://AstalNotifd";
|
|
import { NotificationIcon } from "./Icon";
|
|
import { createTimeoutManager } from "../../../util/notifd";
|
|
|
|
export function NotificationWidget({
|
|
notification,
|
|
}: {
|
|
notification: Notifd.Notification;
|
|
}) {
|
|
const { START, CENTER, END } = Gtk.Align;
|
|
const actions = notification.actions || [];
|
|
const TIMEOUT_DELAY = 3000;
|
|
|
|
// Keep track of notification validity
|
|
const notifd = Notifd.get_default();
|
|
const timeoutManager = createTimeoutManager(
|
|
() => notification.dismiss(),
|
|
TIMEOUT_DELAY,
|
|
);
|
|
return (
|
|
<box
|
|
setup={(self) => {
|
|
// Set up timeout
|
|
timeoutManager.setupTimeout();
|
|
const clickGesture = Gtk.GestureClick.new();
|
|
clickGesture.set_button(0); // 0 means any button
|
|
clickGesture.connect("pressed", (gesture, _) => {
|
|
try {
|
|
// Get which button was pressed (1=left, 2=middle, 3=right)
|
|
const button = gesture.get_current_button();
|
|
|
|
if (button === 1) {
|
|
// PRIMARY/LEFT
|
|
if (actions.length > 0) n.invoke(actions[0]);
|
|
} else if (button === 2) {
|
|
// MIDDLE
|
|
notifd.notifications?.forEach((n) => {
|
|
n.dismiss();
|
|
});
|
|
} else if (button === 3) {
|
|
// SECONDARY/RIGHT
|
|
notification.dismiss();
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
});
|
|
self.add_controller(clickGesture);
|
|
|
|
self.connect("unrealize", () => {
|
|
timeoutManager.cleanup();
|
|
});
|
|
}}
|
|
onHoverEnter={timeoutManager.handleHover}
|
|
onHoverLeave={timeoutManager.handleHoverLost}
|
|
vertical
|
|
vexpand={false}
|
|
cssClasses={["notification", `${urgency(notification)}`]}
|
|
name={notification.id.toString()}
|
|
>
|
|
<box cssClasses={["header"]}>
|
|
<label
|
|
cssClasses={["app-name"]}
|
|
halign={CENTER}
|
|
label={bind(notification, "app_name")}
|
|
/>
|
|
<label
|
|
cssClasses={["time"]}
|
|
hexpand
|
|
halign={END}
|
|
label={time(notification.time)}
|
|
/>
|
|
</box>
|
|
<Gtk.Separator />
|
|
<box cssClasses={["content"]}>
|
|
<box
|
|
cssClasses={["thumb"]}
|
|
visible={Boolean(NotificationIcon(notification))}
|
|
halign={CENTER}
|
|
valign={CENTER}
|
|
vexpand={true}
|
|
>
|
|
{NotificationIcon(notification)}
|
|
</box>
|
|
<box
|
|
vertical
|
|
cssClasses={["text-content"]}
|
|
hexpand={true}
|
|
halign={CENTER}
|
|
valign={CENTER}
|
|
>
|
|
<label
|
|
cssClasses={["title"]}
|
|
valign={CENTER}
|
|
wrap={false}
|
|
label={bind(notification, "summary")}
|
|
/>
|
|
{notification.body && (
|
|
<label
|
|
cssClasses={["body"]}
|
|
valign={CENTER}
|
|
wrap={true}
|
|
maxWidthChars={50}
|
|
label={bind(notification, "body")}
|
|
/>
|
|
)}
|
|
</box>
|
|
</box>
|
|
{actions.length > 0 && (
|
|
<box cssClasses={["actions"]}>
|
|
{actions.map(({ label, action }) => (
|
|
<button
|
|
hexpand
|
|
cssClasses={["action-button"]}
|
|
onClicked={() => notification.invoke(action)}
|
|
>
|
|
<label label={label} halign={CENTER} hexpand />
|
|
</button>
|
|
))}
|
|
</box>
|
|
)}
|
|
</box>
|
|
);
|
|
}
|