// A single banner: a notification card that slides in and times itself out. import QtQuick import Quickshell.Services.Notifications import qs.config import qs.services Item { id: root required property var notification // Raised while the inline reply field has focus — Toasts.qml turns that // into a keyboard focus request on the layer surface. signal replyFocusChanged(bool focused) implicitHeight: card.implicitHeight // Critical notifications stay until dismissed (the setting is 0). An app // asking for 0 means "never expire" per the freedesktop spec; -1 means // "server decides", which is our default. readonly property int timeoutMs: { if (root.notification.urgency === NotificationUrgency.Critical) return Settings.notificationTimeoutCriticalMs; if (root.notification.expireTimeout === 0) return 0; if (root.notification.expireTimeout > 0) return Math.round(root.notification.expireTimeout * 1000); return Settings.notificationTimeoutMs; } HoverHandler { id: hover } Timer { // Hovering holds the banner open; the countdown restarts on leave. running: root.timeoutMs > 0 && !hover.hovered interval: root.timeoutMs onTriggered: Notifs.dropPopup(root.notification) } NotificationCard { id: card width: parent.width notification: root.notification onDismissed: Notifs.dropPopup(root.notification) onReplyFocusChanged: focused => root.replyFocusChanged(focused) // Slide in from the right edge. Runs once, on creation. NumberAnimation on x { from: 40 to: 0 duration: Theme.durNormal easing.type: Easing.OutCubic } NumberAnimation on opacity { from: 0 to: 1 duration: Theme.durNormal } } }