Document model items

This commit is contained in:
miruka 2019-12-18 15:00:34 -04:00
parent 934d6a79a2
commit 5f1044e96a
3 changed files with 59 additions and 6 deletions

View File

@ -1,3 +1,5 @@
"""Provide classes related to data models shared between Python and QML."""
from typing import Tuple, Type, Union
from .model_item import ModelItem

View File

@ -1,3 +1,5 @@
"""`ModelItem` subclasses definitions."""
import asyncio
import re
from dataclasses import dataclass, field
@ -19,6 +21,8 @@ OptionalExceptionType = Union[Type[None], Type[Exception]]
@dataclass
class Account(ModelItem):
"""A logged in matrix account."""
user_id: str = field()
display_name: str = ""
avatar_url: str = ""
@ -26,17 +30,21 @@ class Account(ModelItem):
profile_updated: Optional[datetime] = None
def __lt__(self, other: "Account") -> bool:
"""Sort by display name or user ID."""
name = self.display_name or self.user_id[1:]
other_name = other.display_name or other.user_id[1:]
return name < other_name
@property
def filter_string(self) -> str:
"""Filter based on display name."""
return self.display_name
@dataclass
class Room(ModelItem):
"""A matrix room we are invited to, are or were member of."""
room_id: str = field()
given_name: str = ""
display_name: str = ""
@ -66,8 +74,13 @@ class Room(ModelItem):
last_event: Optional[Dict[str, Any]] = field(default=None, repr=False)
def __lt__(self, other: "Room") -> bool:
# Order: Invited rooms > joined rooms > left rooms.
# Within these categories, sort by date then by name.
"""Sort by join state, then descending last event date, then name.
Invited rooms are first, then joined rooms, then left rooms.
Within these categories, sort by last event date (room with recent
messages are first), then by display names.
"""
# Left rooms may still have an inviter_id, so check left first.
return (
self.left,
@ -91,6 +104,8 @@ class Room(ModelItem):
@property
def filter_string(self) -> str:
"""Filter based on room display name, topic, and last event content."""
return " ".join((
self.display_name,
self.topic,
@ -101,6 +116,8 @@ class Room(ModelItem):
@dataclass
class Member(ModelItem):
"""A member in a matrix room."""
user_id: str = field()
display_name: str = ""
avatar_url: str = ""
@ -109,8 +126,8 @@ class Member(ModelItem):
invited: bool = False
def __lt__(self, other: "Member") -> bool:
# Sort by name, but have members with higher power-level first and
# invited-but-not-joined members last
"""Sort by power level, then by display name/user ID."""
name = (self.display_name or self.user_id[1:]).lower()
other_name = (other.display_name or other.user_id[1:]).lower()
@ -123,10 +140,13 @@ class Member(ModelItem):
@property
def filter_string(self) -> str:
"""Filter members based on display name."""
return self.display_name
class UploadStatus(AutoStrEnum):
"""Enum describing the status of an upload operation."""
Uploading = auto()
Caching = auto()
Error = auto()
@ -134,6 +154,8 @@ class UploadStatus(AutoStrEnum):
@dataclass
class Upload(ModelItem):
"""Represent a running or failed file upload operation."""
uuid: UUID = field()
task: asyncio.Task = field()
monitor: nio.TransferMonitor = field()
@ -152,11 +174,14 @@ class Upload(ModelItem):
def __lt__(self, other: "Upload") -> bool:
# Sort from newest upload to oldest.
"""Sort by the start date, from newest upload to oldest."""
return self.start_date > other.start_date
class TypeSpecifier(AutoStrEnum):
"""Enum providing clarification of purpose for some matrix events."""
none = auto()
profile_change = auto()
membership_change = auto()
@ -164,6 +189,8 @@ class TypeSpecifier(AutoStrEnum):
@dataclass
class Event(ModelItem):
"""A matrix state event or message."""
source: Optional[nio.Event] = field()
client_id: str = field()
event_id: str = field()
@ -204,11 +231,14 @@ class Event(ModelItem):
def __lt__(self, other: "Event") -> bool:
# Sort events from newest to oldest. return True means return False.
"""Sort by date in descending order, from newest to oldest."""
return self.date > other.date
@property
def event_type(self) -> Type:
"""Type of the source nio event used to create this `Event`."""
if self.local_event_type:
return self.local_event_type
@ -216,6 +246,8 @@ class Event(ModelItem):
@property
def links(self) -> List[str]:
"""List of URLs (`<a href=...>` tags) present in the event content."""
urls: List[str] = []
if self.content.strip():
@ -229,6 +261,8 @@ class Event(ModelItem):
@dataclass
class Device(ModelItem):
"""A matrix user's device. This class is currently unused."""
device_id: str = field()
ed25519_key: str = field()
trusted: bool = False

View File

@ -4,6 +4,19 @@ from ..utils import serialize_value_for_qml
class ModelItem:
"""Base class for items stored inside a `Model`.
This class must be subclassed and not used directly.
All subclasses must be dataclasses.
Subclasses are also expected to implement `__lt__()`,
to provide support for comparisons with the `<`, `>`, `<=`, `=>` operators
and thus allow a `Model` to sort its `ModelItem`s.
They may also implement a `filter_string` property, that will be used
for filtering from the UI.
"""
def __new__(cls, *_args, **_kwargs) -> "ModelItem":
from .model import Model
cls.parent_model: Optional[Model] = None
@ -11,6 +24,8 @@ class ModelItem:
def __setattr__(self, name: str, value) -> None:
"""If this item is in a `Model`, alert it of attribute changes."""
super().__setattr__(name, value)
if name != "parent_model" and self.parent_model is not None:
@ -24,6 +39,8 @@ class ModelItem:
@property
def serialized(self) -> Dict[str, Any]:
"""Return this item as a dict ready to be passed to QML."""
return {
name: serialize_value_for_qml(getattr(self, name))
for name in dir(self)