diff --git a/TODO.md b/TODO.md index 727970bc..e3b72586 100644 --- a/TODO.md +++ b/TODO.md @@ -2,8 +2,8 @@ ## Before release -- Catch 5xx errors and retry -- nio ClientTimeout +- Catch server 5xx errors when sending message and retry +- nio ClientTimeout (to fix sync hanging after network changes or hibernation) - Update docstrings - Update README.md diff --git a/src/backend/matrix_client.py b/src/backend/matrix_client.py index a5acdace..dc742448 100644 --- a/src/backend/matrix_client.py +++ b/src/backend/matrix_client.py @@ -117,6 +117,7 @@ class MatrixClient(nio.AsyncClient): self.load_rooms_task: Optional[asyncio.Future] = None self.upload_monitors: Dict[UUID, nio.TransferMonitor] = {} + self.upload_tasks: Dict[UUID, asyncio.Task] = {} self.first_sync_done: asyncio.Event = asyncio.Event() self.first_sync_date: Optional[datetime] = None @@ -336,7 +337,7 @@ class MatrixClient(nio.AsyncClient): if isinstance(uuid, str): uuid = UUID(uuid) - self.upload_monitors[uuid].cancel = True + self.upload_tasks[uuid].cancel() async def send_file(self, room_id: str, path: Union[Path, str]) -> None: @@ -349,6 +350,7 @@ class MatrixClient(nio.AsyncClient): except (nio.TransferCancelledError, asyncio.CancelledError): log.info("Deleting item for cancelled upload %s", item_uuid) del self.upload_monitors[item_uuid] + del self.upload_tasks[item_uuid] del self.models[room_id, "uploads"][str(item_uuid)] @@ -373,9 +375,11 @@ class MatrixClient(nio.AsyncClient): monitor = nio.TransferMonitor(size) upload_item = Upload(item_uuid, path, total_size=size) - self.upload_monitors[item_uuid] = monitor self.models[room_id, "uploads"][str(item_uuid)] = upload_item + self.upload_monitors[item_uuid] = monitor + self.upload_tasks[item_uuid] = asyncio.current_task() # type: ignore + def on_transferred(transferred: int) -> None: upload_item.uploaded = transferred @@ -539,6 +543,7 @@ class MatrixClient(nio.AsyncClient): content["filename"] = path.name del self.upload_monitors[item_uuid] + del self.upload_tasks[item_uuid] del self.models[room_id, "uploads"][str(upload_item.id)] await self._local_echo( diff --git a/src/gui/Pages/Chat/FileTransfer/Transfer.qml b/src/gui/Pages/Chat/FileTransfer/Transfer.qml index 4d9b2cb3..39d17b75 100644 --- a/src/gui/Pages/Chat/FileTransfer/Transfer.qml +++ b/src/gui/Pages/Chat/FileTransfer/Transfer.qml @@ -9,6 +9,8 @@ HColumnLayout { id: transfer + property bool cancelPending: false + property int msLeft: model.time_left property int uploaded: model.uploaded readonly property int speed: model.speed @@ -18,9 +20,7 @@ HColumnLayout { function cancel() { - // Python might take a sec to cancel, but we want - // immediate visual feedback - transfer.height = 0 + cancelPending = true // Python will delete this model item on cancel py.callClientCoro(chat.userId, "cancel_upload", [model.id]) } @@ -38,8 +38,12 @@ HColumnLayout { HIcon { svgName: "uploading" colorize: - transfer.status === "Error" ? theme.colors.negativeBackground : - transfer.paused ? theme.colors.middleBackground : + cancelPending || transfer.status === "Error" ? + theme.colors.negativeBackground : + + transfer.paused ? + theme.colors.middleBackground : + theme.icons.colorize Layout.preferredWidth: theme.baseElementsHeight @@ -51,7 +55,11 @@ HColumnLayout { wrapMode: expand ? Text.Wrap : Text.NoWrap text: - status === "Uploading" ? fileName : + cancelPending ? + qsTr("Cancelling...") : + + status === "Uploading" ? + fileName : status === "Caching" ? qsTr("Caching %1...").arg(fileName) : @@ -179,7 +187,7 @@ HColumnLayout { // TODO: bake this in hprogressbar foregroundColor: - status === "Error" ? + cancelPending || status === "Error" ? theme.controls.progressBar.errorForeground : transfer.paused ?