Room context menu: notification setting checkmark

Indicate which notification override setting is currently active
This commit is contained in:
miruka 2021-02-28 09:52:51 -04:00
parent af321d8eae
commit 0017a1562c
4 changed files with 85 additions and 14 deletions

View File

@ -41,8 +41,8 @@ from .errors import (
from .html_markdown import HTML_PROCESSOR as HTML from .html_markdown import HTML_PROCESSOR as HTML
from .media_cache import Media, Thumbnail from .media_cache import Media, Thumbnail
from .models.items import ( from .models.items import (
ZERO_DATE, Account, Event, Member, PushRule, Room, Transfer, ZERO_DATE, Account, Event, Member, PushRule, Room,
TransferStatus, TypeSpecifier, RoomNotificationOverride, Transfer, TransferStatus, TypeSpecifier,
) )
from .models.model_store import ModelStore from .models.model_store import ModelStore
from .nio_callbacks import NioCallbacks from .nio_callbacks import NioCallbacks
@ -1919,13 +1919,25 @@ class MatrixClient(nio.AsyncClient):
await self.delete_pushrule("global", kind, rule_id) await self.delete_pushrule("global", kind, rule_id)
def _rule_overrides_room(self, rule: PushRule) -> Optional[str]:
override = rule.kind is nio.PushRuleKind.override
one_cnd = len(rule.conditions) == 1
if not one_cnd:
return None
cnd = nio.PushCondition.from_dict(rule.conditions[0])
ev_match = isinstance(cnd, nio.PushEventMatch)
if override and ev_match and cnd.key == "room_id":
return cnd.pattern
return None
async def _remove_room_override_rule(self, room_id: str) -> None: async def _remove_room_override_rule(self, room_id: str) -> None:
for rule in self.models[self.user_id, "pushrules"].values(): for rule in self.models[self.user_id, "pushrules"].values():
override_kind = rule.kind is nio.PushRuleKind.override if self._rule_overrides_room(rule) == room_id:
this_room_cnd = nio.PushEventMatch("room_id", room_id).as_value
if (override_kind and rule.conditions == [this_room_cnd]):
print(rule)
await self.remove_pushrule(rule.kind, rule.rule_id) await self.remove_pushrule(rule.kind, rule.rule_id)
@ -2015,7 +2027,6 @@ class MatrixClient(nio.AsyncClient):
) -> None: ) -> None:
"""Register/update a `nio.MatrixRoom` as a `models.items.Room`.""" """Register/update a `nio.MatrixRoom` as a `models.items.Room`."""
# Add room
inviter = getattr(room, "inviter", "") or "" inviter = getattr(room, "inviter", "") or ""
levels = room.power_levels levels = room.power_levels
can_send_state = partial(levels.can_user_send_state, self.user_id) can_send_state = partial(levels.can_user_send_state, self.user_id)
@ -2044,7 +2055,28 @@ class MatrixClient(nio.AsyncClient):
) )
unverified_devices = registered.unverified_devices unverified_devices = registered.unverified_devices
notification_setting = RoomNotificationOverride.UseDefaultSettings
for rule in self.models[self.user_id, "pushrules"].values():
overrides = self._rule_overrides_room(rule) == room.room_id
is_room_kind = rule.kind is nio.PushRuleKind.room
room_kind_match = is_room_kind and rule.rule_id == room.room_id
if overrides and not rule.actions:
notification_setting = RoomNotificationOverride.IgnoreEvents
break
elif overrides:
notification_setting = RoomNotificationOverride.AllEvents
break
elif room_kind_match and not rule.actions:
notification_setting = RoomNotificationOverride.HighlightsOnly
break
elif room_kind_match:
notification_setting = RoomNotificationOverride.AllEvents
break
pinned = self.backend.settings.RoomList.Pinned pinned = self.backend.settings.RoomList.Pinned
room_item = Room( room_item = Room(
id = room.room_id, id = room.room_id,
for_account = self.user_id, for_account = self.user_id,
@ -2085,9 +2117,10 @@ class MatrixClient(nio.AsyncClient):
last_event_date = last_event_date, last_event_date = last_event_date,
unreads = room.unread_notifications, unreads = room.unread_notifications,
highlights = room.unread_highlights, highlights = room.unread_highlights,
local_unreads = local_unreads, local_unreads = local_unreads,
notification_setting = notification_setting,
lexical_sorting = self.backend.settings.RoomList.lexical_sort, lexical_sorting = self.backend.settings.RoomList.lexical_sort,
pinned = room.room_id in pinned.get(self.user_id, []), pinned = room.room_id in pinned.get(self.user_id, []),

View File

@ -38,6 +38,16 @@ class PingStatus(AutoStrEnum):
Failed = auto() Failed = auto()
class RoomNotificationOverride(AutoStrEnum):
"""Possible per-room notification override settings, as displayed in the
left sidepane's context menu when right-clicking a room.
"""
UseDefaultSettings = auto()
AllEvents = auto()
HighlightsOnly = auto()
IgnoreEvents = auto()
@dataclass(eq=False) @dataclass(eq=False)
class Homeserver(ModelItem): class Homeserver(ModelItem):
"""A homeserver we can connect to. The `id` field is the server's URL.""" """A homeserver we can connect to. The `id` field is the server's URL."""
@ -170,6 +180,9 @@ class Room(ModelItem):
highlights: int = 0 highlights: int = 0
local_unreads: bool = False local_unreads: bool = False
notification_setting: RoomNotificationOverride = \
RoomNotificationOverride.UseDefaultSettings
lexical_sorting: bool = False lexical_sorting: bool = False
pinned: bool = False pinned: bool = False
@ -229,6 +242,12 @@ class Room(ModelItem):
@dataclass(eq=False) @dataclass(eq=False)
class AccountOrRoom(Account, Room): class AccountOrRoom(Account, Room):
"""The left sidepane in the GUI lists a mixture of accounts and rooms
giving a tree view illusion. Since all items in a QML ListView must have
the same available properties, this class inherits both
`Account` and `Room` to fulfill that purpose.
"""
type: Union[Type[Account], Type[Room]] = Account type: Union[Type[Account], Type[Room]] = Account
account_order: int = -1 account_order: int = -1

View File

@ -4,7 +4,7 @@
import asyncio import asyncio
import json import json
import logging as log import logging as log
from dataclasses import asdict, dataclass, field from dataclasses import dataclass, field
from datetime import datetime, timedelta from datetime import datetime, timedelta
from html import escape from html import escape
from pathlib import Path from pathlib import Path
@ -783,6 +783,18 @@ class NioCallbacks:
# Account data callbacks # Account data callbacks
async def onPushRulesEvent(self, ev: nio.PushRulesEvent) -> None: async def onPushRulesEvent(self, ev: nio.PushRulesEvent) -> None:
async def update_affected_room(rule: PushRule) -> None:
affects_room: Optional[str]
if rule.kind == nio.PushRuleKind.room:
affects_room = rule.rule_id
else:
affects_room = self.client._rule_overrides_room(rule)
if affects_room in self.client.rooms:
nio_room = self.client.rooms[affects_room]
await self.client.register_nio_room(nio_room)
model = self.models[self.user_id, "pushrules"] model = self.models[self.user_id, "pushrules"]
kinds: Dict[nio.PushRuleKind, List[nio.PushRule]] = { kinds: Dict[nio.PushRuleKind, List[nio.PushRule]] = {
@ -800,9 +812,10 @@ class NioCallbacks:
new_keys.add((kind.value, rule.id)) new_keys.add((kind.value, rule.id))
with model.batch_remove(): with model.batch_remove():
for key in tuple(model): for key, rule in list(model.items()):
if key not in new_keys: if key not in new_keys:
del model[key] del model[key]
await update_affected_room(rule)
# Then, add new rules/modify changed existing ones # Then, add new rules/modify changed existing ones
@ -825,7 +838,7 @@ class NioCallbacks:
sound = str(tweaks.get("sound") or "") sound = str(tweaks.get("sound") or "")
hint = tweaks.get("urgency_hint", bool(sound)) is not False hint = tweaks.get("urgency_hint", bool(sound)) is not False
model[kind.value, rule.id] = PushRule( rule_item = PushRule(
id = (kind.value, rule.id), id = (kind.value, rule.id),
kind = kind, kind = kind,
rule_id = rule.id, rule_id = rule.id,
@ -841,6 +854,8 @@ class NioCallbacks:
sound = sound, sound = sound,
urgency_hint = hint, urgency_hint = hint,
) )
model[kind.value, rule.id] = rule_item
await update_affected_room(rule_item)
self.client.push_rules = ev self.client.push_rules = ev

View File

@ -152,6 +152,7 @@ HTile {
HMenuItem { HMenuItem {
text: qsTr("Use default account settings") text: qsTr("Use default account settings")
checked: model.notification_setting === "UseDefaultSettings"
onTriggered: py.callClientCoro( onTriggered: py.callClientCoro(
model.for_account, "room_pushrule_use_default", [model.id], model.for_account, "room_pushrule_use_default", [model.id],
) )
@ -159,6 +160,7 @@ HTile {
HMenuItem { HMenuItem {
text: qsTr("All new messages") text: qsTr("All new messages")
checked: model.notification_setting === "AllEvents"
onTriggered: py.callClientCoro( onTriggered: py.callClientCoro(
model.for_account, "room_pushrule_all_events", [model.id], model.for_account, "room_pushrule_all_events", [model.id],
) )
@ -166,6 +168,7 @@ HTile {
HMenuItem { HMenuItem {
text: qsTr("Highlights only (replies, keywords...)") text: qsTr("Highlights only (replies, keywords...)")
checked: model.notification_setting === "HighlightsOnly"
onTriggered: py.callClientCoro( onTriggered: py.callClientCoro(
model.for_account, model.for_account,
"room_pushrule_highlights_only", "room_pushrule_highlights_only",
@ -175,6 +178,7 @@ HTile {
HMenuItem { HMenuItem {
text: qsTr("Ignore new messages") text: qsTr("Ignore new messages")
checked: model.notification_setting === "IgnoreEvents"
onTriggered: py.callClientCoro( onTriggered: py.callClientCoro(
model.for_account, "room_pushrule_ignore_all", [model.id], model.for_account, "room_pushrule_ignore_all", [model.id],
) )