Improved ListModel and ListItem
- New ListItem implemented using a metaclass, which makes defining new ListItem subclasses much cleaner and shorter - ListModel functions taking an index now accept either an int (list index) or str (value of a main key) - getWhere() gone, simply use get(a_main_key_value) now - updateOrAppendWhere replaced by update()/upsert()
This commit is contained in:
parent
216ae312c5
commit
012e89f6cb
2
TODO.md
2
TODO.md
|
@ -5,7 +5,7 @@
|
||||||
- Bug fixes
|
- Bug fixes
|
||||||
- 100% CPU usage when hitting top edge to trigger messages loading
|
- 100% CPU usage when hitting top edge to trigger messages loading
|
||||||
- Sending `![A picture](https://picsum.photos/256/256)` → not clickable?
|
- Sending `![A picture](https://picsum.photos/256/256)` → not clickable?
|
||||||
- Icons aren't reloaded
|
- Icons and images aren't reloaded
|
||||||
- HStyle singleton isn't reloaded
|
- HStyle singleton isn't reloaded
|
||||||
- `MessageDelegate.qml:63: TypeError: 'reloadPreviousItem' not a function`
|
- `MessageDelegate.qml:63: TypeError: 'reloadPreviousItem' not a function`
|
||||||
- Bug when resizing window being tiled (i3), can't figure it out
|
- Bug when resizing window being tiled (i3), can't figure it out
|
||||||
|
|
|
@ -1,92 +1,38 @@
|
||||||
from typing import Any, Callable, Optional, Sequence, Tuple, Union
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal
|
from PyQt5.QtCore import QDateTime
|
||||||
|
|
||||||
|
from .list_item import ListItem
|
||||||
class ListItem(QObject):
|
|
||||||
roles: Tuple[str, ...] = ()
|
|
||||||
|
|
||||||
def __init__(self, *args, no_update: Sequence[str] = (), **kwargs):
|
|
||||||
super().__init__()
|
|
||||||
self.no_update = no_update
|
|
||||||
|
|
||||||
for role, value in zip(self.roles, args):
|
|
||||||
setattr(self, role, value)
|
|
||||||
|
|
||||||
for role, value in kwargs.items():
|
|
||||||
setattr(self, role, value)
|
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return "%s(no_update=%s, %s)" % (
|
|
||||||
type(self).__name__,
|
|
||||||
self.no_update,
|
|
||||||
", ".join((f"{r}={getattr(self, r)!r}" for r in self.roles)),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pyqtProperty(str, constant=True)
|
|
||||||
def _repr(self) -> str:
|
|
||||||
return repr(self)
|
|
||||||
|
|
||||||
|
|
||||||
def prop(qt_type: Union[str, Callable],
|
|
||||||
name: str,
|
|
||||||
signal: Optional[pyqtSignal] = None,
|
|
||||||
default_value: Any = None) -> pyqtProperty:
|
|
||||||
|
|
||||||
def fget(self, name=name, default_value=default_value):
|
|
||||||
if not hasattr(self, f"_{name}"):
|
|
||||||
setattr(self, f"_{name}", default_value)
|
|
||||||
return getattr(self, f"_{name}")
|
|
||||||
|
|
||||||
def fset(self, value, name=name, signal=signal):
|
|
||||||
setattr(self, f"_{name}", value)
|
|
||||||
if signal:
|
|
||||||
getattr(self, f"{name}Changed").emit(value)
|
|
||||||
|
|
||||||
kws = {"notify": signal} if signal else {"constant": True}
|
|
||||||
|
|
||||||
return pyqtProperty(qt_type, fget=fget, fset=fset, **kws)
|
|
||||||
|
|
||||||
|
|
||||||
class User(ListItem):
|
class User(ListItem):
|
||||||
roles = ("userId", "displayName", "avatarUrl", "statusMessage")
|
_required_init_values = {"userId"}
|
||||||
|
_constant = {"userId"}
|
||||||
|
|
||||||
displayNameChanged = pyqtSignal("QVariant")
|
userId: str = ""
|
||||||
avatarUrlChanged = pyqtSignal("QVariant")
|
displayName: Optional[str] = None
|
||||||
statusMessageChanged = pyqtSignal(str)
|
avatarUrl: Optional[str] = None
|
||||||
|
statusMessage: Optional[str] = None
|
||||||
userId = prop(str, "userId")
|
|
||||||
displayName = prop("QVariant", "displayName", displayNameChanged)
|
|
||||||
avatarUrl = prop(str, "avatarUrl", avatarUrlChanged)
|
|
||||||
statusMessage = prop(str, "statusMessage", statusMessageChanged, "")
|
|
||||||
|
|
||||||
|
|
||||||
class Room(ListItem):
|
class Room(ListItem):
|
||||||
roles = ("roomId", "category", "displayName", "topic", "typingUsers",
|
_required_init_values = {"roomId", "displayName"}
|
||||||
"inviter", "leftEvent")
|
_constant = {"roomId"}
|
||||||
|
|
||||||
categoryChanged = pyqtSignal(str)
|
roomId: str = ""
|
||||||
displayNameChanged = pyqtSignal("QVariant")
|
displayName: str = ""
|
||||||
topicChanged = pyqtSignal(str)
|
category: str = "Rooms"
|
||||||
typingUsersChanged = pyqtSignal("QVariantList")
|
topic: Optional[str] = None
|
||||||
inviterChanged = pyqtSignal("QVariant")
|
typingUsers: List[str] = []
|
||||||
leftEventChanged = pyqtSignal("QVariant")
|
inviter: Optional[Dict[str, str]] = None
|
||||||
|
leftEvent: Optional[Dict[str, str]] = None
|
||||||
roomId = prop(str, "roomId")
|
|
||||||
category = prop(str, "category", categoryChanged)
|
|
||||||
displayName = prop(str, "displayName", displayNameChanged)
|
|
||||||
topic = prop(str, "topic", topicChanged, "")
|
|
||||||
typingUsers = prop(list, "typingUsers", typingUsersChanged, [])
|
|
||||||
inviter = prop("QVariant", "inviter", inviterChanged)
|
|
||||||
leftEvent = prop("QVariant", "leftEvent", leftEventChanged)
|
|
||||||
|
|
||||||
|
|
||||||
class RoomEvent(ListItem):
|
class RoomEvent(ListItem):
|
||||||
roles = ("type", "dateTime", "dict", "isLocalEcho")
|
_required_init_values = {"type", "dict"}
|
||||||
|
_constant = {"type"}
|
||||||
|
|
||||||
type = prop(str, "type")
|
type: str = ""
|
||||||
dateTime = prop("QVariant", "dateTime")
|
dict: Dict[str, Any] = {}
|
||||||
dict = prop("QVariantMap", "dict")
|
dateTime: QDateTime = QDateTime.currentDateTime()
|
||||||
isLocalEcho = prop(bool, "isLocalEcho", None, False)
|
isLocalEcho: bool = False
|
||||||
|
|
147
harmonyqml/backend/model/list_item.py
Normal file
147
harmonyqml/backend/model/list_item.py
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
from typing import Any, Dict, List, Mapping, Optional, Tuple
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
|
||||||
|
|
||||||
|
|
||||||
|
class _ListItemMeta(type(QObject)): # type: ignore
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __new__(mcs, name: str, bases: Tuple[type], attrs: Dict[str, Any]):
|
||||||
|
def to_pyqt_type(type_):
|
||||||
|
try:
|
||||||
|
if issubclass(type_, (bool, int, float, str)):
|
||||||
|
return type_
|
||||||
|
if issubclass(type_, Mapping):
|
||||||
|
return "QVariantMap"
|
||||||
|
return "QVariant"
|
||||||
|
except TypeError: # e.g. None passed
|
||||||
|
return to_pyqt_type(type(type_))
|
||||||
|
|
||||||
|
special = {"_main_key", "_required_init_values", "_constant"}
|
||||||
|
constant = set(attrs.get("_constant") or set())
|
||||||
|
|
||||||
|
props = {
|
||||||
|
name: (to_pyqt_type(attrs.get("__annotations__", {}).get(name)),
|
||||||
|
value)
|
||||||
|
for name, value in attrs.items()
|
||||||
|
|
||||||
|
if not (name.startswith("__") or callable(value) or
|
||||||
|
name in special)
|
||||||
|
}
|
||||||
|
|
||||||
|
signals = {
|
||||||
|
f"{name}Changed": pyqtSignal(type_)
|
||||||
|
for name, (type_, _) in props.items() if name not in constant
|
||||||
|
}
|
||||||
|
|
||||||
|
pyqt_props_kwargs: Dict[str, Dict[str, Any]] = {
|
||||||
|
name: {"constant": True} if name in constant else
|
||||||
|
{"notify": signals[f"{name}Changed"],
|
||||||
|
"fset": lambda self, value, n=name: (
|
||||||
|
setattr(self, f"_{n}", value) or # type: ignore
|
||||||
|
getattr(self, f"{n}Changed").emit(value),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
for name in props
|
||||||
|
}
|
||||||
|
|
||||||
|
pyqt_props = {
|
||||||
|
name: pyqtProperty(
|
||||||
|
type_,
|
||||||
|
fget=lambda self, n=name: getattr(self, f"_{n}"),
|
||||||
|
**pyqt_props_kwargs.get(name, {}),
|
||||||
|
)
|
||||||
|
for name, (type_, _) in props.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs = {
|
||||||
|
**attrs, **signals, **pyqt_props,
|
||||||
|
"__slots__": tuple({f"_{prop}" for prop in props} & {"_main_key"}),
|
||||||
|
"_props": props,
|
||||||
|
"_main_key": attrs.get("_main_key") or
|
||||||
|
list(props.keys())[0] if props else None,
|
||||||
|
|
||||||
|
"_required_init_values": attrs.get("_required_init_values") or (),
|
||||||
|
"_constant": constant,
|
||||||
|
}
|
||||||
|
return type.__new__(mcs, name, bases, attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class ListItem(QObject, metaclass=_ListItemMeta):
|
||||||
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
method = "%s.__init__()" % type(self).__name__
|
||||||
|
already_set = set()
|
||||||
|
|
||||||
|
required = set(self._required_init_values)
|
||||||
|
required_num = len(required) + 1 # + 1 = self
|
||||||
|
args_num = len(self._props) + 1
|
||||||
|
from_to = str(args_num) if required_num == args_num else \
|
||||||
|
f"from {required_num} to {args_num}"
|
||||||
|
|
||||||
|
if len(args) > len(self._props):
|
||||||
|
raise TypeError(
|
||||||
|
f"{method} takes {from_to} positional arguments but "
|
||||||
|
f"{len(args) + 1} were given"
|
||||||
|
)
|
||||||
|
|
||||||
|
for prop, value in zip(self._props, args):
|
||||||
|
setattr(self, f"_{prop}", value)
|
||||||
|
already_set.add(prop)
|
||||||
|
|
||||||
|
for prop, value in kwargs.items():
|
||||||
|
if prop in already_set:
|
||||||
|
raise TypeError(f"{method} got multiple values for "
|
||||||
|
f"argument {prop!r}")
|
||||||
|
if prop not in self._props:
|
||||||
|
raise TypeError(f"{method} got an unexpected keyword "
|
||||||
|
f"argument {prop!r}")
|
||||||
|
setattr(self, f"_{prop}", value)
|
||||||
|
already_set.add(prop)
|
||||||
|
|
||||||
|
missing = required - already_set
|
||||||
|
if missing:
|
||||||
|
raise TypeError("%s missing %d required argument: %s" % (
|
||||||
|
method, len(missing), ", ".join((repr(m) for m in missing))))
|
||||||
|
|
||||||
|
for prop in set(self._props) - already_set:
|
||||||
|
# Set default values for properties not provided in arguments
|
||||||
|
setattr(self, f"_{prop}", self._props[prop][1])
|
||||||
|
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "%s(main_key=%r, required_init_values=%r, constant=%r, %s)" % (
|
||||||
|
type(self).__name__,
|
||||||
|
self.mainKey,
|
||||||
|
self._required_init_values,
|
||||||
|
self._constant,
|
||||||
|
", ".join((("%s=%r" % (p, getattr(self, p))) for p in self._props))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pyqtSlot(result=str)
|
||||||
|
def repr(self) -> str:
|
||||||
|
return self.__repr()
|
||||||
|
|
||||||
|
|
||||||
|
@pyqtProperty(list)
|
||||||
|
def roles(self) -> List[str]:
|
||||||
|
return list(self._props.keys())
|
||||||
|
|
||||||
|
|
||||||
|
@pyqtProperty(str)
|
||||||
|
def mainKey(self) -> str:
|
||||||
|
return self._main_key
|
||||||
|
|
||||||
|
|
||||||
|
class User(ListItem):
|
||||||
|
_required_init_values = {"name"}
|
||||||
|
_constant = {"name"}
|
||||||
|
|
||||||
|
name: str = ""
|
||||||
|
age: int = 0
|
||||||
|
likes: Tuple[str, ...] = ()
|
||||||
|
knows: Dict[str, str] = {}
|
||||||
|
photo: Optional[str] = None
|
||||||
|
other = None
|
|
@ -9,12 +9,14 @@ from PyQt5.QtCore import (
|
||||||
pyqtSlot
|
pyqtSlot
|
||||||
)
|
)
|
||||||
|
|
||||||
from .items import ListItem
|
from .list_item import ListItem
|
||||||
|
|
||||||
|
Index = Union[int, str]
|
||||||
NewItem = Union[ListItem, Mapping[str, Any], Sequence]
|
NewItem = Union[ListItem, Mapping[str, Any], Sequence]
|
||||||
|
|
||||||
|
|
||||||
class ListModel(QAbstractListModel):
|
class ListModel(QAbstractListModel):
|
||||||
|
rolesSet = pyqtSignal()
|
||||||
changed = pyqtSignal()
|
changed = pyqtSignal()
|
||||||
countChanged = pyqtSignal(int)
|
countChanged = pyqtSignal(int)
|
||||||
|
|
||||||
|
@ -34,7 +36,7 @@ class ListModel(QAbstractListModel):
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
return self._data[index]
|
return self.get(index)
|
||||||
|
|
||||||
|
|
||||||
def __setitem__(self, index, value) -> None:
|
def __setitem__(self, index, value) -> None:
|
||||||
|
@ -53,11 +55,17 @@ class ListModel(QAbstractListModel):
|
||||||
return iter(self._data)
|
return iter(self._data)
|
||||||
|
|
||||||
|
|
||||||
@pyqtProperty(list, constant=True)
|
@pyqtProperty("QVariant", notify=rolesSet)
|
||||||
def roles(self) -> Tuple[str, ...]:
|
def roles(self) -> Tuple[str, ...]:
|
||||||
return self._data[0].roles if self._data else () # type: ignore
|
return self._data[0].roles if self._data else () # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
@pyqtProperty("QVariant", notify=rolesSet)
|
||||||
|
def mainKey(self) -> Optional[str]:
|
||||||
|
return self._data[0].mainKey if self._data else None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def roleNames(self) -> Dict[int, bytes]:
|
def roleNames(self) -> Dict[int, bytes]:
|
||||||
return {Qt.UserRole + i: bytes(f, "utf-8")
|
return {Qt.UserRole + i: bytes(f, "utf-8")
|
||||||
for i, f in enumerate(self.roles, 1)} \
|
for i, f in enumerate(self.roles, 1)} \
|
||||||
|
@ -110,11 +118,6 @@ class ListModel(QAbstractListModel):
|
||||||
return len(self)
|
return len(self)
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(int, result="QVariant")
|
|
||||||
def get(self, index: int) -> ListItem:
|
|
||||||
return self._data[index]
|
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(str, "QVariant", result=int)
|
@pyqtSlot(str, "QVariant", result=int)
|
||||||
def indexWhere(self, prop: str, is_value: Any) -> int:
|
def indexWhere(self, prop: str, is_value: Any) -> int:
|
||||||
for i, item in enumerate(self._data):
|
for i, item in enumerate(self._data):
|
||||||
|
@ -125,16 +128,26 @@ class ListModel(QAbstractListModel):
|
||||||
f"property {prop!r} set to {is_value!r}.")
|
f"property {prop!r} set to {is_value!r}.")
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(str, "QVariant", result="QVariant")
|
@pyqtSlot(int, result="QVariant")
|
||||||
def getWhere(self, prop: str, is_value: Any) -> ListItem:
|
@pyqtSlot(str, result="QVariant")
|
||||||
return self.get(self.indexWhere(prop, is_value))
|
def get(self, index: Index) -> ListItem:
|
||||||
|
if isinstance(index, str):
|
||||||
|
index = self.indexWhere(self.mainKey, index)
|
||||||
|
|
||||||
|
return self._data[index] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(int, "QVariantMap")
|
@pyqtSlot(int, "QVariantMap")
|
||||||
def insert(self, index: int, value: NewItem) -> None:
|
def insert(self, index: int, value: NewItem) -> None:
|
||||||
value = self._convert_new_value(value)
|
value = self._convert_new_value(value)
|
||||||
|
|
||||||
self.beginInsertRows(QModelIndex(), index, index)
|
self.beginInsertRows(QModelIndex(), index, index)
|
||||||
|
|
||||||
|
had_data = bool(self._data)
|
||||||
self._data.insert(index, value)
|
self._data.insert(index, value)
|
||||||
|
if not had_data:
|
||||||
|
self.rolesSet.emit()
|
||||||
|
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
|
|
||||||
self.countChanged.emit(len(self))
|
self.countChanged.emit(len(self))
|
||||||
|
@ -152,46 +165,68 @@ class ListModel(QAbstractListModel):
|
||||||
self.append(val)
|
self.append(val)
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot("QVariantMap")
|
@pyqtSlot(int, "QVariantMap")
|
||||||
def update(self, index: int, value: NewItem) -> None:
|
@pyqtSlot(int, "QVariantMap", "QVariant")
|
||||||
|
@pyqtSlot(str, "QVariantMap")
|
||||||
|
@pyqtSlot(str, "QVariantMap", "QVariant")
|
||||||
|
def update(self,
|
||||||
|
index: Index,
|
||||||
|
value: NewItem,
|
||||||
|
ignore_roles: Sequence[str] = ()) -> None:
|
||||||
value = self._convert_new_value(value)
|
value = self._convert_new_value(value)
|
||||||
|
|
||||||
for role in self.roles:
|
if isinstance(index, str):
|
||||||
if role in value.no_update:
|
index = self.indexWhere(self.mainKey or value.mainKey, index)
|
||||||
continue
|
|
||||||
|
|
||||||
setattr(self._data[index], role, getattr(value, role))
|
to_update = self._data[index] # type: ignore
|
||||||
|
|
||||||
|
for role in self.roles:
|
||||||
|
if role not in ignore_roles:
|
||||||
|
try:
|
||||||
|
setattr(to_update, role, getattr(value, role))
|
||||||
|
except AttributeError: # constant/not settable
|
||||||
|
pass
|
||||||
|
|
||||||
qidx = QAbstractListModel.index(self, index, 0)
|
qidx = QAbstractListModel.index(self, index, 0)
|
||||||
self.dataChanged.emit(qidx, qidx, self.roleNames())
|
self.dataChanged.emit(qidx, qidx, self.roleNames())
|
||||||
self.changed.emit()
|
self.changed.emit()
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(str, "QVariant", "QVariantMap")
|
@pyqtSlot(str, "QVariantMap")
|
||||||
def updateOrAppendWhere(
|
@pyqtSlot(str, "QVariantMap", int)
|
||||||
self, prop: str, is_value: Any, update_with: NewItem
|
@pyqtSlot(str, "QVariantMap", int, list)
|
||||||
) -> None:
|
def upsert(self,
|
||||||
|
where_main_key_is_value: Any,
|
||||||
|
update_with: NewItem,
|
||||||
|
index_if_insert: Optional[int] = None,
|
||||||
|
ignore_roles: Sequence[str] = ()) -> None:
|
||||||
try:
|
try:
|
||||||
index = self.indexWhere(prop, is_value)
|
self.update(where_main_key_is_value, update_with, ignore_roles)
|
||||||
self.update(index, update_with)
|
except (IndexError, ValueError):
|
||||||
except ValueError:
|
self.insert(index_if_insert or len(self), update_with)
|
||||||
index = len(self)
|
|
||||||
self.append(update_with)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(int, list)
|
@pyqtSlot(int, list)
|
||||||
def set(self, index: int, value: NewItem) -> None:
|
@pyqtSlot(str, list)
|
||||||
|
def set(self, index: Index, value: NewItem) -> None:
|
||||||
|
if isinstance(index, str):
|
||||||
|
index = self.indexWhere(self.mainKey, index)
|
||||||
|
|
||||||
qidx = QAbstractListModel.index(self, index, 0)
|
qidx = QAbstractListModel.index(self, index, 0)
|
||||||
value = self._convert_new_value(value)
|
value = self._convert_new_value(value)
|
||||||
self._data[index] = value
|
self._data[index] = value # type: ignore
|
||||||
self.dataChanged.emit(qidx, qidx, self.roleNames())
|
self.dataChanged.emit(qidx, qidx, self.roleNames())
|
||||||
self.changed.emit()
|
self.changed.emit()
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(int, str, "QVariant")
|
@pyqtSlot(int, str, "QVariant")
|
||||||
def setProperty(self, index: int, prop: str, value: Any) -> None:
|
@pyqtSlot(str, str, "QVariant")
|
||||||
setattr(self._data[index], prop, value)
|
def setProperty(self, index: Index, prop: str, value: Any) -> None:
|
||||||
|
if isinstance(index, str):
|
||||||
|
index = self.indexWhere(self.mainKey, index)
|
||||||
|
|
||||||
|
setattr(self._data[index], prop, value) # type: ignore
|
||||||
qidx = QAbstractListModel.index(self, index, 0)
|
qidx = QAbstractListModel.index(self, index, 0)
|
||||||
self.dataChanged.emit(qidx, qidx, self.roleNames())
|
self.dataChanged.emit(qidx, qidx, self.roleNames())
|
||||||
self.changed.emit()
|
self.changed.emit()
|
||||||
|
@ -227,9 +262,13 @@ class ListModel(QAbstractListModel):
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
@pyqtSlot(int)
|
||||||
def remove(self, index: int) -> None:
|
@pyqtSlot(str)
|
||||||
|
def remove(self, index: Index) -> None:
|
||||||
|
if isinstance(index, str):
|
||||||
|
index = self.indexWhere(self.mainKey, index)
|
||||||
|
|
||||||
self.beginRemoveRows(QModelIndex(), index, index)
|
self.beginRemoveRows(QModelIndex(), index, index)
|
||||||
del self._data[index]
|
del self._data[index] # type: ignore
|
||||||
self.endRemoveRows()
|
self.endRemoveRows()
|
||||||
|
|
||||||
self.countChanged.emit(len(self))
|
self.countChanged.emit(len(self))
|
||||||
|
|
|
@ -41,8 +41,7 @@ class SignalManager(QObject):
|
||||||
|
|
||||||
|
|
||||||
def onClientDeleted(self, user_id: str) -> None:
|
def onClientDeleted(self, user_id: str) -> None:
|
||||||
accs = self.backend.models.accounts
|
del self.backend.models.accounts[user_id]
|
||||||
del accs[accs.indexWhere("userId", user_id)]
|
|
||||||
|
|
||||||
|
|
||||||
def connectClient(self, client: Client) -> None:
|
def connectClient(self, client: Client) -> None:
|
||||||
|
@ -120,7 +119,7 @@ class SignalManager(QObject):
|
||||||
client: Client,
|
client: Client,
|
||||||
room_id: str,
|
room_id: str,
|
||||||
room: MatrixRoom,
|
room: MatrixRoom,
|
||||||
category: str,
|
category: str = "Rooms",
|
||||||
inviter: Inviter = None,
|
inviter: Inviter = None,
|
||||||
left_event: LeftEvent = None) -> None:
|
left_event: LeftEvent = None) -> None:
|
||||||
|
|
||||||
|
@ -144,15 +143,14 @@ class SignalManager(QObject):
|
||||||
|
|
||||||
item = Room(
|
item = Room(
|
||||||
roomId = room_id,
|
roomId = room_id,
|
||||||
category = category,
|
|
||||||
displayName = get_displayname(),
|
displayName = get_displayname(),
|
||||||
topic = room.topic if room else "",
|
category = category,
|
||||||
|
topic = room.topic if room else None,
|
||||||
inviter = inviter,
|
inviter = inviter,
|
||||||
leftEvent = left_event,
|
leftEvent = left_event,
|
||||||
no_update = no_update,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
model.updateOrAppendWhere("roomId", room_id, item)
|
model.upsert(room_id, item, ignore_roles=no_update)
|
||||||
with self._lock:
|
with self._lock:
|
||||||
self._move_room(client.userId, room_id)
|
self._move_room(client.userId, room_id)
|
||||||
|
|
||||||
|
@ -242,9 +240,7 @@ class SignalManager(QObject):
|
||||||
client: Client,
|
client: Client,
|
||||||
room_id: str,
|
room_id: str,
|
||||||
users: List[str]) -> None:
|
users: List[str]) -> None:
|
||||||
|
self.backend.models.rooms[client.userId][room_id].typingUsers = users
|
||||||
rooms = self.backend.models.rooms[client.userId]
|
|
||||||
rooms[rooms.indexWhere("roomId", room_id)].typingUsers = users
|
|
||||||
|
|
||||||
|
|
||||||
def onMessageAboutToBeSent(self,
|
def onMessageAboutToBeSent(self,
|
||||||
|
@ -253,17 +249,15 @@ class SignalManager(QObject):
|
||||||
content: Dict[str, str]) -> None:
|
content: Dict[str, str]) -> None:
|
||||||
|
|
||||||
with self._lock:
|
with self._lock:
|
||||||
timestamp = QDateTime.currentMSecsSinceEpoch()
|
|
||||||
model = self.backend.models.roomEvents[room_id]
|
model = self.backend.models.roomEvents[room_id]
|
||||||
nio_event = nio.events.RoomMessage.parse_event({
|
nio_event = nio.events.RoomMessage.parse_event({
|
||||||
"event_id": "",
|
"event_id": "",
|
||||||
"sender": client.userId,
|
"sender": client.userId,
|
||||||
"origin_server_ts": timestamp,
|
"origin_server_ts": QDateTime.currentMSecsSinceEpoch(),
|
||||||
"content": content,
|
"content": content,
|
||||||
})
|
})
|
||||||
event = RoomEvent(
|
event = RoomEvent(
|
||||||
type = type(nio_event).__name__,
|
type = type(nio_event).__name__,
|
||||||
dateTime = QDateTime.fromMSecsSinceEpoch(timestamp),
|
|
||||||
dict = nio_event.__dict__,
|
dict = nio_event.__dict__,
|
||||||
isLocalEcho = True,
|
isLocalEcho = True,
|
||||||
)
|
)
|
||||||
|
@ -275,7 +269,5 @@ class SignalManager(QObject):
|
||||||
|
|
||||||
def onRoomAboutToBeForgotten(self, client: Client, room_id: str) -> None:
|
def onRoomAboutToBeForgotten(self, client: Client, room_id: str) -> None:
|
||||||
with self._lock:
|
with self._lock:
|
||||||
rooms = self.backend.models.rooms[client.userId]
|
del self.backend.models.rooms[client.userId][room_id]
|
||||||
del rooms[rooms.indexWhere("roomId", room_id)]
|
|
||||||
|
|
||||||
self.backend.models.roomEvents[room_id].clear()
|
self.backend.models.roomEvents[room_id].clear()
|
||||||
|
|
|
@ -8,7 +8,7 @@ HColumnLayout {
|
||||||
property string roomId: ""
|
property string roomId: ""
|
||||||
|
|
||||||
readonly property var roomInfo:
|
readonly property var roomInfo:
|
||||||
Backend.models.rooms.get(userId).getWhere("roomId", roomId)
|
Backend.models.rooms.get(userId).get(roomId)
|
||||||
|
|
||||||
property bool canLoadPastEvents: true
|
property bool canLoadPastEvents: true
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ HColumnLayout {
|
||||||
|
|
||||||
RoomHeader {
|
RoomHeader {
|
||||||
displayName: roomInfo.displayName
|
displayName: roomInfo.displayName
|
||||||
topic: roomInfo.topic
|
topic: roomInfo.topic || ""
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomEventList {}
|
RoomEventList {}
|
||||||
|
|
|
@ -6,9 +6,6 @@ Item {
|
||||||
property string loginWith: "username"
|
property string loginWith: "username"
|
||||||
onFocusChanged: identifierField.forceActiveFocus()
|
onFocusChanged: identifierField.forceActiveFocus()
|
||||||
|
|
||||||
property int wi: x
|
|
||||||
onWiChanged: console.log("loginI", wi)
|
|
||||||
|
|
||||||
HInterfaceBox {
|
HInterfaceBox {
|
||||||
id: signInBox
|
id: signInBox
|
||||||
title: "Sign in"
|
title: "Sign in"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user