notifications: Replace existing notifications
This commit is contained in:
parent
1aaa1c8160
commit
2c8ce1b038
|
|
@ -172,6 +172,19 @@ class DBusNotificationPresenter(QObject):
|
|||
f"Got a message of type {type_str} but expected {expected_type_str}"
|
||||
f"(args: {message.arguments()})")
|
||||
|
||||
def _find_matching_id(self, new_notification: "QWebEngineNotification") -> int:
|
||||
"""Find an existing notification to replace.
|
||||
|
||||
If no notification should be replaced or the notification to be replaced was not
|
||||
found, this returns 0 (as per the notification spec).
|
||||
"""
|
||||
if not new_notification.tag():
|
||||
return 0
|
||||
for notification_id, notification in self._active_notifications.items():
|
||||
if notification.matches(new_notification):
|
||||
return notification_id
|
||||
return 0
|
||||
|
||||
def _present(self, qt_notification: "QWebEngineNotification") -> None:
|
||||
"""Shows a notification over DBus.
|
||||
|
||||
|
|
@ -184,10 +197,10 @@ class DBusNotificationPresenter(QObject):
|
|||
self._fetch_capabilities()
|
||||
assert self._capabilities is not None
|
||||
|
||||
# notification id 0 means 'assign us the ID'. We can't just pass 0
|
||||
# because it won't get sent as the right type.
|
||||
zero = QVariant(0)
|
||||
zero.convert(QVariant.UInt)
|
||||
# We can't just pass the int because it won't get sent as the right type.
|
||||
existing_id = self._find_matching_id(qt_notification)
|
||||
existing_id_arg = QVariant(existing_id)
|
||||
existing_id_arg.convert(QVariant.UInt)
|
||||
|
||||
actions = []
|
||||
if 'actions' in self._capabilities:
|
||||
|
|
@ -208,7 +221,7 @@ class DBusNotificationPresenter(QObject):
|
|||
QDBus.BlockWithGui,
|
||||
"Notify",
|
||||
"qutebrowser", # application name
|
||||
zero, # replaces notification id
|
||||
existing_id_arg, # replaces notification id
|
||||
"qutebrowser", # icon (freedesktop.org icon theme name)
|
||||
# Titles don't support markup, so no need to escape them.
|
||||
qt_notification.title(),
|
||||
|
|
@ -220,6 +233,12 @@ class DBusNotificationPresenter(QObject):
|
|||
self._verify_message(reply, "u", QDBusMessage.ReplyMessage)
|
||||
|
||||
notification_id = reply.arguments()[0]
|
||||
if existing_id != 0 and notification_id != existing_id:
|
||||
raise DBusException(f"Wanted to replace notification {existing_id} but got "
|
||||
f"new id {notification_id}.")
|
||||
if notification_id == 0:
|
||||
raise DBusException("Got invalid notification id 0")
|
||||
|
||||
self._active_notifications[notification_id] = qt_notification
|
||||
log.webview.debug(f"Sent out notification {notification_id}")
|
||||
|
||||
|
|
|
|||
|
|
@ -46,11 +46,19 @@
|
|||
let notification = new Notification(str, { body: str });
|
||||
notification.onshow = function() { console.log("notification shown"); };
|
||||
}
|
||||
|
||||
function show_multiple_notifications() {
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
let notification = new Notification(`i=${i}`, { tag: 'counter' });
|
||||
notification.onshow = function() { console.log(`i=${i} notification shown`); };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<input type="button" onclick="get_notification_permission()" value="Get notification permission" id="button">
|
||||
<input type="button" onclick="show_notification()" value="Show notification" id="show-button">
|
||||
<input type="button" onclick="show_symbol_notification()" value="Show notification with symbols" id="show-symbols-button">
|
||||
<input type="button" onclick="show_multiple_notifications()" value="Show multiple notifications" id="show-multiple-button">
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,15 @@ Feature: Notifications
|
|||
Then the javascript message "notification shown" should be logged
|
||||
And a notification with id 1 is presented
|
||||
|
||||
@qtwebengine_notifications
|
||||
Scenario: Replacing existing notifications
|
||||
When I run :click-element id show-multiple-button
|
||||
Then the javascript message "i=1 notification shown" should be logged
|
||||
Then the javascript message "i=2 notification shown" should be logged
|
||||
Then the javascript message "i=3 notification shown" should be logged
|
||||
And 1 notification is presented
|
||||
And notification 1 has title "i=3"
|
||||
|
||||
@qtwebengine_notifications
|
||||
Scenario: Notification containing escaped characters
|
||||
Given the notification server supports body markup
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ def notification_presented(notification_server, id_):
|
|||
assert id_ in notification_server.messages
|
||||
|
||||
|
||||
@bdd.then('1 notification is presented')
|
||||
def notification_presented_single(notification_server):
|
||||
assert len(notification_server.messages) == 1
|
||||
|
||||
|
||||
@bdd.then(bdd.parsers.cfparse('notification {id_:d} has body "{body}"'))
|
||||
def notification_body(notification_server, id_, body):
|
||||
assert notification_server.messages[id_].body == body
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class NotificationProperties:
|
|||
|
||||
title: str
|
||||
body: str
|
||||
replaces_id: int
|
||||
|
||||
|
||||
def _as_uint32(x: int) -> QVariant:
|
||||
|
|
@ -92,7 +93,6 @@ class TestNotificationServer(QObject):
|
|||
values being checked inside test cases.
|
||||
"""
|
||||
assert appname == "qutebrowser"
|
||||
assert replaces_id == 0
|
||||
assert icon == "qutebrowser"
|
||||
assert actions == ['default', '']
|
||||
assert timeout == -1
|
||||
|
|
@ -101,7 +101,10 @@ class TestNotificationServer(QObject):
|
|||
assert hints['x-qutebrowser-origin'].startswith('http://localhost:')
|
||||
assert hints['desktop-entry'] == 'org.qutebrowser.qutebrowser'
|
||||
|
||||
return NotificationProperties(title=title, body=body)
|
||||
if replaces_id != 0:
|
||||
assert replaces_id in self.messages
|
||||
|
||||
return NotificationProperties(title=title, body=body, replaces_id=replaces_id)
|
||||
|
||||
def close(self, notification_id: int) -> None:
|
||||
"""Sends a close notification for the given ID."""
|
||||
|
|
@ -131,12 +134,18 @@ class TestNotificationServer(QObject):
|
|||
# pylint: disable=invalid-name
|
||||
|
||||
@pyqtSlot(QDBusMessage, result="uint")
|
||||
def Notify(self, message: QDBusMessage) -> QDBusArgument:
|
||||
assert message.signature() == 'susssasa{sv}i'
|
||||
assert message.type() == QDBusMessage.MethodCallMessage
|
||||
def Notify(self, dbus_message: QDBusMessage) -> QDBusArgument:
|
||||
assert dbus_message.signature() == 'susssasa{sv}i'
|
||||
assert dbus_message.type() == QDBusMessage.MethodCallMessage
|
||||
|
||||
message = self._parse_notify_args(*dbus_message.arguments())
|
||||
|
||||
if message.replaces_id == 0:
|
||||
message_id = next(self._message_id_gen)
|
||||
else:
|
||||
message_id = message.replaces_id
|
||||
self.messages[message_id] = message
|
||||
|
||||
message_id = next(self._message_id_gen)
|
||||
self.messages[message_id] = self._parse_notify_args(*message.arguments())
|
||||
return message_id
|
||||
|
||||
@pyqtSlot(QDBusMessage, result="QStringList")
|
||||
|
|
|
|||
Loading…
Reference in New Issue