Overhaul room list sorting
This commit is contained in:
parent
424405e3e8
commit
237d750d47
4
TODO.md
4
TODO.md
|
@ -1,6 +1,6 @@
|
||||||
- Current focus
|
- Current focus
|
||||||
- Separate categories for invited, group and direct rooms
|
- When clicking on invited room but no multiaccount broadcasting events
|
||||||
- Invited → Accept/Deny dialog
|
- Sort accounts
|
||||||
- Merge login page
|
- Merge login page
|
||||||
|
|
||||||
- Refactoring
|
- Refactoring
|
||||||
|
|
|
@ -8,6 +8,7 @@ from typing import Dict, Sequence, Set
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
|
||||||
|
|
||||||
from .html_filter import HtmlFilter
|
from .html_filter import HtmlFilter
|
||||||
|
from .model.items import RoomEvent
|
||||||
from .model.qml_models import QMLModels
|
from .model.qml_models import QMLModels
|
||||||
from .pyqt_future import futurize
|
from .pyqt_future import futurize
|
||||||
|
|
||||||
|
@ -113,3 +114,22 @@ class Backend(QObject):
|
||||||
from PyQt5.QtCore import pyqtRemoveInputHook
|
from PyQt5.QtCore import pyqtRemoveInputHook
|
||||||
pyqtRemoveInputHook()
|
pyqtRemoveInputHook()
|
||||||
pdb.set_trace()
|
pdb.set_trace()
|
||||||
|
|
||||||
|
|
||||||
|
@pyqtSlot("QVariant", str, result=bool)
|
||||||
|
def EventIsOurProfileChanged(self, event: RoomEvent, account_id) -> bool:
|
||||||
|
# pylint: disable=unused-self
|
||||||
|
info = event.dict.get("content")
|
||||||
|
previous = event.dict.get("prev_content")
|
||||||
|
|
||||||
|
return (
|
||||||
|
event.type == "RoomMemberEvent" and
|
||||||
|
event.dict["sender"] == account_id and
|
||||||
|
bool(info) and
|
||||||
|
bool(previous) and
|
||||||
|
info["membership"] == previous["membership"] and
|
||||||
|
(
|
||||||
|
info.get("displayname") != previous.get("displayname") or
|
||||||
|
info.get("avatar_url") != previous.get("avatar_url")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -48,6 +48,10 @@ class ListModel(QAbstractListModel):
|
||||||
return self.rowCount()
|
return self.rowCount()
|
||||||
|
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self._data)
|
||||||
|
|
||||||
|
|
||||||
@pyqtProperty(list)
|
@pyqtProperty(list)
|
||||||
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
|
||||||
|
@ -205,7 +209,7 @@ class ListModel(QAbstractListModel):
|
||||||
valid = self.beginMoveRows(qidx, from_, qlast, qidx, qto)
|
valid = self.beginMoveRows(qidx, from_, qlast, qidx, qto)
|
||||||
|
|
||||||
if not valid:
|
if not valid:
|
||||||
logging.warning("Invalid move operation")
|
logging.warning("Invalid move operation - %r", locals())
|
||||||
return
|
return
|
||||||
|
|
||||||
last = from_ + n
|
last = from_ + n
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# This file is part of harmonyqml, licensed under GPLv3.
|
# This file is part of harmonyqml, licensed under GPLv3.
|
||||||
|
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from typing import Any, Deque, Dict, List, Optional
|
from typing import Any, Deque, Dict, List, Optional, Sequence
|
||||||
|
|
||||||
from PyQt5.QtCore import QDateTime, QObject, pyqtBoundSignal
|
from PyQt5.QtCore import QDateTime, QObject, pyqtBoundSignal
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ LeftEvent = Optional[Dict[str, str]]
|
||||||
|
|
||||||
|
|
||||||
class SignalManager(QObject):
|
class SignalManager(QObject):
|
||||||
_event_handling_lock: Lock = Lock()
|
_lock: Lock = Lock()
|
||||||
|
|
||||||
def __init__(self, backend: Backend) -> None:
|
def __init__(self, backend: Backend) -> None:
|
||||||
super().__init__(parent=backend)
|
super().__init__(parent=backend)
|
||||||
|
@ -79,6 +79,43 @@ class SignalManager(QObject):
|
||||||
left_event=left_event)
|
left_event=left_event)
|
||||||
|
|
||||||
|
|
||||||
|
def _move_room(self, account_id: str, room_id: str) -> None:
|
||||||
|
def get_newest_event_date_time(room_id: str) -> QDateTime:
|
||||||
|
for ev in self.backend.models.roomEvents[room_id]:
|
||||||
|
if not self.backend.EventIsOurProfileChanged(ev, account_id):
|
||||||
|
return ev.dateTime
|
||||||
|
|
||||||
|
return QDateTime.fromMSecsSinceEpoch(0)
|
||||||
|
|
||||||
|
rooms_model = self.backend.models.rooms[account_id]
|
||||||
|
room_index = rooms_model.indexWhere("roomId", room_id)
|
||||||
|
category = rooms_model[room_index].category
|
||||||
|
timestamp = get_newest_event_date_time(room_id)
|
||||||
|
|
||||||
|
def get_index(put_before_categories: Sequence[str],
|
||||||
|
put_after_categories: Sequence[str]) -> int:
|
||||||
|
for i, room in enumerate(rooms_model):
|
||||||
|
if room.category not in put_after_categories and \
|
||||||
|
(room.category in put_before_categories or
|
||||||
|
timestamp >= get_newest_event_date_time(room.roomId)):
|
||||||
|
return i
|
||||||
|
|
||||||
|
return len(rooms_model) - 1
|
||||||
|
|
||||||
|
to = 0
|
||||||
|
|
||||||
|
if category == "Invites":
|
||||||
|
to = get_index(["Rooms", "Left"], [])
|
||||||
|
|
||||||
|
if category == "Rooms":
|
||||||
|
to = get_index(["Left"], ["Invites"])
|
||||||
|
|
||||||
|
elif category == "Left":
|
||||||
|
to = get_index([], ["Invites", "Rooms", "Left"])
|
||||||
|
|
||||||
|
rooms_model.move(room_index, to)
|
||||||
|
|
||||||
|
|
||||||
def _add_room(self,
|
def _add_room(self,
|
||||||
client: Client,
|
client: Client,
|
||||||
room_id: str,
|
room_id: str,
|
||||||
|
@ -115,27 +152,23 @@ class SignalManager(QObject):
|
||||||
)
|
)
|
||||||
|
|
||||||
model.updateOrAppendWhere("roomId", room_id, item)
|
model.updateOrAppendWhere("roomId", room_id, item)
|
||||||
index = model.indexWhere("roomId", room_id)
|
with self._lock:
|
||||||
|
self._move_room(client.userId, room_id)
|
||||||
if category == "Invites":
|
|
||||||
model.move(index, 0)
|
|
||||||
|
|
||||||
elif category == "Left":
|
|
||||||
model.move(index, len(model))
|
|
||||||
|
|
||||||
|
|
||||||
|
def onRoomSyncPrevBatchTokenReceived(self,
|
||||||
def onRoomSyncPrevBatchTokenReceived(
|
_: Client,
|
||||||
self, _: Client, room_id: str, token: str
|
room_id: str,
|
||||||
) -> None:
|
token: str) -> None:
|
||||||
|
|
||||||
if room_id not in self.backend.past_tokens:
|
if room_id not in self.backend.past_tokens:
|
||||||
self.backend.past_tokens[room_id] = token
|
self.backend.past_tokens[room_id] = token
|
||||||
|
|
||||||
|
|
||||||
def onRoomPastPrevBatchTokenReceived(
|
def onRoomPastPrevBatchTokenReceived(self,
|
||||||
self, _: Client, room_id: str, token: str
|
_: Client,
|
||||||
) -> None:
|
room_id: str,
|
||||||
|
token: str) -> None:
|
||||||
|
|
||||||
if self.backend.past_tokens[room_id] == token:
|
if self.backend.past_tokens[room_id] == token:
|
||||||
self.backend.fully_loaded_rooms.add(room_id)
|
self.backend.fully_loaded_rooms.add(room_id)
|
||||||
|
@ -143,11 +176,12 @@ class SignalManager(QObject):
|
||||||
self.backend.past_tokens[room_id] = token
|
self.backend.past_tokens[room_id] = token
|
||||||
|
|
||||||
|
|
||||||
def onRoomEventReceived(
|
def onRoomEventReceived(self,
|
||||||
self, _: Client, room_id: str, etype: str, edict: Dict[str, Any]
|
client: Client,
|
||||||
) -> None:
|
room_id: str,
|
||||||
|
etype: str,
|
||||||
with self._event_handling_lock:
|
edict: Dict[str, Any]) -> None:
|
||||||
|
def process() -> None:
|
||||||
# Prevent duplicate events in models due to multiple accounts
|
# Prevent duplicate events in models due to multiple accounts
|
||||||
if edict["event_id"] in self.last_room_events:
|
if edict["event_id"] in self.last_room_events:
|
||||||
return
|
return
|
||||||
|
@ -195,19 +229,26 @@ class SignalManager(QObject):
|
||||||
|
|
||||||
model.append(new_event)
|
model.append(new_event)
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
|
process()
|
||||||
|
self._move_room(client.userId, room_id)
|
||||||
|
|
||||||
def onRoomTypingUsersUpdated(
|
|
||||||
self, client: Client, room_id: str, users: List[str]
|
def onRoomTypingUsersUpdated(self,
|
||||||
) -> None:
|
client: Client,
|
||||||
|
room_id: str,
|
||||||
|
users: List[str]) -> None:
|
||||||
|
|
||||||
rooms = self.backend.models.rooms[client.userId]
|
rooms = self.backend.models.rooms[client.userId]
|
||||||
rooms[rooms.indexWhere("roomId", room_id)].typingUsers = users
|
rooms[rooms.indexWhere("roomId", room_id)].typingUsers = users
|
||||||
|
|
||||||
|
|
||||||
def onMessageAboutToBeSent(
|
def onMessageAboutToBeSent(self,
|
||||||
self, client: Client, room_id: str, content: Dict[str, str]
|
client: Client,
|
||||||
) -> None:
|
room_id: str,
|
||||||
with self._event_handling_lock:
|
content: Dict[str, str]) -> None:
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
timestamp = QDateTime.currentMSecsSinceEpoch()
|
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({
|
||||||
|
@ -224,3 +265,5 @@ class SignalManager(QObject):
|
||||||
)
|
)
|
||||||
model.insert(0, event)
|
model.insert(0, event)
|
||||||
self._events_in_transfer += 1
|
self._events_in_transfer += 1
|
||||||
|
|
||||||
|
self._move_room(client.userId, room_id)
|
||||||
|
|
|
@ -2,12 +2,19 @@ import QtQuick 2.7
|
||||||
import "../base" as Base
|
import "../base" as Base
|
||||||
|
|
||||||
Base.HLabel {
|
Base.HLabel {
|
||||||
|
property bool isToday: {
|
||||||
|
const today = new Date()
|
||||||
|
return dateTime.getDate() == today.getDate() &&
|
||||||
|
dateTime.getMonth() == today.getMonth() &&
|
||||||
|
dateTime.getFullYear() == today.getFullYear()
|
||||||
|
}
|
||||||
|
|
||||||
width: messageDelegate.width
|
width: messageDelegate.width
|
||||||
topPadding: messageDelegate.isFirstMessage ?
|
topPadding: messageDelegate.isFirstMessage ?
|
||||||
0 : messageDelegate.standardSpacing
|
0 : messageDelegate.standardSpacing
|
||||||
bottomPadding: messageDelegate.standardSpacing
|
bottomPadding: messageDelegate.standardSpacing
|
||||||
|
|
||||||
text: dateTime.toLocaleDateString()
|
text: dateTime.toLocaleDateString() + (isToday ? qsTr(" (Today)") : "")
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
font.pixelSize: normalSize * 1.1
|
font.pixelSize: normalSize * 1.1
|
||||||
color: "darkolivegreen"
|
color: "darkolivegreen"
|
||||||
|
|
|
@ -46,7 +46,7 @@ Column {
|
||||||
readonly property bool dayBreak:
|
readonly property bool dayBreak:
|
||||||
isFirstEvent ||
|
isFirstEvent ||
|
||||||
previousItem &&
|
previousItem &&
|
||||||
dateTime.getDay() != previousItem.dateTime.getDay()
|
dateTime.getDate() != previousItem.dateTime.getDate()
|
||||||
|
|
||||||
readonly property bool talkBreak:
|
readonly property bool talkBreak:
|
||||||
previousItem &&
|
previousItem &&
|
||||||
|
|
|
@ -37,7 +37,9 @@ MouseArea {
|
||||||
}
|
}
|
||||||
Base.HLabel {
|
Base.HLabel {
|
||||||
function getText() {
|
function getText() {
|
||||||
return SidePaneJS.getLastRoomEventText(roomId)
|
return SidePaneJS.getLastRoomEventText(
|
||||||
|
roomId, roomList.forUserId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
.import "../chat/utils.js" as ChatJS
|
.import "../chat/utils.js" as ChatJS
|
||||||
|
|
||||||
|
|
||||||
function getLastRoomEventText(roomId) {
|
function getLastRoomEventText(roomId, accountId) {
|
||||||
var eventsModel = Backend.models.roomEvents.get(roomId)
|
var eventsModel = Backend.models.roomEvents.get(roomId)
|
||||||
|
|
||||||
for (var i = 0; i < eventsModel.count; i++) {
|
for (var i = 0; i < eventsModel.count; i++) {
|
||||||
var ev = eventsModel.get(i)
|
var ev = eventsModel.get(i)
|
||||||
|
|
||||||
if (ev.type !== "RoomMemberEvent") {
|
if (! Backend.EventIsOurProfileChanged(ev, accountId)) {
|
||||||
var found = true
|
var found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user