Add ability to cancel uploads

This commit is contained in:
miruka 2019-12-02 05:06:21 -04:00
parent ae009c7412
commit 3919b964ca
4 changed files with 52 additions and 7 deletions

View File

@ -57,6 +57,7 @@
- Quote links color in room subtitles (e.g. "> http://foo.orgA)" ) - Quote links color in room subtitles (e.g. "> http://foo.orgA)" )
- UI - UI
- Make theme error/etc text colors more like name colors
- Standardize usage of punctuation - Standardize usage of punctuation
- Way to open context menus without a right mouse button - Way to open context menus without a right mouse button
- `smartVerticalFlick()` gradual acceleration - `smartVerticalFlick()` gradual acceleration

View File

@ -12,7 +12,7 @@ from typing import (
Any, DefaultDict, Dict, NamedTuple, Optional, Set, Tuple, Type, Union, Any, DefaultDict, Dict, NamedTuple, Optional, Set, Tuple, Type, Union,
) )
from urllib.parse import urlparse from urllib.parse import urlparse
from uuid import uuid4 from uuid import UUID, uuid4
import cairosvg import cairosvg
from PIL import Image as PILImage 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: 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 from .media_cache import Media, Thumbnail
path = Path(path) path = Path(path)
size = path.resolve().stat().st_size size = path.resolve().stat().st_size
encrypt = room_id in self.encrypted_rooms 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 self.models[Upload, room_id][upload_item.uuid] = upload_item
try: try:
raise MatrixError(111, "Ooops!")
url, mime, crypt_dict = await self.upload( url, mime, crypt_dict = await self.upload(
path, filename=path.name, encrypt=encrypt, path, filename=path.name, encrypt=encrypt,
) )
@ -229,7 +240,10 @@ class MatrixClient(nio.AsyncClient):
upload_item.status = UploadStatus.Error upload_item.status = UploadStatus.Error
upload_item.error = type(err) upload_item.error = type(err)
upload_item.error_args = err.args 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 upload_item.status = UploadStatus.Caching
await Media.from_existing_file(self.backend.media_cache, url, path) await Media.from_existing_file(self.backend.media_cache, url, path)

View File

@ -1,9 +1,10 @@
import asyncio
import re import re
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, Type, Union from typing import Any, Dict, List, Optional, Tuple, Type, Union
from uuid import uuid4 from uuid import UUID
import lxml # nosec import lxml # nosec
@ -113,6 +114,8 @@ class UploadStatus(AutoStrEnum):
@dataclass @dataclass
class Upload(ModelItem): class Upload(ModelItem):
uuid: UUID = field()
task: asyncio.Task = field()
filepath: Path = field() filepath: Path = field()
status: UploadStatus = UploadStatus.Uploading status: UploadStatus = UploadStatus.Uploading
total_size: int = 0 total_size: int = 0
@ -120,7 +123,6 @@ class Upload(ModelItem):
error: OptionalExceptionType = type(None) error: OptionalExceptionType = type(None)
error_args: Tuple[Any, ...] = () error_args: Tuple[Any, ...] = ()
uuid: str = field(init=False, default_factory=lambda: str(uuid4()))
start_date: datetime = field(init=False, default_factory=datetime.now) start_date: datetime = field(init=False, default_factory=datetime.now)

View File

@ -35,7 +35,34 @@ Rectangle {
id: delegate id: delegate
width: uploadsList.width width: uploadsList.width
Behavior on height { HNumberAnimation {} }
Binding {
id: hideBind
target: delegate
property: "height"
value: 0
when: false
}
HRowLayout { 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 { HLabel {
id: statusLabel id: statusLabel
elide: expand ? Text.ElideNone : Text.ElideRight elide: expand ? Text.ElideNone : Text.ElideRight
@ -108,7 +135,8 @@ Rectangle {
} }
TapHandler { TapHandler {
onTapped: statusLabel.expand = ! statusLabel.expand onTapped: if (model.status !== "Error")
statusLabel.expand = ! statusLabel.expand
} }
HoverHandler { id: infoRowHover } HoverHandler { id: infoRowHover }