Show import keys error in the UI

This commit is contained in:
miruka 2019-08-28 11:42:52 -04:00
parent 7d2cbae26f
commit ce3404a516
8 changed files with 84 additions and 35 deletions

View File

@ -22,9 +22,7 @@ translated arg for avatar upload and login
- Fixes - Fixes
- Restore previous focus after closing right click context menu - Restore previous focus after closing right click context menu
- Run import in thread and AsyncClient.olm functions, they block async loop - Show error if uploading avatar fails
- Handle import keys errors
- Show error box if uploading avatar fails
- Don't strip user spacing in html - Don't strip user spacing in html
- Do something when access token is invalid - Do something when access token is invalid
@ -35,9 +33,7 @@ translated arg for avatar upload and login
- Terrible performance using `QT_QPA_PLATFORM=wayland-egl`, must use `xcb` - Terrible performance using `QT_QPA_PLATFORM=wayland-egl`, must use `xcb`
- UI - UI
- When starting a long task, e.g. importing keys, quitting the page, - Decrypt messages again after importing keys
and coming back, show the buttons as still loading until operation is done
- Choose a better default easing type for animations - Choose a better default easing type for animations
- Make invite icon blink if there's no one but ourself in the room, - Make invite icon blink if there's no one but ourself in the room,
but never do it again once the user hovered it long enough to show tooltip but never do it again once the user hovered it long enough to show tooltip

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M13.5 2c-5.629 0-10.212 4.436-10.475 10h-3.025l4.537 5.917 4.463-5.917h-2.975c.26-3.902 3.508-7 7.475-7 4.136 0 7.5 3.364 7.5 7.5s-3.364 7.5-7.5 7.5c-2.381 0-4.502-1.119-5.876-2.854l-1.847 2.449c1.919 2.088 4.664 3.405 7.723 3.405 5.798 0 10.5-4.702 10.5-10.5s-4.702-10.5-10.5-10.5z"/></svg>

After

Width:  |  Height:  |  Size: 383 B

View File

@ -304,17 +304,21 @@ class MatrixClient(nio.AsyncClient):
return True return True
async def import_keys(self, infile: str, passphrase: str) -> Optional[str]: async def import_keys(self, infile: str, passphrase: str) -> None:
# Reimplemented until better solutions are worked on in nio # Reimplemented until better solutions are worked on in nio
await self.clear_import_error()
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
account = self.models[Account][self.user_id]
import_keys = partial(self.olm.import_keys_static, infile, passphrase) import_keys = partial(self.olm.import_keys_static, infile, passphrase)
try: try:
sessions = await loop.run_in_executor(None, import_keys) sessions = await loop.run_in_executor(None, import_keys)
except nio.EncryptionError as err: except nio.EncryptionError as err:
return str(err) account.import_error = (infile, passphrase, str(err))
return
account = self.models[Account][self.user_id]
account.importing_key = 0 account.importing_key = 0
account.total_keys_to_import = len(sessions) account.total_keys_to_import = len(sessions)
@ -330,6 +334,10 @@ class MatrixClient(nio.AsyncClient):
return None return None
async def clear_import_error(self) -> None:
self.models[Account][self.user_id].import_error = ("", "", "")
# Functions to register data into models # Functions to register data into models
async def event_is_past(self, ev: Union[nio.Event, Event]) -> bool: async def event_is_past(self, ev: Union[nio.Event, Event]) -> bool:

View File

@ -1,7 +1,7 @@
import re import re
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional, Tuple
from ..html_filter import HTML_FILTER from ..html_filter import HTML_FILTER
from ..utils import AutoStrEnum, auto from ..utils import AutoStrEnum, auto
@ -16,8 +16,9 @@ class Account(ModelItem):
first_sync_done: bool = False first_sync_done: bool = False
profile_updated: Optional[datetime] = None profile_updated: Optional[datetime] = None
importing_key: int = 0 importing_key: int = 0
total_keys_to_import: int = 0 total_keys_to_import: int = 0
import_error: Tuple[str, str, str] = ("", "", "") # path,pw,err
def __lt__(self, other: "Account") -> bool: def __lt__(self, other: "Account") -> bool:
name = self.display_name or self.user_id[1:] name = self.display_name or self.user_id[1:]

