diff --git a/TODO.md b/TODO.md index c1e6bb72..964ba087 100644 --- a/TODO.md +++ b/TODO.md @@ -57,6 +57,7 @@ - Quote links color in room subtitles (e.g. "> http://foo.orgA)" ) - UI + - Make theme error/etc text colors more like name colors - Standardize usage of punctuation - Way to open context menus without a right mouse button - `smartVerticalFlick()` gradual acceleration diff --git a/src/python/matrix_client.py b/src/python/matrix_client.py index abd336ed..3d0bfb2f 100644 --- a/src/python/matrix_client.py +++ b/src/python/matrix_client.py @@ -12,7 +12,7 @@ from typing import ( Any, DefaultDict, Dict, NamedTuple, Optional, Set, Tuple, Type, Union, ) from urllib.parse import urlparse -from uuid import uuid4 +from uuid import UUID, uuid4 import cairosvg from PIL import Image as PILImage @@ -211,17 +211,28 @@ class MatrixClient(nio.AsyncClient): async def send_file(self, room_id: str, path: Union[Path, str]) -> None: + item_uuid = uuid4() + + try: + await self._send_file(item_uuid, room_id, path) + except asyncio.CancelledError: + del self.models[Upload, room_id][item_uuid] + + + async def _send_file( + self, item_uuid: UUID, room_id: str, path: Union[Path, str], + ) -> None: from .media_cache import Media, Thumbnail path = Path(path) size = path.resolve().stat().st_size encrypt = room_id in self.encrypted_rooms - upload_item = Upload(path, total_size=size) + task = asyncio.Task.current_task() + upload_item = Upload(item_uuid, task, path, total_size=size) self.models[Upload, room_id][upload_item.uuid] = upload_item try: - raise MatrixError(111, "Ooops!") url, mime, crypt_dict = await self.upload( path, filename=path.name, encrypt=encrypt, ) @@ -229,7 +240,10 @@ class MatrixClient(nio.AsyncClient): upload_item.status = UploadStatus.Error upload_item.error = type(err) upload_item.error_args = err.args - return + + # Wait for cancellation, see parent send_file() method + while True: + await asyncio.sleep(0.1) upload_item.status = UploadStatus.Caching await Media.from_existing_file(self.backend.media_cache, url, path) diff --git a/src/python/models/items.py b/src/python/models/items.py index 0f961bdb..23f6bdb5 100644 --- a/src/python/models/items.py +++ b/src/python/models/items.py @@ -1,9 +1,10 @@ +import asyncio import re from dataclasses import dataclass, field from datetime import datetime from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Type, Union -from uuid import uuid4 +from uuid import UUID import lxml # nosec @@ -113,6 +114,8 @@ class UploadStatus(AutoStrEnum): @dataclass class Upload(ModelItem): + uuid: UUID = field() + task: asyncio.Task = field() filepath: Path = field() status: UploadStatus = UploadStatus.Uploading total_size: int = 0 @@ -120,7 +123,6 @@ class Upload(ModelItem): error: OptionalExceptionType = type(None) error_args: Tuple[Any, ...] = () - uuid: str = field(init=False, default_factory=lambda: str(uuid4())) start_date: datetime = field(init=False, default_factory=datetime.now) diff --git a/src/qml/Chat/UploadsBar.qml b/src/qml/Chat/UploadsBar.qml index ce0ffa99..d70ba493 100644 --- a/src/qml/Chat/UploadsBar.qml +++ b/src/qml/Chat/UploadsBar.qml @@ -35,7 +35,34 @@ Rectangle { id: delegate width: uploadsList.width + Behavior on height { HNumberAnimation {} } + + Binding { + id: hideBind + target: delegate + property: "height" + value: 0 + when: false + } + HRowLayout { + HButton { + icon.name: "cancel" + icon.color: theme.colors.negativeBackground + padded: false + + onClicked: { + // Python might take a sec to cancel, but we want + // immediate visual feedback + hideBind.when = true + // Python will delete this model item on cancel + py.call(py.getattr(model.task, "cancel")) + } + + Layout.preferredWidth: theme.baseElementsHeight + Layout.preferredHeight: Layout.preferredWidth + } + HLabel { id: statusLabel elide: expand ? Text.ElideNone : Text.ElideRight @@ -108,7 +135,8 @@ Rectangle { } TapHandler { - onTapped: statusLabel.expand = ! statusLabel.expand + onTapped: if (model.status !== "Error") + statusLabel.expand = ! statusLabel.expand } HoverHandler { id: infoRowHover }