Make desktop notifications follow push rules
This commit is contained in:
parent
2ef1edb3dc
commit
3dd12691b8
|
@ -4,17 +4,22 @@
|
||||||
- PCN error handling
|
- PCN error handling
|
||||||
- Change docs linking to dev branch back to master
|
- Change docs linking to dev branch back to master
|
||||||
|
|
||||||
|
- Implement fallback QML notifications, usable if dbus isn't available
|
||||||
|
- profiles missing in notifications
|
||||||
|
- option to use plaintext notifications
|
||||||
|
- Notification urgency level (plyer)?
|
||||||
|
- Rename the alertOn(Mention/Message)ForMsec options, default Message to non-0
|
||||||
|
- Make local unread counter an optional turned off by default
|
||||||
|
|
||||||
- fix DeviceSection padding
|
- fix DeviceSection padding
|
||||||
- Implement fallback QML notifications, usable if dbus isn't available
|
- Implement fallback QML notifications, usable if dbus isn't available
|
||||||
- annoying tooltips when menu open
|
- annoying tooltips when menu open
|
||||||
- profiles missing in notifications
|
|
||||||
|
|
||||||
- add http_proxy support
|
- add http_proxy support
|
||||||
- image viewer: can't expand image in reduced window layout
|
- image viewer: can't expand image in reduced window layout
|
||||||
- Encrypted rooms don't show invites in member list after Mirage restart
|
- Encrypted rooms don't show invites in member list after Mirage restart
|
||||||
- Room display name not updated when someone removes theirs
|
- Room display name not updated when someone removes theirs
|
||||||
- Fix right margin of own `<image url>\n<image url>` messages
|
- Fix right margin of own `<image url>\n<image url>` messages
|
||||||
- option to use plaintext notifications
|
|
||||||
- warn on ambiguously activated shortcut
|
- warn on ambiguously activated shortcut
|
||||||
|
|
||||||
- SSO device delete?
|
- SSO device delete?
|
||||||
|
|
|
@ -209,8 +209,7 @@ class MatrixClient(nio.AsyncClient):
|
||||||
self.unassigned_event_last_read_by: DefaultDict[str, Dict[str, int]] =\
|
self.unassigned_event_last_read_by: DefaultDict[str, Dict[str, int]] =\
|
||||||
DefaultDict(dict)
|
DefaultDict(dict)
|
||||||
|
|
||||||
self.previous_server_unreads: Dict[str, int] = {}
|
self.push_rules: nio.PushRulesEvent = nio.PushRulesEvent()
|
||||||
self.previous_server_highlights: Dict[str, int] = {}
|
|
||||||
|
|
||||||
# {room_id: event}
|
# {room_id: event}
|
||||||
self.power_level_events: Dict[str, nio.PowerLevelsEvent] = {}
|
self.power_level_events: Dict[str, nio.PowerLevelsEvent] = {}
|
||||||
|
@ -2247,55 +2246,52 @@ class MatrixClient(nio.AsyncClient):
|
||||||
await self.update_account_unread_counts()
|
await self.update_account_unread_counts()
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
self.models[self.user_id, "rooms"][room.room_id].local_unreads = True
|
||||||
|
await self.update_account_unread_counts()
|
||||||
|
|
||||||
# Alerts & notifications
|
# Alerts & notifications
|
||||||
|
|
||||||
room_item = self.models[self.user_id, "rooms"][room.room_id]
|
name = self.models["accounts"][self.user_id].display_name
|
||||||
|
nio_rule = self.push_rules.global_rules.matching_rule(ev, room, name)
|
||||||
|
|
||||||
unread = \
|
if not nio_rule:
|
||||||
room_item.unreads and \
|
return item
|
||||||
room_item.unreads != \
|
|
||||||
self.previous_server_unreads.get(room.room_id, 0)
|
|
||||||
|
|
||||||
highlight = \
|
model = self.models[self.user_id, "pushrules"]
|
||||||
room_item.highlights and \
|
rule = model[nio_rule.kind.value, nio_rule.id]
|
||||||
room_item.highlights != \
|
|
||||||
self.previous_server_highlights.get(room.room_id, 0)
|
|
||||||
|
|
||||||
self.previous_server_unreads[room.room_id] = room_item.unreads
|
if not rule.notify and not rule.highlight:
|
||||||
self.previous_server_highlights[room.room_id] = room_item.highlights
|
return item
|
||||||
|
|
||||||
room_item.local_unreads = True
|
sender = item.sender_name or item.sender_id
|
||||||
|
|
||||||
if unread or highlight:
|
if isinstance(ev, nio.RoomMessageEmote):
|
||||||
members = self.models[self.user_id, room.room_id, "members"]
|
body = f"<i>{sender} {item.inline_content}</i>"
|
||||||
room_name = room.display_name
|
elif not isinstance(ev, nio.RoomMessage):
|
||||||
sender = item.sender_name or item.sender_id
|
body = item.inline_content.replace(
|
||||||
|
"%1", item.sender_name or item.sender_id,
|
||||||
if isinstance(ev, nio.RoomMessageEmote):
|
).replace(
|
||||||
body = f"<i>{sender} {item.inline_content}</i>"
|
"%2", item.target_name or item.target_id,
|
||||||
elif not isinstance(ev, nio.RoomMessage):
|
|
||||||
body = item.inline_content.replace(
|
|
||||||
"%1", item.sender_name or item.sender_id,
|
|
||||||
).replace(
|
|
||||||
"%2", item.target_name or item.target_id,
|
|
||||||
)
|
|
||||||
elif len(members) == 2 and room_name == sender:
|
|
||||||
body = item.inline_content
|
|
||||||
else:
|
|
||||||
body = f"{sender}: {item.inline_content}"
|
|
||||||
|
|
||||||
NotificationRequested(
|
|
||||||
id = item.id,
|
|
||||||
high_importance = highlight,
|
|
||||||
title = room_name,
|
|
||||||
|
|
||||||
body = body.replace(" ⏎ ", "<br>")
|
|
||||||
.replace(" ⏎⏎ ", f"<br>{'─' * 24}<br>"),
|
|
||||||
|
|
||||||
image = await self.get_notification_avatar(
|
|
||||||
mxc=item.sender_avatar, user_id=item.sender_id,
|
|
||||||
) if item.sender_avatar else "",
|
|
||||||
)
|
)
|
||||||
|
elif room.member_count == 2 and room.display_name == sender:
|
||||||
|
body = item.inline_content
|
||||||
|
else:
|
||||||
|
body = f"{sender}: {item.inline_content}"
|
||||||
|
|
||||||
|
NotificationRequested(
|
||||||
|
id = item.id,
|
||||||
|
critical = rule.highlight,
|
||||||
|
bubble = rule.bubble,
|
||||||
|
sound = rule.sound,
|
||||||
|
urgency_hint = rule.urgency_hint,
|
||||||
|
|
||||||
|
title = room.display_name,
|
||||||
|
body = body.replace(" ⏎ ", "<br>")
|
||||||
|
.replace(" ⏎⏎ ", f"<br>{'─' * 24}<br>"),
|
||||||
|
|
||||||
|
image = await self.get_notification_avatar(
|
||||||
|
mxc=item.sender_avatar, user_id=item.sender_id,
|
||||||
|
) if item.sender_avatar else "",
|
||||||
|
)
|
||||||
|
|
||||||
await self.update_account_unread_counts()
|
|
||||||
return item
|
return item
|
||||||
|
|
|
@ -839,6 +839,8 @@ class NioCallbacks:
|
||||||
urgency_hint = hint,
|
urgency_hint = hint,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.client.push_rules = ev
|
||||||
|
|
||||||
|
|
||||||
# Presence event callbacks
|
# Presence event callbacks
|
||||||
|
|
||||||
|
|
|
@ -31,17 +31,22 @@ class PyOtherSideEvent:
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class NotificationRequested(PyOtherSideEvent):
|
class NotificationRequested(PyOtherSideEvent):
|
||||||
"""Request a notification and window manager alert to be shown.
|
"""Request a notification bubble, sound or window urgency hint.
|
||||||
|
|
||||||
Alerts set the urgency hint for compliant X11/Wayland window managers or
|
Urgency hints usually flash or highlight the program's icon in a taskbar,
|
||||||
flash the program's taskbar icon on Windows.
|
dock or panel.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: str = field()
|
id: str = field()
|
||||||
title: str = field()
|
critical: bool = False
|
||||||
body: str = ""
|
bubble: bool = False
|
||||||
image: Union[Path, str] = ""
|
sound: bool = False
|
||||||
high_importance: bool = False
|
urgency_hint: bool = False
|
||||||
|
|
||||||
|
# Bubble parameters
|
||||||
|
title: str = ""
|
||||||
|
body: str = ""
|
||||||
|
image: Union[Path, str] = ""
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
|
@ -8,26 +8,33 @@ import ".."
|
||||||
QtObject {
|
QtObject {
|
||||||
signal deviceUpdateSignal(string forAccount)
|
signal deviceUpdateSignal(string forAccount)
|
||||||
|
|
||||||
function onNotificationRequested(id, title, body, image, highImportance) {
|
function onNotificationRequested(
|
||||||
|
id, critical, bubble, sound, urgencyHint, title, body, image,
|
||||||
|
) {
|
||||||
const level = window.notificationLevel
|
const level = window.notificationLevel
|
||||||
|
|
||||||
if (level === Window.NotificationLevel.None) return
|
if (level === Window.NotificationLevel.None) return
|
||||||
if (level === Window.MentionsKeywords && ! highImportance) return
|
if (level === Window.MentionsKeywords && ! critical) return
|
||||||
if (window.notifiedIds.has(id)) return
|
if (window.notifiedIds.has(id)) return
|
||||||
|
|
||||||
window.notifiedIds.add(id)
|
window.notifiedIds.add(id)
|
||||||
window.notifiedIdsChanged()
|
window.notifiedIdsChanged()
|
||||||
|
|
||||||
if (Qt.application.state === Qt.ApplicationActive) return
|
if (Qt.application.state === Qt.ApplicationActive)
|
||||||
|
return
|
||||||
|
|
||||||
py.callCoro("desktop_notify", [title, body, image])
|
if (bubble)
|
||||||
|
py.callCoro("desktop_notify", [title, body, image])
|
||||||
|
|
||||||
const msec =
|
if (urgencyHint) {
|
||||||
highImportance ?
|
const msec =
|
||||||
window.settings.Notifications.urgent_alert_time * 1000 :
|
critical ?
|
||||||
window.settings.Notifications.alert_time * 1000
|
window.settings.Notifications.urgent_alert_time * 1000 :
|
||||||
|
window.settings.Notifications.alert_time * 1000
|
||||||
|
|
||||||
if (msec) window.alert(msec === -1 ? 0 : msec) // -1 → 0 = no time out
|
// -1 ? 0 for no time out : msec
|
||||||
|
if (msec !== 0) window.alert(msec === -1 ? 0 : msec)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCoroutineDone(uuid, result, error, traceback) {
|
function onCoroutineDone(uuid, result, error, traceback) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user