// A single banner: a notification card that slides in and times itself out. import QtQuick 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) // Mirrors the signal above so the dismiss timer below can read it. property bool replyFocused: false 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. Shared with Notifs.qml, which // gives a DND-hidden transient notification the same lifetime. readonly property int timeoutMs: Notifs.notificationTimeoutMs(root.notification) HoverHandler { id: hover } Timer { // Hovering, or actively typing a reply, holds the banner open; the // countdown restarts (from the top, same as hover) once both let go. running: root.timeoutMs > 0 && !hover.hovered && !root.replyFocused 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.replyFocused = 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 } } }