Begin yet another model refactor
Use native ListModel which require a lot of changes, but should be much faster than the old way which exponentially slowed down to a crawl. Also fix some popup bugs (leave/forget). Not working yet: side pane keyboard controls, proper highlight, room & member filtering, local echo replacement
This commit is contained in:
@@ -11,31 +11,39 @@ from typing import Any, Dict, List, Optional, Tuple, Type, Union
|
||||
from uuid import UUID
|
||||
|
||||
import lxml # nosec
|
||||
|
||||
import nio
|
||||
|
||||
from ..html_markdown import HTML_PROCESSOR
|
||||
from ..utils import AutoStrEnum, auto
|
||||
from .model_item import ModelItem
|
||||
|
||||
ZeroDate = datetime.fromtimestamp(0)
|
||||
OptionalExceptionType = Union[Type[None], Type[Exception]]
|
||||
|
||||
|
||||
class TypeSpecifier(AutoStrEnum):
|
||||
"""Enum providing clarification of purpose for some matrix events."""
|
||||
|
||||
Unset = auto()
|
||||
ProfileChange = auto()
|
||||
MembershipChange = auto()
|
||||
|
||||
|
||||
@dataclass
|
||||
class Account(ModelItem):
|
||||
"""A logged in matrix account."""
|
||||
|
||||
user_id: str = field()
|
||||
display_name: str = ""
|
||||
avatar_url: str = ""
|
||||
first_sync_done: bool = False
|
||||
profile_updated: Optional[datetime] = None
|
||||
id: str = field()
|
||||
display_name: str = ""
|
||||
avatar_url: str = ""
|
||||
first_sync_done: bool = False
|
||||
profile_updated: datetime = ZeroDate
|
||||
|
||||
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
|
||||
name = self.display_name or self.id[1:]
|
||||
other_name = other.display_name or other.id[1:]
|
||||
return name.lower() < other_name.lower()
|
||||
|
||||
@property
|
||||
def filter_string(self) -> str:
|
||||
@@ -47,18 +55,21 @@ class Account(ModelItem):
|
||||
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 = ""
|
||||
avatar_url: str = ""
|
||||
plain_topic: str = ""
|
||||
topic: str = ""
|
||||
inviter_id: str = ""
|
||||
inviter_name: str = ""
|
||||
inviter_avatar: str = ""
|
||||
left: bool = False
|
||||
id: str = field()
|
||||
given_name: str = ""
|
||||
display_name: str = ""
|
||||
main_alias: str = ""
|
||||
avatar_url: str = ""
|
||||
plain_topic: str = ""
|
||||
topic: str = ""
|
||||
inviter_id: str = ""
|
||||
inviter_name: str = ""
|
||||
inviter_avatar: str = ""
|
||||
left: bool = False
|
||||
|
||||
typing_members: List[str] = field(default_factory=list)
|
||||
|
||||
federated: bool = True
|
||||
encrypted: bool = False
|
||||
invite_required: bool = True
|
||||
guests_allowed: bool = True
|
||||
@@ -72,7 +83,7 @@ class Room(ModelItem):
|
||||
can_set_join_rules: bool = False
|
||||
can_set_guest_access: bool = False
|
||||
|
||||
last_event: Optional["Event"] = field(default=None, repr=False)
|
||||
last_event_date: datetime = ZeroDate
|
||||
|
||||
def __lt__(self, other: "Room") -> bool:
|
||||
"""Sort by join state, then descending last event date, then name.
|
||||
@@ -85,68 +96,45 @@ class Room(ModelItem):
|
||||
# Left rooms may still have an inviter_id, so check left first.
|
||||
return (
|
||||
self.left,
|
||||
|
||||
other.inviter_id,
|
||||
|
||||
other.last_event.date if other.last_event else
|
||||
datetime.fromtimestamp(0),
|
||||
|
||||
self.display_name.lower() or self.room_id,
|
||||
other.last_event_date,
|
||||
(self.display_name or self.id).lower(),
|
||||
) < (
|
||||
other.left,
|
||||
|
||||
self.inviter_id,
|
||||
|
||||
self.last_event.date if self.last_event else
|
||||
datetime.fromtimestamp(0),
|
||||
|
||||
other.display_name.lower() or other.room_id,
|
||||
self.last_event_date,
|
||||
(other.display_name or other.id).lower(),
|
||||
)
|
||||
|
||||
@property
|
||||
def filter_string(self) -> str:
|
||||
"""Filter based on room display name, topic, and last event content."""
|
||||
|
||||
return " ".join((
|
||||
self.display_name,
|
||||
self.topic,
|
||||
re.sub(r"<.*?>", "", self.last_event.inline_content)
|
||||
if self.last_event else "",
|
||||
))
|
||||
|
||||
|
||||
@property
|
||||
def serialized(self) -> Dict[str, Any]:
|
||||
dct = super().serialized
|
||||
|
||||
if self.last_event is not None:
|
||||
dct["last_event"] = self.last_event.serialized
|
||||
|
||||
return dct
|
||||
|
||||
return " ".join((self.display_name, self.topic))
|
||||
|
||||
|
||||
@dataclass
|
||||
class Member(ModelItem):
|
||||
"""A member in a matrix room."""
|
||||
|
||||
user_id: str = field()
|
||||
display_name: str = ""
|
||||
avatar_url: str = ""
|
||||
typing: bool = False
|
||||
power_level: int = 0
|
||||
invited: bool = False
|
||||
id: str = field()
|
||||
display_name: str = ""
|
||||
avatar_url: str = ""
|
||||
typing: bool = False
|
||||
power_level: int = 0
|
||||
invited: bool = False
|
||||
profile_updated: datetime = ZeroDate
|
||||
|
||||
def __lt__(self, other: "Member") -> bool:
|
||||
"""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()
|
||||
name = self.display_name or self.id[1:]
|
||||
other_name = other.display_name or other.id[1:]
|
||||
|
||||
return (
|
||||
self.invited, other.power_level, name,
|
||||
self.invited, other.power_level, name.lower(),
|
||||
) < (
|
||||
other.invited, self.power_level, other_name,
|
||||
other.invited, self.power_level, other_name.lower(),
|
||||
)
|
||||
|
||||
|
||||
@@ -168,15 +156,15 @@ class UploadStatus(AutoStrEnum):
|
||||
class Upload(ModelItem):
|
||||
"""Represent a running or failed file upload operation."""
|
||||
|
||||
uuid: UUID = field()
|
||||
id: UUID = field()
|
||||
task: asyncio.Task = field()
|
||||
monitor: nio.TransferMonitor = field()
|
||||
filepath: Path = field()
|
||||
|
||||
total_size: int = 0
|
||||
uploaded: int = 0
|
||||
speed: float = 0
|
||||
time_left: Optional[timedelta] = None
|
||||
total_size: int = 0
|
||||
uploaded: int = 0
|
||||
speed: float = 0
|
||||
time_left: timedelta = timedelta(0)
|
||||
|
||||
status: UploadStatus = UploadStatus.Uploading
|
||||
error: OptionalExceptionType = type(None)
|
||||
@@ -191,21 +179,13 @@ class Upload(ModelItem):
|
||||
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()
|
||||
|
||||
|
||||
@dataclass
|
||||
class Event(ModelItem):
|
||||
"""A matrix state event or message."""
|
||||
|
||||
source: Optional[nio.Event] = field()
|
||||
client_id: str = field()
|
||||
id: str = field()
|
||||
event_id: str = field()
|
||||
source: Optional[nio.Event] = field()
|
||||
date: datetime = field()
|
||||
sender_id: str = field()
|
||||
sender_name: str = field()
|
||||
@@ -213,8 +193,9 @@ class Event(ModelItem):
|
||||
|
||||
content: str = ""
|
||||
inline_content: str = ""
|
||||
reason: str = ""
|
||||
|
||||
type_specifier: TypeSpecifier = TypeSpecifier.none
|
||||
type_specifier: TypeSpecifier = TypeSpecifier.Unset
|
||||
|
||||
target_id: str = ""
|
||||
target_name: str = ""
|
||||
@@ -271,12 +252,19 @@ class Event(ModelItem):
|
||||
|
||||
return urls
|
||||
|
||||
@property
|
||||
def serialized(self) -> Dict[str, Any]:
|
||||
dct = super().serialized
|
||||
del dct["source"]
|
||||
del dct["local_event_type"]
|
||||
return dct
|
||||
|
||||
|
||||
@dataclass
|
||||
class Device(ModelItem):
|
||||
"""A matrix user's device. This class is currently unused."""
|
||||
|
||||
device_id: str = field()
|
||||
id: str = field()
|
||||
ed25519_key: str = field()
|
||||
trusted: bool = False
|
||||
blacklisted: bool = False
|
||||
|
||||
Reference in New Issue
Block a user