View File

@ -10,7 +10,7 @@ Item {
rotation: 45 * 3 rotation: 45 * 3
gradient: Gradient { gradient: Gradient {
GradientStop { position: 0.0; color: Qt.hsla(0.73, 0.25, 0.25, 1) } GradientStop { position: 0.0; color: Qt.hsla(0.73, 0.25, 0.25, 1) }
GradientStop { position: 1.0; color: Qt.hsla(0.52, 1, 0.08, 1) } GradientStop { position: 1.0; color: Qt.hsla(0.52, 1, 0.06, 1) }
} }
} }

View File

@ -2,18 +2,39 @@ import QtQuick 2.12
import "../../Base" import "../../Base"
HLoader { HLoader {
id: loader property bool importing: false
source: accountInfo.total_keys_to_import ?
"ImportingKeys.qml" : "ImportExportKeys.qml"
function importKeys(file, passphrase, button=null) {
if (button) button.loading = true
importing = true
let path = file.toString().replace(/^file:\/\//, "")
py.callClientCoro(
editAccount.userId, "import_keys", [path, passphrase], () => {
importing = false
if (button) button.loading = false
}
)
}
id: encryptionUI
source:
accountInfo.import_error[0] ? "ImportError.qml" :
importing || accountInfo.total_keys_to_import ? "ImportingKeys.qml" :
"ImportExportKeys.qml"
onSourceChanged: animation.running = true onSourceChanged: animation.running = true
HNumberAnimation { SequentialAnimation {
id: animation id: animation
target: loader.item HNumberAnimation {
property: "scale" target: encryptionUI; property: "scale"; to: 0;
from: 0 }
to: 1 HNumberAnimation {
overshoot: 3 target: encryptionUI; property: "scale"; to: 1; overshoot: 3;
}
} }
} }

View File

@ -0,0 +1,33 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import "../../Base"
import "../../utils.js" as Utils
HInterfaceBox {
buttonModel: [
{ name: "retry", text: qsTr("Retry"), iconName: "retry" },
{ name: "cancel", text: qsTr("Cancel"), iconName: "cancel" },
]
buttonCallbacks: ({
retry: button => {
encryptionUI.importKeys(
accountInfo.import_error[0],
accountInfo.import_error[1],
button,
)
},
cancel: button => { py.callClientCoro(userId, "clear_import_error") },
})
HLabel {
color: theme.colors.errorText
wrapMode: Text.Wrap
text: qsTr("Couldn't import decryption keys file: %1")
.arg(qsTr(accountInfo.import_error[2]))
Layout.fillWidth: true
}
}

View File

@ -5,18 +5,6 @@ import "../../Base"
import "../../utils.js" as Utils import "../../utils.js" as Utils
HColumnLayout { HColumnLayout {
function importKeys(file, passphrase) {
importButton.loading = true
let path = file.toString().replace(/^file:\/\//, "")
py.callClientCoro(
editAccount.userId, "import_keys", [path, passphrase], () => {
if (importButton) importButton.loading = false
}
)
}
HLabel { HLabel {
wrapMode: Text.Wrap wrapMode: Text.Wrap
text: qsTr( text: qsTr(
@ -75,6 +63,7 @@ HColumnLayout {
label.text: qsTr( label.text: qsTr(
"Please enter the passphrase that was used to protect this file:" "Please enter the passphrase that was used to protect this file:"
) )
onAcceptedPasswordChanged: importKeys(file, acceptedPassword) onAcceptedPasswordChanged:
encryptionUI.importKeys(file, acceptedPassword, importButton)
} }
} }