Show explicit choices on notification cards
This commit is contained in:
1 parent
35f8eef1bc
commit
036e501e58
4 files changed
+58
-2
No files matched your search
@@ -185,6 +185,12 @@ function snapshotOf(notification, timestamp) {
|
||||
var id = n.id || 0
|
||||
var expireTimeout = Number(n.expireTimeout || 0)
|
||||
if (!isFinite(expireTimeout) || expireTimeout < 0) expireTimeout = 0
|
||||
var actions = []
|
||||
for (var i = 0; n.actions && i < n.actions.length; i++) {
|
||||
var action = n.actions[i]
|
||||
if (action && action.identifier && action.identifier !== "default")
|
||||
actions.push({ identifier: String(action.identifier), text: String(action.text || action.identifier) })
|
||||
}
|
||||
return {
|
||||
id: id,
|
||||
originalId: id,
|
||||
@@ -195,6 +201,7 @@ function snapshotOf(notification, timestamp) {
|
||||
image: n.image || "",
|
||||
glyph: glyphFromHints(n.hints),
|
||||
execArgv: execArgvFromHints(n.hints),
|
||||
actionsJson: JSON.stringify(actions),
|
||||
// Pinyin's first-use cloud prediction question needs an explicit answer.
|
||||
// Its normal urgency otherwise dismisses it before users can read it.
|
||||
urgency: n.appName === "Pinyin" && n.appIcon === "fcitx-pinyin" ? 2 : n.urgency,
|
||||
@@ -205,7 +212,7 @@ function snapshotOf(notification, timestamp) {
|
||||
|
||||
// Everything the popup card draws, and therefore everything an in-place
|
||||
// update has to write through to the row and its file.
|
||||
var POPUP_ROLES = ["app", "appIcon", "summary", "body", "image", "glyph", "execArgv", "urgency", "expireTimeout"]
|
||||
var POPUP_ROLES = ["app", "appIcon", "summary", "body", "image", "glyph", "execArgv", "actionsJson", "urgency", "expireTimeout"]
|
||||
|
||||
function popupRoles() {
|
||||
return POPUP_ROLES
|
||||
@@ -265,6 +272,8 @@ function historyEntry(value, normalUrgency) {
|
||||
image: e.image || "",
|
||||
glyph: e.glyph || "",
|
||||
execArgv: e.execArgv || "",
|
||||
// Libnotify actions belong to a live sender; never replay stale buttons.
|
||||
actionsJson: "[]",
|
||||
urgency: typeof e.urgency === "number" ? e.urgency : normalUrgency,
|
||||
expireTimeout: 0,
|
||||
timestamp: e.timestamp || 0
|
||||
|
||||
@@ -235,7 +235,7 @@ Item {
|
||||
// about after the popup exists.
|
||||
readonly property var updateSignals: [
|
||||
"summaryChanged", "bodyChanged", "appNameChanged", "appIconChanged",
|
||||
"imageChanged", "urgencyChanged", "expireTimeoutChanged", "hintsChanged"
|
||||
"imageChanged", "urgencyChanged", "expireTimeoutChanged", "hintsChanged", "actionsChanged"
|
||||
]
|
||||
|
||||
// A client that updates a notification through replaces_id does not produce
|
||||
@@ -427,10 +427,26 @@ Item {
|
||||
// libnotify action — they just expect clicking the notification to
|
||||
// focus their window. Fall back to focusing the sending app by class so
|
||||
// that click-to-jump actually works.
|
||||
if (!invoked && entry.actionsJson && entry.actionsJson !== "[]") return
|
||||
if (!invoked) focusApp(entry)
|
||||
dismissPopup(index)
|
||||
}
|
||||
|
||||
function invokePopupAction(index, identifier) {
|
||||
if (index < 0 || index >= popupModel.count) return
|
||||
var entry = popupModel.get(index)
|
||||
var ref = entry && !isRestoredRow(entry) ? liveRefs[entry.originalId] : null
|
||||
if (!ref || !ref.actions) return
|
||||
for (var i = 0; i < ref.actions.length; i++) {
|
||||
var action = ref.actions[i]
|
||||
if (action && action.identifier === identifier) {
|
||||
action.invoke()
|
||||
dismissPopup(index)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to focus an existing Hyprland window matching the notification's
|
||||
// sender. The helper handles case-insensitive class matching.
|
||||
function focusApp(entry) {
|
||||
@@ -726,6 +742,7 @@ Item {
|
||||
image: "",
|
||||
glyph: "",
|
||||
execArgv: "",
|
||||
actionsJson: "[]",
|
||||
urgency: NotificationUrgency.Low,
|
||||
expireTimeout: 0,
|
||||
timestamp: Date.now()
|
||||
@@ -1044,6 +1061,7 @@ Item {
|
||||
required property string body
|
||||
required property string image
|
||||
required property string glyph
|
||||
required property string actionsJson
|
||||
required property int urgency
|
||||
required property double expireTimeout
|
||||
required property double timestamp
|
||||
@@ -1095,9 +1113,11 @@ Item {
|
||||
cornerRadius: service.cornerRadius
|
||||
fontFamily: service.shell && service.shell.bar ? service.shell.bar.fontFamily : ""
|
||||
glyph: cardSlot.glyph
|
||||
actions: JSON.parse(cardSlot.actionsJson || "[]")
|
||||
|
||||
onCloseRequested: service.dismissPopup(cardSlot.index)
|
||||
onCardClicked: service.invokePopupDefault(cardSlot.index)
|
||||
onActionClicked: identifier => service.invokePopupAction(cardSlot.index, identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ BorderSurface {
|
||||
property int urgency: 1
|
||||
property double timestamp: 0
|
||||
property int cornerRadius: 0
|
||||
property var actions: []
|
||||
|
||||
// System monospace font injected by the container.
|
||||
property string fontFamily: ""
|
||||
@@ -34,6 +35,7 @@ BorderSurface {
|
||||
|
||||
signal closeRequested()
|
||||
signal cardClicked()
|
||||
signal actionClicked(string identifier)
|
||||
// Prefer per-notification media/avatar data, then fall back to the app icon.
|
||||
// The `check` flag avoids Qt's missing-texture placeholder for unknown names.
|
||||
readonly property string smallIconSource: image.length > 0 ? image : iconSource(appIcon)
|
||||
@@ -193,6 +195,27 @@ BorderSurface {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.space(12)
|
||||
Layout.rightMargin: Style.space(12)
|
||||
Layout.bottomMargin: visible ? Style.space(10) : 0
|
||||
visible: root.actions.length > 0
|
||||
spacing: Style.space(8)
|
||||
|
||||
Repeater {
|
||||
model: root.actions
|
||||
delegate: Button {
|
||||
required property var modelData
|
||||
text: modelData.text
|
||||
bordered: true
|
||||
foreground: Color.notifications.text
|
||||
fontFamily: root.fontFamily
|
||||
onClicked: root.actionClicked(modelData.identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hover-revealed close. Stacked after mainColumn so its MouseArea sits
|
||||
|
||||
Reference in new issue
Block a user