Extend notification popup lifetime
This commit is contained in:
@@ -56,6 +56,8 @@ function glyphFromHints(hints) {
|
|||||||
function snapshotOf(notification, timestamp) {
|
function snapshotOf(notification, timestamp) {
|
||||||
var n = notification || {}
|
var n = notification || {}
|
||||||
var id = n.id || 0
|
var id = n.id || 0
|
||||||
|
var expireTimeout = Number(n.expireTimeout || 0)
|
||||||
|
if (!isFinite(expireTimeout) || expireTimeout < 0) expireTimeout = 0
|
||||||
return {
|
return {
|
||||||
id: id,
|
id: id,
|
||||||
originalId: id,
|
originalId: id,
|
||||||
@@ -66,6 +68,7 @@ function snapshotOf(notification, timestamp) {
|
|||||||
image: n.image || "",
|
image: n.image || "",
|
||||||
glyph: glyphFromHints(n.hints),
|
glyph: glyphFromHints(n.hints),
|
||||||
urgency: n.urgency,
|
urgency: n.urgency,
|
||||||
|
expireTimeout: expireTimeout,
|
||||||
timestamp: timestamp === undefined ? Date.now() : timestamp,
|
timestamp: timestamp === undefined ? Date.now() : timestamp,
|
||||||
ref: notification
|
ref: notification
|
||||||
}
|
}
|
||||||
@@ -83,6 +86,7 @@ function historyEntry(value, normalUrgency) {
|
|||||||
image: e.image || "",
|
image: e.image || "",
|
||||||
glyph: e.glyph || "",
|
glyph: e.glyph || "",
|
||||||
urgency: typeof e.urgency === "number" ? e.urgency : normalUrgency,
|
urgency: typeof e.urgency === "number" ? e.urgency : normalUrgency,
|
||||||
|
expireTimeout: 0,
|
||||||
timestamp: e.timestamp || 0,
|
timestamp: e.timestamp || 0,
|
||||||
ref: null
|
ref: null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,17 +92,27 @@ Item {
|
|||||||
readonly property int historyCap: 100
|
readonly property int historyCap: 100
|
||||||
property var imageCacheQueue: []
|
property var imageCacheQueue: []
|
||||||
|
|
||||||
function durationFor(urgency) {
|
readonly property int lowPopupDuration: 5000
|
||||||
|
readonly property int normalPopupDuration: 8000
|
||||||
|
readonly property int maxPopupDuration: 30000
|
||||||
|
|
||||||
|
function durationFor(urgency, expireTimeout) {
|
||||||
switch (urgency) {
|
switch (urgency) {
|
||||||
case NotificationUrgency.Critical:
|
case NotificationUrgency.Critical:
|
||||||
return 0
|
return 0
|
||||||
case NotificationUrgency.Low:
|
case NotificationUrgency.Low:
|
||||||
return 3000
|
return Math.min(maxPopupDuration, Math.max(lowPopupDuration, requestedDuration(expireTimeout)))
|
||||||
default:
|
default:
|
||||||
return 5000
|
return Math.min(maxPopupDuration, Math.max(normalPopupDuration, requestedDuration(expireTimeout)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function requestedDuration(expireTimeout) {
|
||||||
|
var seconds = Number(expireTimeout || 0)
|
||||||
|
if (!isFinite(seconds) || seconds <= 0) return 0
|
||||||
|
return Math.round(seconds * 1000)
|
||||||
|
}
|
||||||
|
|
||||||
// DND bypass: only let through notifications we trust to be intentional
|
// DND bypass: only let through notifications we trust to be intentional
|
||||||
// and rare.
|
// and rare.
|
||||||
// - omarchy-action: a user-action confirmation toast ("Theme changed",
|
// - omarchy-action: a user-action confirmation toast ("Theme changed",
|
||||||
@@ -237,6 +247,7 @@ Item {
|
|||||||
image: row.image,
|
image: row.image,
|
||||||
glyph: row.glyph || "",
|
glyph: row.glyph || "",
|
||||||
urgency: row.urgency,
|
urgency: row.urgency,
|
||||||
|
expireTimeout: row.expireTimeout || 0,
|
||||||
timestamp: row.timestamp
|
timestamp: row.timestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,6 +268,14 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dismissPopup(index) {
|
function dismissPopup(index) {
|
||||||
|
removePopup(index, "dismiss")
|
||||||
|
}
|
||||||
|
|
||||||
|
function expirePopup(index) {
|
||||||
|
removePopup(index, "expire")
|
||||||
|
}
|
||||||
|
|
||||||
|
function removePopup(index, reason) {
|
||||||
if (index < 0 || index >= popupModel.count) return
|
if (index < 0 || index >= popupModel.count) return
|
||||||
var entry = popupModel.get(index)
|
var entry = popupModel.get(index)
|
||||||
var ref = entry ? entry.ref : null
|
var ref = entry ? entry.ref : null
|
||||||
@@ -264,7 +283,10 @@ Item {
|
|||||||
popupModel.remove(index)
|
popupModel.remove(index)
|
||||||
if (ref) {
|
if (ref) {
|
||||||
try {
|
try {
|
||||||
if (ref.tracked) ref.dismiss()
|
if (ref.tracked) {
|
||||||
|
if (reason === "expire" && typeof ref.expire === "function") ref.expire()
|
||||||
|
else ref.dismiss()
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Object already torn down by the server — nothing to dismiss.
|
// Object already torn down by the server — nothing to dismiss.
|
||||||
}
|
}
|
||||||
@@ -555,6 +577,7 @@ Item {
|
|||||||
image: r.image,
|
image: r.image,
|
||||||
glyph: r.glyph || "",
|
glyph: r.glyph || "",
|
||||||
urgency: r.urgency,
|
urgency: r.urgency,
|
||||||
|
expireTimeout: r.expireTimeout || 0,
|
||||||
timestamp: r.timestamp
|
timestamp: r.timestamp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -753,6 +776,7 @@ Item {
|
|||||||
required property string image
|
required property string image
|
||||||
required property string glyph
|
required property string glyph
|
||||||
required property int urgency
|
required property int urgency
|
||||||
|
required property double expireTimeout
|
||||||
required property double timestamp
|
required property double timestamp
|
||||||
|
|
||||||
// Each card sizes itself based on mode (text vs media); the slot
|
// Each card sizes itself based on mode (text vs media); the slot
|
||||||
@@ -761,7 +785,7 @@ Item {
|
|||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
implicitHeight: card.implicitHeight
|
implicitHeight: card.implicitHeight
|
||||||
|
|
||||||
readonly property real lifetime: service.durationFor(cardSlot.urgency)
|
readonly property real lifetime: service.durationFor(cardSlot.urgency, cardSlot.expireTimeout)
|
||||||
property real remainingLifetime: 1.0
|
property real remainingLifetime: 1.0
|
||||||
readonly property bool ticking: cardSlot.lifetime > 0 && !card.hovered
|
readonly property bool ticking: cardSlot.lifetime > 0 && !card.hovered
|
||||||
|
|
||||||
@@ -774,7 +798,7 @@ Item {
|
|||||||
cardSlot.remainingLifetime -= 50.0 / cardSlot.lifetime
|
cardSlot.remainingLifetime -= 50.0 / cardSlot.lifetime
|
||||||
if (cardSlot.remainingLifetime <= 0) {
|
if (cardSlot.remainingLifetime <= 0) {
|
||||||
cardSlot.remainingLifetime = 0
|
cardSlot.remainingLifetime = 0
|
||||||
service.dismissPopup(cardSlot.index)
|
service.expirePopup(cardSlot.index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ const notification = {
|
|||||||
body: 'Body',
|
body: 'Body',
|
||||||
image: 'file:///tmp/mail.png',
|
image: 'file:///tmp/mail.png',
|
||||||
hints: { 'omarchy-glyph': '!' },
|
hints: { 'omarchy-glyph': '!' },
|
||||||
urgency: 1
|
urgency: 1,
|
||||||
|
expireTimeout: 1.5
|
||||||
}
|
}
|
||||||
const snapshot = notifications.snapshotOf(notification, 12345)
|
const snapshot = notifications.snapshotOf(notification, 12345)
|
||||||
assertDeepEqual(
|
assertDeepEqual(
|
||||||
@@ -67,6 +68,7 @@ assertDeepEqual(
|
|||||||
image: snapshot.image,
|
image: snapshot.image,
|
||||||
glyph: snapshot.glyph,
|
glyph: snapshot.glyph,
|
||||||
urgency: snapshot.urgency,
|
urgency: snapshot.urgency,
|
||||||
|
expireTimeout: snapshot.expireTimeout,
|
||||||
timestamp: snapshot.timestamp
|
timestamp: snapshot.timestamp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -79,6 +81,7 @@ assertDeepEqual(
|
|||||||
image: 'file:///tmp/mail.png',
|
image: 'file:///tmp/mail.png',
|
||||||
glyph: '!',
|
glyph: '!',
|
||||||
urgency: 1,
|
urgency: 1,
|
||||||
|
expireTimeout: 1.5,
|
||||||
timestamp: 12345
|
timestamp: 12345
|
||||||
},
|
},
|
||||||
'notifications create stable snapshots'
|
'notifications create stable snapshots'
|
||||||
|
|||||||
Reference in New Issue
Block a user