Lock position of the room that's focused in GUI
When the currently shown page is the chat of a certain room, prevent that room from moving around in the left pane due to new messages/activity or unread/highlight counters change. When the user switches to another page/room, the previously held lock is released and that room completes all the moves it would have done if it wasn't locked. This makes navigating a room list with lots of activity easier, and prevent annoyances like clicking on a room with unread messages and having it immediatly fly down the list (possibly out of scroll view).
This commit is contained in:
parent
3f88a2204e
commit
902f13ab68
|
@ -86,6 +86,11 @@ and this project adheres to
|
||||||
|
|
||||||
- Improve room page loading speed
|
- Improve room page loading speed
|
||||||
|
|
||||||
|
- In the left pane, lock the position of the room corresponding to the
|
||||||
|
currently visible chat page if any.
|
||||||
|
This fixes annoyances like clicking on a room with unread messages only to
|
||||||
|
see it immediatly fly down the list, potentially outside of scrolling view.
|
||||||
|
|
||||||
- When replying to a message, pressing the reply keybind again while focusing
|
- When replying to a message, pressing the reply keybind again while focusing
|
||||||
on that message will now cancel the reply
|
on that message will now cancel the reply
|
||||||
|
|
||||||
|
|
|
@ -2021,6 +2021,21 @@ class MatrixClient(nio.AsyncClient):
|
||||||
room.last_event_date = item.date
|
room.last_event_date = item.date
|
||||||
|
|
||||||
|
|
||||||
|
async def lock_room_position(self, room_id: str, lock: bool) -> None:
|
||||||
|
"""Set wheter a room should try to hold its current sort position."""
|
||||||
|
|
||||||
|
room = self.models[self.user_id, "rooms"][room_id]
|
||||||
|
|
||||||
|
if not lock:
|
||||||
|
room._sort_overrides = {}
|
||||||
|
return
|
||||||
|
|
||||||
|
for k in ("last_event_date", "unreads", "highlights", "local_unreads"):
|
||||||
|
room._sort_overrides[k] = getattr(room, k)
|
||||||
|
|
||||||
|
room.notify_change("_sort_overrides")
|
||||||
|
|
||||||
|
|
||||||
async def register_nio_room(
|
async def register_nio_room(
|
||||||
self,
|
self,
|
||||||
room: nio.MatrixRoom,
|
room: nio.MatrixRoom,
|
||||||
|
@ -2038,6 +2053,7 @@ class MatrixClient(nio.AsyncClient):
|
||||||
registered = self.models[self.user_id, "rooms"][room.room_id]
|
registered = self.models[self.user_id, "rooms"][room.room_id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
registered = None
|
registered = None
|
||||||
|
sort_overrides = {}
|
||||||
last_event_date = datetime.fromtimestamp(0)
|
last_event_date = datetime.fromtimestamp(0)
|
||||||
typing_members = []
|
typing_members = []
|
||||||
local_unreads = False
|
local_unreads = False
|
||||||
|
@ -2048,6 +2064,7 @@ class MatrixClient(nio.AsyncClient):
|
||||||
self.room_contains_unverified(room.room_id)
|
self.room_contains_unverified(room.room_id)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
sort_overrides = registered._sort_overrides
|
||||||
last_event_date = registered.last_event_date
|
last_event_date = registered.last_event_date
|
||||||
typing_members = registered.typing_members
|
typing_members = registered.typing_members
|
||||||
local_unreads = registered.local_unreads
|
local_unreads = registered.local_unreads
|
||||||
|
@ -2126,6 +2143,8 @@ class MatrixClient(nio.AsyncClient):
|
||||||
|
|
||||||
lexical_sorting = self.backend.settings.RoomList.lexical_sort,
|
lexical_sorting = self.backend.settings.RoomList.lexical_sort,
|
||||||
pinned = room.room_id in pinned.get(self.user_id, []),
|
pinned = room.room_id in pinned.get(self.user_id, []),
|
||||||
|
|
||||||
|
_sort_overrides = sort_overrides,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.models[self.user_id, "rooms"][room.room_id] = room_item
|
self.models[self.user_id, "rooms"][room.room_id] = room_item
|
||||||
|
|
|
@ -183,6 +183,15 @@ class Room(ModelItem):
|
||||||
lexical_sorting: bool = False
|
lexical_sorting: bool = False
|
||||||
pinned: bool = False
|
pinned: bool = False
|
||||||
|
|
||||||
|
# Allowed keys: "last_event_date", "unreads", "highlights", "local_unreads"
|
||||||
|
# Keys in this dict will override their corresponding item fields for the
|
||||||
|
# __lt__ method. This is used when we want to lock a room's position,
|
||||||
|
# e.g. to avoid having the room move around when it is focused in the GUI
|
||||||
|
_sort_overrides: Dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
|
def _sorting(self, key: str) -> Any:
|
||||||
|
return self._sort_overrides.get(key, getattr(self, key))
|
||||||
|
|
||||||
def __lt__(self, other: "Room") -> bool:
|
def __lt__(self, other: "Room") -> bool:
|
||||||
by_activity = not self.lexical_sorting
|
by_activity = not self.lexical_sorting
|
||||||
|
|
||||||
|
@ -191,10 +200,10 @@ class Room(ModelItem):
|
||||||
other.pinned,
|
other.pinned,
|
||||||
self.left, # Left rooms may have an inviter_id, check them first
|
self.left, # Left rooms may have an inviter_id, check them first
|
||||||
bool(other.inviter_id),
|
bool(other.inviter_id),
|
||||||
bool(by_activity and other.highlights),
|
bool(by_activity and other._sorting("highlights")),
|
||||||
bool(by_activity and other.unreads),
|
bool(by_activity and other._sorting("unreads")),
|
||||||
bool(by_activity and other.local_unreads),
|
bool(by_activity and other._sorting("local_unreads")),
|
||||||
other.last_event_date if by_activity else ZERO_DATE,
|
other._sorting("last_event_date") if by_activity else ZERO_DATE,
|
||||||
(self.display_name or self.id).lower(),
|
(self.display_name or self.id).lower(),
|
||||||
self.id,
|
self.id,
|
||||||
|
|
||||||
|
@ -203,10 +212,10 @@ class Room(ModelItem):
|
||||||
self.pinned,
|
self.pinned,
|
||||||
other.left,
|
other.left,
|
||||||
bool(self.inviter_id),
|
bool(self.inviter_id),
|
||||||
bool(by_activity and self.highlights),
|
bool(by_activity and self._sorting("highlights")),
|
||||||
bool(by_activity and self.unreads),
|
bool(by_activity and self._sorting("unreads")),
|
||||||
bool(by_activity and self.local_unreads),
|
bool(by_activity and self._sorting("local_unreads")),
|
||||||
self.last_event_date if by_activity else ZERO_DATE,
|
self._sorting("last_event_date") if by_activity else ZERO_DATE,
|
||||||
(other.display_name or other.id).lower(),
|
(other.display_name or other.id).lower(),
|
||||||
other.id,
|
other.id,
|
||||||
)
|
)
|
||||||
|
@ -233,10 +242,10 @@ class AccountOrRoom(Account, Room):
|
||||||
other.pinned,
|
other.pinned,
|
||||||
self.left,
|
self.left,
|
||||||
bool(other.inviter_id),
|
bool(other.inviter_id),
|
||||||
bool(by_activity and other.highlights),
|
bool(by_activity and other._sorting("highlights")),
|
||||||
bool(by_activity and other.unreads),
|
bool(by_activity and other._sorting("unreads")),
|
||||||
bool(by_activity and other.local_unreads),
|
bool(by_activity and other._sorting("local_unreads")),
|
||||||
other.last_event_date if by_activity else ZERO_DATE,
|
other._sorting("last_event_date") if by_activity else ZERO_DATE,
|
||||||
(self.display_name or self.id).lower(),
|
(self.display_name or self.id).lower(),
|
||||||
self.id,
|
self.id,
|
||||||
|
|
||||||
|
@ -247,10 +256,10 @@ class AccountOrRoom(Account, Room):
|
||||||
self.pinned,
|
self.pinned,
|
||||||
other.left,
|
other.left,
|
||||||
bool(self.inviter_id),
|
bool(self.inviter_id),
|
||||||
bool(by_activity and self.highlights),
|
bool(by_activity and self._sorting("highlights")),
|
||||||
bool(by_activity and self.unreads),
|
bool(by_activity and self._sorting("unreads")),
|
||||||
bool(by_activity and self.local_unreads),
|
bool(by_activity and self._sorting("local_unreads")),
|
||||||
self.last_event_date if by_activity else ZERO_DATE,
|
self._sorting("last_event_date") if by_activity else ZERO_DATE,
|
||||||
(other.display_name or other.id).lower(),
|
(other.display_name or other.id).lower(),
|
||||||
other.id,
|
other.id,
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,7 +14,9 @@ HColumnPage {
|
||||||
id: chatPage
|
id: chatPage
|
||||||
|
|
||||||
property string loadMembersFutureId: ""
|
property string loadMembersFutureId: ""
|
||||||
|
property var lockedRoom: null // null or [userId, roomId]
|
||||||
|
|
||||||
|
readonly property var userRoomId: chat.userRoomId
|
||||||
readonly property alias roomHeader: roomHeader
|
readonly property alias roomHeader: roomHeader
|
||||||
readonly property alias eventList: eventList
|
readonly property alias eventList: eventList
|
||||||
readonly property alias typingMembers: typingMembers
|
readonly property alias typingMembers: typingMembers
|
||||||
|
@ -30,11 +32,26 @@ HColumnPage {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function lockRoomPosition(lock) {
|
||||||
|
if (lock && lockedRoom) py.callClientCoro(
|
||||||
|
lockedRoom[0], "lock_room_position", [lockedRoom[1], false],
|
||||||
|
)
|
||||||
|
|
||||||
|
lockedRoom = lock ? [chat.userId, chat.roomId] : null
|
||||||
|
py.callClientCoro(
|
||||||
|
chat.userId, "lock_room_position", [chat.roomId, lock],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
padding: 0
|
padding: 0
|
||||||
column.spacing: 0
|
column.spacing: 0
|
||||||
|
|
||||||
Component.onDestruction:
|
onUserRoomIdChanged: lockRoomPosition(true)
|
||||||
|
Component.onDestruction: {
|
||||||
|
lockRoomPosition(false)
|
||||||
if (loadMembersFutureId) py.cancelCoro(loadMembersFutureId)
|
if (loadMembersFutureId) py.cancelCoro(loadMembersFutureId)
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
interval: 200
|
interval: 200
|
||||||
|
|
Loading…
Reference in New Issue
Block a user