Fix notification centre icons and dismissal
This commit is contained in:
1 parent
77ba1dadff
commit
ad46fe4a53
5 files changed
+50
-17
No files matched your search
@@ -53,6 +53,15 @@ border, so they read against the panel in any theme. An active tile takes the
|
||||
accent colour. The Wallpaper tile opens `blob.displays`, the Theme tile opens
|
||||
`blob theme menu`.
|
||||
|
||||
## Notification centre
|
||||
|
||||
`blob.notification-center` lists the notification history, newest first. A
|
||||
toast that expires unseen moves into history; a toast you close or click is
|
||||
deleted instead, so the centre only holds what you missed. The x on an entry
|
||||
removes it through `blob-shell notifications remove <file>`, the bell button
|
||||
toggles silencing, and the trash button clears the whole history with
|
||||
`blob-shell notifications clear`.
|
||||
|
||||
## Deliberately not ported
|
||||
|
||||
The tiles still poll shell commands the way the GTK widgets did - `pamixer` for
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
.pragma library
|
||||
|
||||
// Each history file is one line of JSON, so the reader concatenates the
|
||||
// directory and parses line by line. Newest first, by timestamp.
|
||||
// Each history file is one line of JSON, and the reader prefixes every line
|
||||
// with the file's name and a tab so an entry can be removed later. Newest
|
||||
// first, by timestamp.
|
||||
function parseHistory(raw) {
|
||||
var lines = String(raw || "").split("\n")
|
||||
var entries = []
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i].trim()
|
||||
if (!line) continue
|
||||
var tab = line.indexOf("\t")
|
||||
var fileName = tab >= 0 ? line.slice(0, tab) : ""
|
||||
var json = tab >= 0 ? line.slice(tab + 1) : line
|
||||
try {
|
||||
var value = JSON.parse(line)
|
||||
var value = JSON.parse(json)
|
||||
if (!value || typeof value !== "object") continue
|
||||
entries.push({
|
||||
id: value.id || 0,
|
||||
fileName: fileName,
|
||||
app: value.app || "",
|
||||
summary: value.summary || "",
|
||||
body: value.body || "",
|
||||
|
||||
@@ -45,8 +45,9 @@ Item {
|
||||
}
|
||||
|
||||
function clearAll() {
|
||||
root.run("blob-shell notifications clearHistory")
|
||||
root.run("blob-shell notifications clear")
|
||||
root.entries = []
|
||||
refreshTimer.restart()
|
||||
}
|
||||
|
||||
function toggleSilence() {
|
||||
@@ -57,16 +58,19 @@ Item {
|
||||
function dismissEntry(index) {
|
||||
var entry = root.entries[index]
|
||||
if (!entry) return
|
||||
root.run("blob-notify-dismiss " + entry.id)
|
||||
root.run("blob-shell notifications remove " + Util.shellQuote(entry.fileName))
|
||||
var next = []
|
||||
for (var i = 0; i < root.entries.length; i++)
|
||||
if (i !== index) next.push(root.entries[i])
|
||||
root.entries = next
|
||||
refreshTimer.restart()
|
||||
}
|
||||
|
||||
Process {
|
||||
id: historyProbe
|
||||
command: ["bash", "-c", "cat " + root.historyDir + "/*.json 2>/dev/null || true"]
|
||||
command: ["bash", "-c",
|
||||
"for f in \"$1\"/*.json; do [[ -e $f ]] || continue; printf '%s\\t' \"${f##*/}\"; awk 1 \"$f\"; done",
|
||||
"--", root.historyDir]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.entries = HistoryModel.parseHistory(text)
|
||||
}
|
||||
@@ -139,13 +143,13 @@ Item {
|
||||
spacing: Style.spaceReal(4)
|
||||
|
||||
CardIconButton {
|
||||
icon: root.doNotDisturb ? "" : ""
|
||||
icon: root.doNotDisturb ? "\uf1f6" : "\uf0f3"
|
||||
active: root.doNotDisturb
|
||||
onActivated: root.toggleSilence()
|
||||
}
|
||||
|
||||
CardIconButton {
|
||||
icon: ""
|
||||
icon: "\uf1f8"
|
||||
onActivated: root.clearAll()
|
||||
}
|
||||
}
|
||||
@@ -177,7 +181,7 @@ Item {
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: ""
|
||||
text: "\uf0a2"
|
||||
textFormat: Text.PlainText
|
||||
color: Util.alpha(Color.blue, 0.6)
|
||||
font.family: Style.font.family
|
||||
|
||||
@@ -48,7 +48,7 @@ Rectangle {
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
text: ""
|
||||
text: "\uf00d"
|
||||
textFormat: Text.PlainText
|
||||
color: closeHover.hovered ? Color.urgent : Color.magenta
|
||||
font.family: Style.font.family
|
||||
|
||||
@@ -26,8 +26,8 @@ Item {
|
||||
readonly property string settingsPath: stateDir + "notifications.json"
|
||||
// One file per on-screen popup, so live toasts survive shell restarts.
|
||||
// A file exists exactly as long as its popup is showing: written when the
|
||||
// toast appears, moved into historyDir when it expires, is dismissed, or is
|
||||
// acted upon.
|
||||
// toast appears, moved into historyDir when it expires unseen, and deleted
|
||||
// when it is dismissed or acted upon.
|
||||
readonly property string popupStateDir: stateDir + "notifications/"
|
||||
// The notifications that already left the screen, one file each, trimmed to
|
||||
// the newest historyLimit. This directory IS the history: `showHistory`
|
||||
@@ -327,12 +327,14 @@ Item {
|
||||
// id would dismiss that unrelated notification at the server.
|
||||
var restored = isRestoredRow(entry)
|
||||
var ref = !restored && originalId >= 0 ? liveRefs[originalId] : null
|
||||
// The popup is leaving the screen — for any reason — so its file must not
|
||||
// survive to the next shell restart. It becomes the newest history entry
|
||||
// instead. Rows that never had a file (a history replay, the empty-history
|
||||
// placeholder) archive to nothing, which the move tolerates.
|
||||
// The popup is leaving the screen, so its file must not survive to the
|
||||
// next shell restart. An expired toast was missed and becomes the newest
|
||||
// history entry; a dismissed or acted-on one was seen and is deleted.
|
||||
// Rows that never had a file (a history replay, the empty-history
|
||||
// placeholder) archive or delete nothing, which both jobs tolerate.
|
||||
if (entry) {
|
||||
archivePopupFileFor(entry)
|
||||
if (reason === "expire") archivePopupFileFor(entry)
|
||||
else deletePopupFileFor(entry)
|
||||
if (restored) delete restoredPopups[NotificationLogic.popupFileName(entry)]
|
||||
}
|
||||
popupModel.remove(index)
|
||||
@@ -585,6 +587,15 @@ Item {
|
||||
enqueuePopupFileJob(command, done)
|
||||
}
|
||||
|
||||
function removeHistoryEntry(fileName) {
|
||||
var name = String(fileName || "")
|
||||
if (!/^[A-Za-z0-9._-]+\.json$/.test(name)) return false
|
||||
enqueuePopupFileJob(["bash", "-c",
|
||||
"rm -f \"$1/$2\" \"$3/${2%.json}\"-*", "--",
|
||||
historyDir, name, imagesDir])
|
||||
return true
|
||||
}
|
||||
|
||||
function clearHistory() {
|
||||
enqueuePopupFileJob(["bash", "-c",
|
||||
"for f in \"$1\"/*.json; do\n" +
|
||||
@@ -888,6 +899,10 @@ Item {
|
||||
return "ok"
|
||||
}
|
||||
|
||||
function remove(fileName: string): string {
|
||||
return service.removeHistoryEntry(fileName) ? "ok" : "none"
|
||||
}
|
||||
|
||||
function dismissAll(): string {
|
||||
service.clearPopups()
|
||||
return "ok"
|
||||
|
||||
Reference in new issue
Block a user