fix
This commit is contained in:
@@ -15,14 +15,39 @@ QtObject {
|
||||
}
|
||||
|
||||
function indexOfId(notificationId) {
|
||||
const wantedId = String(notificationId);
|
||||
for (let i = 0; i < notifications.count; i++) {
|
||||
const row = notifications.get(i);
|
||||
if (row.rowNotificationId === notificationId)
|
||||
if (String(row.rowNotificationId) === wantedId)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function indexOfIdAndObject(notificationId, notificationObject) {
|
||||
const wantedId = String(notificationId);
|
||||
for (let i = 0; i < notifications.count; i++) {
|
||||
const row = notifications.get(i);
|
||||
if (String(row.rowNotificationId) === wantedId && row.rowObject === notificationObject)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function removeRowsById(notificationId, replacementObject) {
|
||||
const wantedId = String(notificationId);
|
||||
for (let i = notifications.count - 1; i >= 0; i--) {
|
||||
const row = notifications.get(i);
|
||||
if (String(row.rowNotificationId) !== wantedId)
|
||||
continue;
|
||||
|
||||
if (row.rowObject && row.rowObject !== replacementObject)
|
||||
row.rowObject.dismiss();
|
||||
|
||||
notifications.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
function normalizedString(value) {
|
||||
if (value === undefined || value === null)
|
||||
return "";
|
||||
@@ -36,6 +61,65 @@ QtObject {
|
||||
return value === undefined || value === null ? "" : String(value);
|
||||
}
|
||||
|
||||
function isNotifyToolName(value) {
|
||||
const normalized = String(value || "").trim().toLowerCase();
|
||||
if (normalized.length === 0)
|
||||
return false;
|
||||
return normalized === "notify-send" || normalized === "dunstify" || normalized === "notify-send.desktop" || normalized === "dunstify.desktop";
|
||||
}
|
||||
|
||||
function isNotifyToolNotification(notificationObject) {
|
||||
if (!notificationObject)
|
||||
return false;
|
||||
return isNotifyToolName(notificationObject.appName) || isNotifyToolName(hintString(notificationObject, "desktop-entry"));
|
||||
}
|
||||
|
||||
function removeOldNotifyToolRows(replacementObject) {
|
||||
if (!isNotifyToolNotification(replacementObject))
|
||||
return;
|
||||
|
||||
for (let i = notifications.count - 1; i >= 0; i--) {
|
||||
const row = notifications.get(i);
|
||||
const rowObject = row.rowObject;
|
||||
if (!rowObject || rowObject === replacementObject)
|
||||
continue;
|
||||
if (!isNotifyToolNotification(rowObject))
|
||||
continue;
|
||||
|
||||
rowObject.dismiss();
|
||||
notifications.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
function replacementFallbackKeyFor(notificationObject) {
|
||||
if (!notificationObject)
|
||||
return "";
|
||||
|
||||
const idValue = Number(notificationObject.id);
|
||||
if (Number.isFinite(idValue) && idValue > 0)
|
||||
return "id:" + String(Math.trunc(idValue));
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function removeRowsByFallbackReplacementKey(replacementObject) {
|
||||
const fallbackKey = replacementFallbackKeyFor(replacementObject);
|
||||
if (fallbackKey.length === 0)
|
||||
return;
|
||||
|
||||
for (let i = notifications.count - 1; i >= 0; i--) {
|
||||
const row = notifications.get(i);
|
||||
if (row.rowObject === replacementObject)
|
||||
continue;
|
||||
if (String(row.rowReplacementFallbackKey || "") !== fallbackKey)
|
||||
continue;
|
||||
|
||||
if (row.rowObject)
|
||||
row.rowObject.dismiss();
|
||||
notifications.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
function groupKeyFor(notificationObject) {
|
||||
const desktopEntry = normalizedString(hintString(notificationObject, "desktop-entry")).trim().toLowerCase();
|
||||
if (desktopEntry.length > 0)
|
||||
@@ -123,6 +207,37 @@ QtObject {
|
||||
setGroupExpanded(groupKey, !groupIsExpanded(groupKey));
|
||||
}
|
||||
|
||||
function rowDataFor(notificationObject, createdAtMsOverride) {
|
||||
return {
|
||||
rowNotificationId: notificationObject.id,
|
||||
rowObject: notificationObject,
|
||||
rowVersion: nextVersion(),
|
||||
rowCreatedAt: createdAtMsOverride !== undefined ? createdAtMsOverride : Date.now(),
|
||||
rowGroupKey: groupKeyFor(notificationObject),
|
||||
rowAppName: normalizedString(notificationObject.appName),
|
||||
rowAppIcon: normalizedString(notificationObject.appIcon),
|
||||
rowImage: normalizedString(notificationObject.image),
|
||||
rowDesktopEntry: hintString(notificationObject, "desktop-entry"),
|
||||
rowReplacementFallbackKey: replacementFallbackKeyFor(notificationObject)
|
||||
};
|
||||
}
|
||||
|
||||
function bumpNotificationToTop(notificationObject) {
|
||||
const rowIndex = indexOfIdAndObject(notificationObject.id, notificationObject);
|
||||
if (rowIndex < 0)
|
||||
return;
|
||||
|
||||
if (rowIndex === 0) {
|
||||
notifications.set(0, rowDataFor(notificationObject));
|
||||
rebuildGroups();
|
||||
return;
|
||||
}
|
||||
|
||||
removeRowsById(notificationObject.id, notificationObject);
|
||||
notifications.insert(0, rowDataFor(notificationObject));
|
||||
rebuildGroups();
|
||||
}
|
||||
|
||||
function addNotification(notificationObject) {
|
||||
if (notificationObject.lastGeneration) {
|
||||
notificationObject.dismiss();
|
||||
@@ -130,48 +245,62 @@ QtObject {
|
||||
}
|
||||
|
||||
notificationObject.tracked = true;
|
||||
const groupKey = groupKeyFor(notificationObject);
|
||||
|
||||
const idCopy = notificationObject.id;
|
||||
const objectCopy = notificationObject;
|
||||
notificationObject.closed.connect(function () {
|
||||
const rowIndex = indexOfId(idCopy);
|
||||
if (rowIndex >= 0 && notifications.get(rowIndex).rowObject === objectCopy) {
|
||||
notifications.remove(rowIndex);
|
||||
rebuildGroups();
|
||||
}
|
||||
});
|
||||
// Guard against reconnecting signals when the same QObject is seen again.
|
||||
// Replacement is strict freedesktop id semantics:
|
||||
// `id=$(notify-send -p ...)`, then `notify-send -r "$id" ...`.
|
||||
if (!notificationObject.__dqModelWired) {
|
||||
notificationObject.__dqModelWired = true;
|
||||
|
||||
const nowMs = Date.now();
|
||||
const groupKey = groupKeyFor(notificationObject);
|
||||
notificationObject.closed.connect(function () {
|
||||
let rowIndex = indexOfIdAndObject(idCopy, objectCopy);
|
||||
if (rowIndex < 0) {
|
||||
const idOnlyIndex = indexOfId(idCopy);
|
||||
if (idOnlyIndex >= 0 && notifications.get(idOnlyIndex).rowObject === objectCopy)
|
||||
rowIndex = idOnlyIndex;
|
||||
}
|
||||
|
||||
if (rowIndex >= 0) {
|
||||
notifications.remove(rowIndex);
|
||||
setGroupExpanded(groupKey, false);
|
||||
rebuildGroups();
|
||||
}
|
||||
});
|
||||
|
||||
const onUpdated = function () {
|
||||
root.bumpNotificationToTop(objectCopy);
|
||||
};
|
||||
notificationObject.expireTimeoutChanged.connect(onUpdated);
|
||||
notificationObject.appNameChanged.connect(onUpdated);
|
||||
notificationObject.appIconChanged.connect(onUpdated);
|
||||
notificationObject.summaryChanged.connect(onUpdated);
|
||||
notificationObject.bodyChanged.connect(onUpdated);
|
||||
notificationObject.actionsChanged.connect(onUpdated);
|
||||
notificationObject.desktopEntryChanged.connect(onUpdated);
|
||||
notificationObject.imageChanged.connect(onUpdated);
|
||||
notificationObject.hintsChanged.connect(onUpdated);
|
||||
}
|
||||
|
||||
const existingIndex = indexOfId(notificationObject.id);
|
||||
if (existingIndex >= 0) {
|
||||
notifications.set(existingIndex, {
|
||||
rowNotificationId: notificationObject.id,
|
||||
rowObject: notificationObject,
|
||||
rowVersion: nextVersion(),
|
||||
rowCreatedAt: nowMs,
|
||||
rowGroupKey: groupKey,
|
||||
rowAppName: normalizedString(notificationObject.appName),
|
||||
rowAppIcon: normalizedString(notificationObject.appIcon),
|
||||
rowImage: normalizedString(notificationObject.image),
|
||||
rowDesktopEntry: hintString(notificationObject, "desktop-entry")
|
||||
});
|
||||
if (existingIndex >= 0 && notifications.get(existingIndex).rowObject === notificationObject) {
|
||||
const currentRow = notifications.get(existingIndex);
|
||||
notifications.set(existingIndex, rowDataFor(notificationObject, currentRow.rowCreatedAt));
|
||||
rebuildGroups();
|
||||
return;
|
||||
}
|
||||
|
||||
notifications.append({
|
||||
rowNotificationId: notificationObject.id,
|
||||
rowObject: notificationObject,
|
||||
rowVersion: nextVersion(),
|
||||
rowCreatedAt: nowMs,
|
||||
rowGroupKey: groupKey,
|
||||
rowAppName: normalizedString(notificationObject.appName),
|
||||
rowAppIcon: normalizedString(notificationObject.appIcon),
|
||||
rowImage: normalizedString(notificationObject.image),
|
||||
rowDesktopEntry: hintString(notificationObject, "desktop-entry")
|
||||
});
|
||||
removeRowsById(notificationObject.id, notificationObject);
|
||||
// Quickshell currently doesn't expose client replaces_id in QML, so keep
|
||||
// notify-send/dunstify entries collapsed to newest to match -r user intent.
|
||||
removeOldNotifyToolRows(notificationObject);
|
||||
// Fallback replacement key uses id only.
|
||||
removeRowsByFallbackReplacementKey(notificationObject);
|
||||
|
||||
notifications.insert(0, rowDataFor(notificationObject));
|
||||
// setGroupExpanded(groupKey, true);
|
||||
rebuildGroups();
|
||||
}
|
||||
|
||||
@@ -191,8 +320,16 @@ QtObject {
|
||||
}
|
||||
}
|
||||
|
||||
notifications.remove(rowIndex);
|
||||
rebuildGroups();
|
||||
const remainingIndex = indexOfId(notificationId);
|
||||
if (remainingIndex >= 0) {
|
||||
const remainingRow = notifications.get(remainingIndex);
|
||||
// Avoid removing a newly inserted replacement row with the same id.
|
||||
if (!notifObject || remainingRow.rowObject === notifObject) {
|
||||
notifications.remove(remainingIndex);
|
||||
// setGroupExpanded(groupKey, true);
|
||||
rebuildGroups();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property NotificationServer server: NotificationServer {
|
||||
|
||||
Reference in New Issue
Block a user