Display room messages and other events

This commit is contained in:
miruka
2019-04-14 12:56:30 -04:00
parent 5c8fd4500d
commit 9c66166c4f
16 changed files with 340 additions and 110 deletions

View File

@@ -2,10 +2,12 @@
# This file is part of harmonyqml, licensed under GPLv3.
import hashlib
from typing import Dict
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
from .client_manager import ClientManager
from .model.items import User
from .model.qml_models import QMLModels
@@ -35,6 +37,18 @@ class Backend(QObject):
return self._models
@pyqtSlot(str, result="QVariantMap")
def getUser(self, user_id: str) -> Dict[str, str]:
for client in self.clientManager.clients.values():
for room in client.nio.rooms.values():
name = room.user_name(user_id)
if name:
return User(user_id=user_id, display_name=name)._asdict()
return User(user_id=user_id, display_name=user_id)._asdict()
@pyqtSlot(str, result=float)
def hueFromString(self, string: str) -> float:
# pylint:disable=no-self-use

View File

@@ -7,15 +7,13 @@ import sys
import traceback
from concurrent.futures import Future, ThreadPoolExecutor
from threading import Event, currentThread
from typing import Callable, DefaultDict, Dict
from typing import Callable, DefaultDict
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
import nio
import nio.responses as nr
from .model.items import User
# One pool per hostname/remote server;
# multiple Client for different accounts on the same server can exist.
_POOLS: DefaultDict[str, ThreadPoolExecutor] = \
@@ -39,9 +37,10 @@ def futurize(func: Callable) -> Callable:
class Client(QObject):
roomInvited = pyqtSignal(str)
roomJoined = pyqtSignal(str)
roomLeft = pyqtSignal(str)
roomInvited = pyqtSignal(str)
roomJoined = pyqtSignal(str)
roomLeft = pyqtSignal(str)
roomEventReceived = pyqtSignal(str, str, dict)
def __init__(self, hostname: str, username: str, device_id: str = ""
@@ -114,21 +113,13 @@ class Client(QObject):
for room_id in response.rooms.invite:
self.roomInvited.emit(room_id)
for room_id in response.rooms.join:
for room_id, room_info in response.rooms.join.items():
self.roomJoined.emit(room_id)
for ev in room_info.timeline.events:
self.roomEventReceived.emit(
room_id, type(ev).__name__, ev.__dict__
)
for room_id in response.rooms.leave:
self.roomLeft.emit(room_id)
@pyqtSlot(str, str, result="QVariantMap")
def getUser(self, room_id: str, user_id: str) -> Dict[str, str]:
try:
name = self.nio.rooms[room_id].user_name(user_id)
except KeyError:
name = None
return User(
user_id = user_id,
display_name = name or user_id,
)._asdict()

View File

@@ -1,11 +1,11 @@
# Copyright 2019 miruka
# This file is part of harmonyqml, licensed under GPLv3.
from typing import NamedTuple, Optional
from typing import Dict, NamedTuple, Optional
from PyQt5.QtCore import QDateTime
from .enums import Activity, MessageKind, Presence
from .enums import Activity, Presence
class User(NamedTuple):
@@ -26,9 +26,7 @@ class Room(NamedTuple):
avatar_url: Optional[str] = None
class Message(NamedTuple):
sender_id: str
date_time: QDateTime
content: str
kind: MessageKind = MessageKind.text
sender_avatar: Optional[str] = None
class RoomEvent(NamedTuple):
type: str
date_time: QDateTime
dict: Dict[str, str]

View File

@@ -13,9 +13,9 @@ class QMLModels(QObject):
def __init__(self) -> None:
super().__init__()
self._accounts: ListModel = ListModel()
self._rooms: ListModelMap = ListModelMap()
self._messages: ListModelMap = ListModelMap()
self._accounts: ListModel = ListModel()
self._rooms: ListModelMap = ListModelMap()
self._room_events: ListModelMap = ListModelMap()
@pyqtProperty(ListModel, constant=True)
@@ -29,5 +29,5 @@ class QMLModels(QObject):
@pyqtProperty("QVariant", constant=True)
def messages(self):
return self._messages
def roomEvents(self):
return self._room_events

View File

@@ -1,18 +1,18 @@
# Copyright 2019 miruka
# This file is part of harmonyqml, licensed under GPLv3.
from typing import Optional
from typing import Any, Dict, Optional
from PyQt5.QtCore import QObject
from PyQt5.QtCore import QDateTime, QObject, pyqtBoundSignal
from .backend import Backend
from .client import Client
from .model.items import Room, User
from .model.items import Room, RoomEvent, User
class SignalManager(QObject):
def __init__(self, backend: Backend) -> None:
super().__init__()
super().__init__(parent=backend)
self.backend = backend
cm = self.backend.clientManager
@@ -34,10 +34,15 @@ class SignalManager(QObject):
def connectClient(self, client: Client) -> None:
for sig_name in ("roomInvited", "roomJoined", "roomLeft"):
sig = getattr(client, sig_name)
on_sig = getattr(self, f"on{sig_name[0].upper()}{sig_name[1:]}")
sig.connect(lambda room_id, o=on_sig, c=client: o(c, room_id))
for name in dir(client):
attr = getattr(client, name)
if isinstance(attr, pyqtBoundSignal):
def onSignal(*args, name=name) -> None:
func = getattr(self, f"on{name[0].upper()}{name[1:]}")
func(client, *args)
attr.connect(onSignal)
def onRoomInvited(self, client: Client, room_id: str) -> None:
@@ -69,3 +74,25 @@ class SignalManager(QObject):
def onRoomLeft(self, client: Client, room_id: str) -> None:
rooms = self.backend.models.rooms[client.userID]
del rooms[rooms.indexWhere("room_id", room_id)]
def onRoomEventReceived(
self, _: Client, room_id: str, etype: str, edict: Dict[str, Any]
) -> None:
model = self.backend.models.roomEvents[room_id]
date_time = QDateTime.fromMSecsSinceEpoch(edict["server_timestamp"])
new_event = RoomEvent(type=etype, date_time=date_time, dict=edict)
# Insert event in model at the right position, based on timestamps
# to keep them sorted by date of arrival.
# Iterate in reverse, since a new event is more likely to be appended,
# but events can arrive out of order.
if not model or model[-1].date_time < new_event.date_time:
model.append(new_event)
else:
for i, event in enumerate(reversed(model)):
if event.date_time < new_event.date_time:
model.insert(-i, new_event)
break
else:
model.insert(0, new_event)