Improve room past events loading

- Trigger when room is shown if there's not enough messages to fill the
  list height

- Trigger whenever user is scrolling before a certain point, instead of
  when dragging is released/scrolling stopped and the top edge is hit

- Prevent multiple load requests at same time

- Keep a set of fully loaded rooms, don't request anymore history
  if a room is fully loaded
This commit is contained in:
miruka 2019-04-17 22:34:22 -04:00
parent a0f9acddaa
commit 6ab4acdc84
5 changed files with 39 additions and 9 deletions

View File

@ -30,3 +30,7 @@
- Push instead of replacing in stack view - Push instead of replacing in stack view
- QQuickImageProvider, matrix preview API - QQuickImageProvider, matrix preview API
- Spinner when loading past room events or images
- nio: org.matrix.room.preview\_urls, m.room.aliases

View File

@ -2,20 +2,21 @@
# This file is part of harmonyqml, licensed under GPLv3. # This file is part of harmonyqml, licensed under GPLv3.
import hashlib import hashlib
from typing import Dict from typing import Dict, Set
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
from .client_manager import ClientManager from .client_manager import ClientManager
from .html_filter import HtmlFilter
from .model.items import User from .model.items import User
from .model.qml_models import QMLModels from .model.qml_models import QMLModels
from .html_filter import HtmlFilter
class Backend(QObject): class Backend(QObject):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self.past_tokens: Dict[str, str] = {} self.past_tokens: Dict[str, str] = {}
self.fully_loaded_rooms: Set[str] = set()
self._client_manager: ClientManager = ClientManager() self._client_manager: ClientManager = ClientManager()
self._models: QMLModels = QMLModels() self._models: QMLModels = QMLModels()
@ -61,13 +62,19 @@ class Backend(QObject):
@pyqtSlot(str) @pyqtSlot(str)
def loadPastEvents(self, room_id: str) -> None: @pyqtSlot(str, int)
def loadPastEvents(self, room_id: str, limit: int = 100) -> None:
if not room_id in self.past_tokens: if not room_id in self.past_tokens:
return # Initial sync not done yet return # Initial sync not done yet
if room_id in self.fully_loaded_rooms:
return
for client in self.clientManager.clients.values(): for client in self.clientManager.clients.values():
if room_id in client.nio.rooms: if room_id in client.nio.rooms:
client.loadPastEvents(room_id, self.past_tokens[room_id]) client.loadPastEvents(
room_id, self.past_tokens[room_id], limit
)
break break
else: else:
raise ValueError(f"Room not found in any client: {room_id}") raise ValueError(f"Room not found in any client: {room_id}")

View File

@ -69,6 +69,8 @@ class Client(QObject):
self.net = NetworkManager(self.host, self.port, self.nio) self.net = NetworkManager(self.host, self.port, self.nio)
self.net_sync = NetworkManager(self.host, self.port, self.nio_sync) self.net_sync = NetworkManager(self.host, self.port, self.nio_sync)
self._loading: bool = False
self._stop_sync: Event = Event() self._stop_sync: Event = Event()
@ -157,14 +159,22 @@ class Client(QObject):
@futurize @futurize
def loadPastEvents(self, room_id: str, start_token: str) -> None: def loadPastEvents(self, room_id: str, start_token: str, limit: int = 100
) -> None:
# From QML, use Backend.loastPastEvents instead # From QML, use Backend.loastPastEvents instead
if self._loading:
return
self._loading = True
print("load", limit)
self._on_past_events( self._on_past_events(
room_id, room_id,
self.net.talk( self.net.talk(
self.nio.room_messages, room_id, start=start_token, limit=100 self.nio.room_messages, room_id, start=start_token, limit=limit
) )
) )
self._loading = False
def _on_past_events(self, room_id: str, response: nr.RoomMessagesResponse def _on_past_events(self, room_id: str, response: nr.RoomMessagesResponse

View File

@ -93,6 +93,9 @@ class SignalManager(QObject):
self, _: Client, room_id: str, token: str self, _: Client, room_id: str, token: str
) -> None: ) -> None:
if self.backend.past_tokens[room_id] == token:
self.backend.fully_loaded_rooms.add(room_id)
self.backend.past_tokens[room_id] = token self.backend.past_tokens[room_id] = token

View File

@ -26,8 +26,14 @@ Rectangle {
// reloaded from network. // reloaded from network.
cacheBuffer: height * 6 cacheBuffer: height * 6
onMovementEnded: if (atYBeginning) { // Declaring this "alias" provides the on... signal
Backend.loadPastEvents(chatPage.room.room_id) property real yPos: visibleArea.yPosition
onYPosChanged: {
console.log(yPos)
if (yPos <= 0.1) {
Backend.loadPastEvents(chatPage.room.room_id)
}
} }
} }
} }