Document model items
This commit is contained in:
parent
934d6a79a2
commit
5f1044e96a
|
@ -1,3 +1,5 @@
|
||||||
|
"""Provide classes related to data models shared between Python and QML."""
|
||||||
|
|
||||||
from typing import Tuple, Type, Union
|
from typing import Tuple, Type, Union
|
||||||
|
|
||||||
from .model_item import ModelItem
|
from .model_item import ModelItem
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""`ModelItem` subclasses definitions."""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import re
|
import re
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
@ -19,6 +21,8 @@ OptionalExceptionType = Union[Type[None], Type[Exception]]
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Account(ModelItem):
|
class Account(ModelItem):
|
||||||
|
"""A logged in matrix account."""
|
||||||
|
|
||||||
user_id: str = field()
|
user_id: str = field()
|
||||||
display_name: str = ""
|
display_name: str = ""
|
||||||
avatar_url: str = ""
|
avatar_url: str = ""
|
||||||
|
@ -26,17 +30,21 @@ class Account(ModelItem):
|
||||||
profile_updated: Optional[datetime] = None
|
profile_updated: Optional[datetime] = None
|
||||||
|
|
||||||
def __lt__(self, other: "Account") -> bool:
|
def __lt__(self, other: "Account") -> bool:
|
||||||
|
"""Sort by display name or user ID."""
|
||||||
name = self.display_name or self.user_id[1:]
|
name = self.display_name or self.user_id[1:]
|
||||||
other_name = other.display_name or other.user_id[1:]
|
other_name = other.display_name or other.user_id[1:]
|
||||||
return name < other_name
|
return name < other_name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filter_string(self) -> str:
|
def filter_string(self) -> str:
|
||||||
|
"""Filter based on display name."""
|
||||||
return self.display_name
|
return self.display_name
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Room(ModelItem):
|
class Room(ModelItem):
|
||||||
|
"""A matrix room we are invited to, are or were member of."""
|
||||||
|
|
||||||
room_id: str = field()
|
room_id: str = field()
|
||||||
given_name: str = ""
|
given_name: str = ""
|
||||||
display_name: str = ""
|
display_name: str = ""
|
||||||
|
@ -66,8 +74,13 @@ class Room(ModelItem):
|
||||||
last_event: Optional[Dict[str, Any]] = field(default=None, repr=False)
|
last_event: Optional[Dict[str, Any]] = field(default=None, repr=False)
|
||||||
|
|
||||||
def __lt__(self, other: "Room") -> bool:
|
def __lt__(self, other: "Room") -> bool:
|
||||||
# Order: Invited rooms > joined rooms > left rooms.
|
"""Sort by join state, then descending last event date, then name.
|
||||||
# Within these categories, sort by date then by 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.
|
# Left rooms may still have an inviter_id, so check left first.
|
||||||
return (
|
return (
|
||||||
self.left,
|
self.left,
|
||||||
|
@ -91,6 +104,8 @@ class Room(ModelItem):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filter_string(self) -> str:
|
def filter_string(self) -> str:
|
||||||
|
"""Filter based on room display name, topic, and last event content."""
|
||||||
|
|
||||||
return " ".join((
|
return " ".join((
|
||||||
self.display_name,
|
self.display_name,
|
||||||
self.topic,
|
self.topic,
|
||||||
|
@ -101,6 +116,8 @@ class Room(ModelItem):
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Member(ModelItem):
|
class Member(ModelItem):
|
||||||
|
"""A member in a matrix room."""
|
||||||
|
|
||||||
user_id: str = field()
|
user_id: str = field()
|
||||||
display_name: str = ""
|
display_name: str = ""
|
||||||
avatar_url: str = ""
|
avatar_url: str = ""
|
||||||
|
@ -109,8 +126,8 @@ class Member(ModelItem):
|
||||||
invited: bool = False
|
invited: bool = False
|
||||||
|
|
||||||
def __lt__(self, other: "Member") -> bool:
|
def __lt__(self, other: "Member") -> bool:
|
||||||
# Sort by name, but have members with higher power-level first and
|
"""Sort by power level, then by display name/user ID."""
|
||||||
# invited-but-not-joined members last
|
|
||||||
name = (self.display_name or self.user_id[1:]).lower()
|
name = (self.display_name or self.user_id[1:]).lower()
|
||||||
other_name = (other.display_name or other.user_id[1:]).lower()
|
other_name = (other.display_name or other.user_id[1:]).lower()
|
||||||
|
|
||||||
|
@ -123,10 +140,13 @@ class Member(ModelItem):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filter_string(self) -> str:
|
def filter_string(self) -> str:
|
||||||
|
"""Filter members based on display name."""
|
||||||
return self.display_name
|
return self.display_name
|
||||||
|
|
||||||
|
|
||||||
class UploadStatus(AutoStrEnum):
|
class UploadStatus(AutoStrEnum):
|
||||||
|
"""Enum describing the status of an upload operation."""
|
||||||
|
|
||||||
Uploading = auto()
|
Uploading = auto()
|
||||||
Caching = auto()
|
Caching = auto()
|
||||||
Error = auto()
|
Error = auto()
|
||||||
|
@ -134,6 +154,8 @@ class UploadStatus(AutoStrEnum):
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Upload(ModelItem):
|
class Upload(ModelItem):
|
||||||
|
"""Represent a running or failed file upload operation."""
|
||||||
|
|
||||||
uuid: UUID = field()
|
uuid: UUID = field()
|
||||||
task: asyncio.Task = field()
|
task: asyncio.Task = field()
|
||||||
monitor: nio.TransferMonitor = field()
|
monitor: nio.TransferMonitor = field()
|
||||||
|
@ -152,11 +174,14 @@ class Upload(ModelItem):
|
||||||
|
|
||||||
|
|
||||||
def __lt__(self, other: "Upload") -> bool:
|
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
|
return self.start_date > other.start_date
|
||||||
|
|
||||||
|
|
||||||
class TypeSpecifier(AutoStrEnum):
|
class TypeSpecifier(AutoStrEnum):
|
||||||
|
"""Enum providing clarification of purpose for some matrix events."""
|
||||||
|
|
||||||
none = auto()
|
none = auto()
|
||||||
profile_change = auto()
|
profile_change = auto()
|
||||||
membership_change = auto()
|
membership_change = auto()
|
||||||
|
@ -164,6 +189,8 @@ class TypeSpecifier(AutoStrEnum):
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Event(ModelItem):
|
class Event(ModelItem):
|
||||||
|
"""A matrix state event or message."""
|
||||||
|
|
||||||
source: Optional[nio.Event] = field()
|
source: Optional[nio.Event] = field()
|
||||||
client_id: str = field()
|
client_id: str = field()
|
||||||
event_id: str = field()
|
event_id: str = field()
|
||||||
|
@ -204,11 +231,14 @@ class Event(ModelItem):
|
||||||
|
|
||||||
|
|
||||||
def __lt__(self, other: "Event") -> bool:
|
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
|
return self.date > other.date
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def event_type(self) -> Type:
|
def event_type(self) -> Type:
|
||||||
|
"""Type of the source nio event used to create this `Event`."""
|
||||||
|
|
||||||
if self.local_event_type:
|
if self.local_event_type:
|
||||||
return self.local_event_type
|
return self.local_event_type
|
||||||
|
|
||||||
|
@ -216,6 +246,8 @@ class Event(ModelItem):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def links(self) -> List[str]:
|
def links(self) -> List[str]:
|
||||||
|
"""List of URLs (`<a href=...>` tags) present in the event content."""
|
||||||
|
|
||||||
urls: List[str] = []
|
urls: List[str] = []
|
||||||
|
|
||||||
if self.content.strip():
|
if self.content.strip():
|
||||||
|
@ -229,6 +261,8 @@ class Event(ModelItem):
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Device(ModelItem):
|
class Device(ModelItem):
|
||||||
|
"""A matrix user's device. This class is currently unused."""
|
||||||
|
|
||||||
device_id: str = field()
|
device_id: str = field()
|
||||||
ed25519_key: str = field()
|
ed25519_key: str = field()
|
||||||
trusted: bool = False
|
trusted: bool = False
|
||||||
|
|
|
@ -4,6 +4,19 @@ from ..utils import serialize_value_for_qml
|
||||||
|
|
||||||
|
|
||||||
class ModelItem:
|
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":
|
def __new__(cls, *_args, **_kwargs) -> "ModelItem":
|
||||||
from .model import Model
|
from .model import Model
|
||||||
cls.parent_model: Optional[Model] = None
|
cls.parent_model: Optional[Model] = None
|
||||||
|
@ -11,6 +24,8 @@ class ModelItem:
|
||||||
|
|
||||||
|
|
||||||
def __setattr__(self, name: str, value) -> None:
|
def __setattr__(self, name: str, value) -> None:
|
||||||
|
"""If this item is in a `Model`, alert it of attribute changes."""
|
||||||
|
|
||||||
super().__setattr__(name, value)
|
super().__setattr__(name, value)
|
||||||
|
|
||||||
if name != "parent_model" and self.parent_model is not None:
|
if name != "parent_model" and self.parent_model is not None:
|
||||||
|
@ -24,6 +39,8 @@ class ModelItem:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serialized(self) -> Dict[str, Any]:
|
def serialized(self) -> Dict[str, Any]:
|
||||||
|
"""Return this item as a dict ready to be passed to QML."""
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: serialize_value_for_qml(getattr(self, name))
|
name: serialize_value_for_qml(getattr(self, name))
|
||||||
for name in dir(self)
|
for name in dir(self)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user