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:
vslg 2020-07-09 20:53:25 -03:00 committed by miruka
parent a3c9ac20c6
commit 43df8fd60b
6 changed files with 94 additions and 60 deletions

View File

@ -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)

View File

@ -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(),
)

View File

@ -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()

View File

@ -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 {

View File

@ -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

View File

@ -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
)
)
}
}
}