Bug fix and minor improvements
Improvements: - Add instant feedback upon setting a different presence for account (local echo) - Sort room members by power level and then presence - Periodically update members' `last_acitve_at` field on the room pane - Move status message field up on account context menu, and put invisible before offline again Bug fix: - Do not try to override presence set from another client, accept it
This commit is contained in:
parent
a3c9ac20c6
commit
43df8fd60b
@ -400,7 +400,7 @@ class MatrixClient(nio.AsyncClient):
|
||||
presence = self.backend.presences.get(self.user_id, None)
|
||||
|
||||
if presence:
|
||||
presence.members.pop(("account", self.user_id), None)
|
||||
presence.account = None
|
||||
|
||||
|
||||
async def update_own_profile(self) -> None:
|
||||
@ -1315,10 +1315,11 @@ class MatrixClient(nio.AsyncClient):
|
||||
account.connecting = True
|
||||
self.start_task = asyncio.ensure_future(self._start())
|
||||
|
||||
# Assign invisible on model in here, because server will tell us we are
|
||||
# offline
|
||||
if presence == "invisible":
|
||||
account.presence = Presence.State.invisible
|
||||
if (
|
||||
presence != "offline" and
|
||||
Presence.State(presence) != account.presence
|
||||
):
|
||||
account.presence = Presence.State("echo_" + presence)
|
||||
|
||||
if not account.presence_support:
|
||||
account.presence = Presence.State(presence)
|
||||
|
@ -10,7 +10,6 @@ from typing import Any, Dict, List, Optional, Tuple, Type, Union
|
||||
from uuid import UUID
|
||||
|
||||
import lxml # nosec
|
||||
|
||||
import nio
|
||||
|
||||
from ..utils import AutoStrEnum, auto
|
||||
@ -20,7 +19,6 @@ ZeroDate = datetime.fromtimestamp(0)
|
||||
OptionalExceptionType = Union[Type[None], Type[Exception]]
|
||||
|
||||
|
||||
|
||||
class TypeSpecifier(AutoStrEnum):
|
||||
"""Enum providing clarification of purpose for some matrix events."""
|
||||
|
||||
@ -37,6 +35,10 @@ class Presence():
|
||||
online = auto()
|
||||
invisible = auto()
|
||||
|
||||
echo_unavailable = auto()
|
||||
echo_online = auto()
|
||||
echo_invisible = auto()
|
||||
|
||||
def __lt__(self, other: "Presence.State") -> bool:
|
||||
order = [
|
||||
self.online,
|
||||
@ -53,7 +55,7 @@ class Presence():
|
||||
|
||||
presence: State = State.offline
|
||||
currently_active: bool = False
|
||||
last_active_ago: int = -1
|
||||
last_active_at: datetime = ZeroDate
|
||||
status_msg: str = ""
|
||||
|
||||
members: Dict[Tuple[str, str], "Member"] = field(default_factory=dict)
|
||||
@ -63,7 +65,7 @@ class Presence():
|
||||
for member in self.members.values():
|
||||
member.presence = self.presence
|
||||
member.status_msg = self.status_msg
|
||||
member.last_active_ago = self.last_active_ago
|
||||
member.last_active_at = self.last_active_at
|
||||
member.currently_active = self.currently_active
|
||||
|
||||
def update_account(self) -> None:
|
||||
@ -73,14 +75,16 @@ class Presence():
|
||||
# account presence to offline.
|
||||
if (
|
||||
not self.account or
|
||||
self.account.presence == self.State.invisible and
|
||||
self.presence == self.State.offline
|
||||
self.presence == self.State.offline and
|
||||
self.account.presence != self.State.echo_invisible
|
||||
):
|
||||
return
|
||||
|
||||
self.account.presence = self.presence
|
||||
self.account.presence = self.presence if (
|
||||
self.account.presence != self.State.echo_invisible
|
||||
) else self.State.invisible
|
||||
self.account.status_msg = self.status_msg
|
||||
self.account.last_active_ago = self.last_active_ago
|
||||
self.account.last_active_at = self.last_active_at
|
||||
self.account.currently_active = self.currently_active
|
||||
|
||||
|
||||
@ -105,7 +109,7 @@ class Account(ModelItem):
|
||||
presence_support: bool = False
|
||||
presence: Presence.State = Presence.State.offline
|
||||
currently_active: bool = False
|
||||
last_active_ago: int = -1
|
||||
last_active_at: datetime = ZeroDate
|
||||
status_msg: str = ""
|
||||
|
||||
def __lt__(self, other: "Account") -> bool:
|
||||
@ -242,7 +246,7 @@ class Member(ModelItem):
|
||||
|
||||
presence: Presence.State = Presence.State.offline
|
||||
currently_active: bool = False
|
||||
last_active_ago: int = -1
|
||||
last_active_at: datetime = ZeroDate
|
||||
status_msg: str = ""
|
||||
|
||||
def __lt__(self, other: "Member") -> bool:
|
||||
@ -252,14 +256,14 @@ class Member(ModelItem):
|
||||
other_name = other.display_name or other.id[1:]
|
||||
|
||||
return (
|
||||
self.presence,
|
||||
self.invited,
|
||||
other.power_level,
|
||||
self.presence,
|
||||
name.lower(),
|
||||
) < (
|
||||
other.presence,
|
||||
other.invited,
|
||||
self.power_level,
|
||||
other.presence,
|
||||
other_name.lower(),
|
||||
)
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
import json
|
||||
import logging as log
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from html import escape
|
||||
from typing import TYPE_CHECKING, Optional, Tuple
|
||||
from urllib.parse import quote
|
||||
@ -596,7 +596,9 @@ class NioCallbacks:
|
||||
presence.status_msg = ev.status_msg or ""
|
||||
presence.presence = Presence.State(ev.presence) if ev.presence\
|
||||
else Presence.State.offline
|
||||
presence.last_active_ago = ev.last_active_ago or -1
|
||||
presence.last_active_at = (
|
||||
datetime.now() - timedelta(milliseconds=ev.last_active_ago)
|
||||
) if ev.last_active_ago else datetime.fromtimestamp(0)
|
||||
presence.currently_active = ev.currently_active or False
|
||||
|
||||
# Add all existing members related to this presence
|
||||
@ -614,17 +616,26 @@ class NioCallbacks:
|
||||
# Check if presence event is ours
|
||||
if (
|
||||
ev.user_id in self.models["accounts"] and
|
||||
presence.presence != Presence.State.offline
|
||||
not (
|
||||
presence.presence == Presence.State.offline and
|
||||
self.models["accounts"][ev.user_id].presence !=
|
||||
Presence.State.echo_invisible
|
||||
)
|
||||
):
|
||||
account = self.models["accounts"][ev.user_id]
|
||||
|
||||
# Do not fight back presence
|
||||
self.client.backend.clients[ev.user_id]._presence = ev.presence
|
||||
|
||||
# Servers that send presence events support presence
|
||||
account.presence_support = True
|
||||
|
||||
# Save the presence for the next resume
|
||||
await self.client.backend.saved_accounts.update(
|
||||
user_id = ev.user_id,
|
||||
presence = presence.presence.value,
|
||||
presence = presence.presence.value if (
|
||||
account.presence != Presence.State.echo_invisible
|
||||
) else "invisible",
|
||||
)
|
||||
|
||||
presence.update_account()
|
||||
|
@ -71,12 +71,13 @@ HAvatar {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
radius: diameter / 2
|
||||
opacity: presence.includes("echo") ? 0.4 : 1
|
||||
|
||||
color:
|
||||
presence === "online" ?
|
||||
presence.includes("online") ?
|
||||
theme.controls.presence.online :
|
||||
|
||||
presence === "unavailable" ?
|
||||
presence.includes("unavailable") ?
|
||||
theme.controls.presence.unavailable :
|
||||
|
||||
theme.controls.presence.offline
|
||||
@ -84,6 +85,9 @@ HAvatar {
|
||||
border.color: theme.controls.presence.border
|
||||
border.width: diameter / 10
|
||||
|
||||
Behavior on color { HColorAnimation {} }
|
||||
Behavior on opacity { HNumberAnimation {} }
|
||||
|
||||
HoverHandler { id: presenceHover }
|
||||
|
||||
HToolTip {
|
||||
|
@ -21,38 +21,6 @@ HMenu {
|
||||
}
|
||||
|
||||
|
||||
HMenuItem {
|
||||
icon.name: "presence"
|
||||
icon.color: theme.controls.presence.online
|
||||
text: qsTr("Online")
|
||||
onTriggered: setPresence("online")
|
||||
}
|
||||
|
||||
HMenuItem {
|
||||
enabled: presence
|
||||
icon.name: "presence-busy"
|
||||
icon.color: theme.controls.presence.unavailable
|
||||
text: qsTr("Unavailable")
|
||||
onTriggered: setPresence("unavailable")
|
||||
}
|
||||
|
||||
HMenuItem {
|
||||
icon.name: "presence-offline"
|
||||
icon.color: theme.controls.presence.offline
|
||||
text: qsTr("Offline")
|
||||
onTriggered: setPresence("offline")
|
||||
}
|
||||
|
||||
HMenuItem {
|
||||
enabled: presence
|
||||
icon.name: "presence-invisible"
|
||||
icon.color: theme.controls.presence.offline
|
||||
text: qsTr("Invisible")
|
||||
onTriggered: setPresence("invisible")
|
||||
}
|
||||
|
||||
HMenuSeparator { }
|
||||
|
||||
HLabeledItem {
|
||||
id: statusMsgLabel
|
||||
enabled: presence && presence !== "offline"
|
||||
@ -95,6 +63,38 @@ HMenu {
|
||||
}
|
||||
}
|
||||
|
||||
HMenuSeparator { }
|
||||
|
||||
HMenuItem {
|
||||
icon.name: "presence"
|
||||
icon.color: theme.controls.presence.online
|
||||
text: qsTr("Online")
|
||||
onTriggered: setPresence("online")
|
||||
}
|
||||
|
||||
HMenuItem {
|
||||
enabled: presence
|
||||
icon.name: "presence-busy"
|
||||
icon.color: theme.controls.presence.unavailable
|
||||
text: qsTr("Unavailable")
|
||||
onTriggered: setPresence("unavailable")
|
||||
}
|
||||
|
||||
HMenuItem {
|
||||
enabled: presence
|
||||
icon.name: "presence-invisible"
|
||||
icon.color: theme.controls.presence.offline
|
||||
text: qsTr("Invisible")
|
||||
onTriggered: setPresence("invisible")
|
||||
}
|
||||
|
||||
HMenuItem {
|
||||
icon.name: "presence-offline"
|
||||
icon.color: theme.controls.presence.offline
|
||||
text: qsTr("Offline")
|
||||
onTriggered: setPresence("offline")
|
||||
}
|
||||
|
||||
HMenuSeparator {
|
||||
visible: statusMsgLabel.visible
|
||||
height: visible ? implicitHeight : 0
|
||||
|
@ -44,11 +44,25 @@ HTile {
|
||||
|
||||
TitleRightInfoLabel {
|
||||
tile: member
|
||||
text:
|
||||
model.presence !== "online" &&
|
||||
model.last_active_ago !== -1 ?
|
||||
utils.formatRelativeTime(model.last_active_ago) :
|
||||
""
|
||||
visible: presenceTimer.running
|
||||
|
||||
Timer {
|
||||
id: presenceTimer
|
||||
running:
|
||||
! model.currently_active &&
|
||||
model.last_active_at > new Date(1)
|
||||
repeat: true
|
||||
interval:
|
||||
new Date() - model.last_active_at < 60000 ?
|
||||
10000 :
|
||||
60000
|
||||
triggeredOnStart: true
|
||||
onTriggered: parent.text = Qt.binding(() =>
|
||||
utils.formatRelativeTime(
|
||||
new Date() - model.last_active_at
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user