Make desktop notifications follow push rules

This commit is contained in:
miruka 2020-11-03 07:29:32 -04:00
parent 2ef1edb3dc
commit 3dd12691b8
5 changed files with 78 additions and 63 deletions

View File

@ -4,17 +4,22 @@
- PCN error handling
- 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
- Implement fallback QML notifications, usable if dbus isn't available
- annoying tooltips when menu open
- profiles missing in notifications
- add http_proxy support
- image viewer: can't expand image in reduced window layout
- Encrypted rooms don't show invites in member list after Mirage restart
- Room display name not updated when someone removes theirs
- Fix right margin of own `<image url>\n<image url>` messages
- option to use plaintext notifications
- warn on ambiguously activated shortcut
- SSO device delete?

View File

@ -209,8 +209,7 @@ class MatrixClient(nio.AsyncClient):
self.unassigned_event_last_read_by: DefaultDict[str, Dict[str, int]] =\
DefaultDict(dict)
self.previous_server_unreads: Dict[str, int] = {}
self.previous_server_highlights: Dict[str, int] = {}
self.push_rules: nio.PushRulesEvent = nio.PushRulesEvent()
# {room_id: event}
self.power_level_events: Dict[str, nio.PowerLevelsEvent] = {}
@ -2247,55 +2246,52 @@ class MatrixClient(nio.AsyncClient):
await self.update_account_unread_counts()
return item
self.models[self.user_id, "rooms"][room.room_id].local_unreads = True
await self.update_account_unread_counts()
# 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 = \
room_item.unreads and \
room_item.unreads != \
self.previous_server_unreads.get(room.room_id, 0)
if not nio_rule:
return item
highlight = \
room_item.highlights and \
room_item.highlights != \
self.previous_server_highlights.get(room.room_id, 0)
model = self.models[self.user_id, "pushrules"]
rule = model[nio_rule.kind.value, nio_rule.id]
self.previous_server_unreads[room.room_id] = room_item.unreads
self.previous_server_highlights[room.room_id] = room_item.highlights
if not rule.notify and not rule.highlight:
return item
room_item.local_unreads = True
sender = item.sender_name or item.sender_id
if unread or highlight:
members = self.models[self.user_id, room.room_id, "members"]
room_name = room.display_name
sender = item.sender_name or item.sender_id
if isinstance(ev, nio.RoomMessageEmote):
body = f"<i>{sender} {item.inline_content}</i>"
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 "",
if isinstance(ev, nio.RoomMessageEmote):
body = f"<i>{sender} {item.inline_content}</i>"
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 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

View File

@ -839,6 +839,8 @@ class NioCallbacks:
urgency_hint = hint,
)
self.client.push_rules = ev
# Presence event callbacks

View File

@ -31,17 +31,22 @@ class PyOtherSideEvent:
@dataclass
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
flash the program's taskbar icon on Windows.
Urgency hints usually flash or highlight the program's icon in a taskbar,
dock or panel.
"""
id: str = field()
title: str = field()
body: str = ""
image: Union[Path, str] = ""
high_importance: bool = False
id: str = field()
critical: bool = False
bubble: bool = False
sound: bool = False
urgency_hint: bool = False
# Bubble parameters
title: str = ""
body: str = ""
image: Union[Path, str] = ""
@dataclass

View File

@ -8,26 +8,33 @@ import ".."
QtObject {
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
if (level === Window.NotificationLevel.None) return
if (level === Window.MentionsKeywords && ! highImportance) return
if (level === Window.MentionsKeywords && ! critical) return
if (window.notifiedIds.has(id)) return
window.notifiedIds.add(id)
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 =
highImportance ?
window.settings.Notifications.urgent_alert_time * 1000 :
window.settings.Notifications.alert_time * 1000
if (urgencyHint) {
const msec =
critical ?
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) {