diff --git a/TODO.md b/TODO.md index fb0b586f..90657970 100644 --- a/TODO.md +++ b/TODO.md @@ -16,6 +16,9 @@ - When qml syntax highlighting supports string interpolation, use them - Fixes + - Run import in thread ? Does it blocks the async loop? + - Handle import errors + - Update the room subtitle when a message is decrypted/edited - Don't linkify images for outgoing html - state: If last page is a room and the account for it is no longer present, load Default.qml instead @@ -29,6 +32,13 @@ - [hr not working](https://bugreports.qt.io/browse/QTBUG-74342) - UI + - Popup: + - label size + - Accept/cancel buttons + - Transitions + + - When starting a long task, e.g. importing keys, quitting the page, + and coming back, show the buttons as still loading until operation is done - Make invite/left banners look better in column mode - Messages editing - Code highlighting diff --git a/src/icons/dark-filled/export-keys.svg b/src/icons/dark-filled/export-keys.svg new file mode 100644 index 00000000..9b9b732c --- /dev/null +++ b/src/icons/dark-filled/export-keys.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/dark-filled/import-keys.svg b/src/icons/dark-filled/import-keys.svg new file mode 100644 index 00000000..51e5123b --- /dev/null +++ b/src/icons/dark-filled/import-keys.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/light-thin/export-keys.svg b/src/icons/light-thin/export-keys.svg new file mode 100644 index 00000000..55b716a5 --- /dev/null +++ b/src/icons/light-thin/export-keys.svg @@ -0,0 +1,32 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/icons/light-thin/import-keys.svg b/src/icons/light-thin/import-keys.svg new file mode 100644 index 00000000..b33a28ef --- /dev/null +++ b/src/icons/light-thin/import-keys.svg @@ -0,0 +1,32 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/qml/Base/HFileDialogOpener.qml b/src/qml/Base/HFileDialogOpener.qml index 9bfac066..bdd0c983 100644 --- a/src/qml/Base/HFileDialogOpener.qml +++ b/src/qml/Base/HFileDialogOpener.qml @@ -13,7 +13,7 @@ Item { property string file: "" enum FileType { All, Images } - property int fileType: FileType.All + property int fileType: HFileDialogOpener.FileType.All TapHandler { onTapped: fileDialog.open() } diff --git a/src/qml/Base/HPasswordPopup.qml b/src/qml/Base/HPasswordPopup.qml new file mode 100644 index 00000000..806e8f9a --- /dev/null +++ b/src/qml/Base/HPasswordPopup.qml @@ -0,0 +1,55 @@ +// Copyright 2019 miruka +// This file is part of harmonyqml, licensed under LGPLv3. + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import "../SidePane" + +Popup { + id: popup + width: window.width + anchors.centerIn: Overlay.overlay + modal: true + + onOpened: passwordField.forceActiveFocus() + + property alias label: popupLabel + property alias field: passwordField + property string password: "" + + background: HRectangle { + color: theme.controls.popup.background + } + + HColumnLayout { + width: parent.width + spacing: theme.spacing + + HLabel { + id: popupLabel + wrapMode: Text.Wrap + + Layout.alignment: Qt.AlignCenter + Layout.minimumWidth: theme.minimumSupportedWidth + Layout.maximumWidth: + Math.min(480, window.width - theme.spacing * 2) + } + + HTextField { + id: passwordField + echoMode: TextInput.Password + focus: true + onAccepted: { + popup.password = text + popup.close() + } + + Layout.alignment: Qt.AlignCenter + Layout.fillWidth: true + + Layout.preferredWidth: popupLabel.width + Layout.maximumWidth: popupLabel.width + } + } +} diff --git a/src/qml/Pages/EditAccount/ClientSettings.qml b/src/qml/Pages/EditAccount/ClientSettings.qml deleted file mode 100644 index 742ae0ab..00000000 --- a/src/qml/Pages/EditAccount/ClientSettings.qml +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2019 miruka -// This file is part of harmonyqml, licensed under LGPLv3. - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 -import "../../Base" -import "../../utils.js" as Utils - -HLabel { - text: "Client - TODO" -} diff --git a/src/qml/Pages/EditAccount/Devices.qml b/src/qml/Pages/EditAccount/Devices.qml deleted file mode 100644 index 1e8cb0a6..00000000 --- a/src/qml/Pages/EditAccount/Devices.qml +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2019 miruka -// This file is part of harmonyqml, licensed under LGPLv3. - -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 -import "../../Base" -import "../../utils.js" as Utils - -HLabel { - text: "Devices - TODO" -} diff --git a/src/qml/Pages/EditAccount/EditAccount.qml b/src/qml/Pages/EditAccount/EditAccount.qml index 3d2478d0..94fa7fd7 100644 --- a/src/qml/Pages/EditAccount/EditAccount.qml +++ b/src/qml/Pages/EditAccount/EditAccount.qml @@ -24,21 +24,32 @@ HPage { Utils.coloredNameHtml(headerName, userId) ) - HRectangle { - color: ready ? theme.controls.box.background : "transparent" - Behavior on color { HColorAnimation {} } + HSpacer {} - Layout.alignment: Qt.AlignCenter + Repeater { + model: ["Profile.qml", "Encryption.qml"] - Layout.maximumWidth: Math.min(parent.width, 640) - Layout.preferredWidth: - pageStack.isWide ? parent.width : avatarPreferredSize + HRectangle { + color: ready ? theme.controls.box.background : "transparent" + Behavior on color { HColorAnimation {} } - Layout.preferredHeight: childrenRect.height + Layout.alignment: Qt.AlignCenter - Loader { - width: parent.width - source: ready ? "Profile.qml" : "../../Base/HBusyIndicator.qml" + Layout.maximumWidth: Math.min(parent.width, 640) + Layout.preferredWidth: + pageStack.isWide ? parent.width : avatarPreferredSize + + Layout.preferredHeight: childrenRect.height + + Loader { + width: parent.width + source: ready ? + modelData : + (modelData == "Profile.qml" ? + "../../Base/HBusyIndicator.qml" : "") + } } } + + HSpacer {} } diff --git a/src/qml/Pages/EditAccount/Encryption.qml b/src/qml/Pages/EditAccount/Encryption.qml new file mode 100644 index 00000000..02c1ada8 --- /dev/null +++ b/src/qml/Pages/EditAccount/Encryption.qml @@ -0,0 +1,79 @@ +// Copyright 2019 miruka +// This file is part of harmonyqml, licensed under LGPLv3. + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import "../../Base" +import "../../utils.js" as Utils + +HColumnLayout { + function importKeys(file, passphrase) { + importButton.loading = true + + let path = Qt.resolvedUrl(file).replace(/^file:\/\//, "") + + py.callClientCoro( + editAccount.userId, "import_keys", [path, passphrase], () => { + importButton.loading = false + } + ) + } + + HLabel { + wrapMode: Text.Wrap + text: qsTr( + "The decryption keys for the messages you received in " + + "encrypted rooms can be exported to a file.%1" + + "You will then be able to import this file in another " + + "Matrix client." + ).arg(pageStack.isWide ? "\n" :"\n\n") + + Layout.fillWidth: true + Layout.margins: currentSpacing + } + + HRowLayout { + HUIButton { + id: exportButton + iconName: "export-keys" + text: qsTr("Export") + enabled: false + + Layout.fillWidth: true + Layout.alignment: Qt.AlignBottom + } + + HUIButton { + id: importButton + iconName: "import-keys" + text: qsTr("Import") + + Layout.fillWidth: true + Layout.alignment: Qt.AlignBottom + + HFileDialogOpener { + id: fileDialog + dialog.title: qsTr("Select a decryption key file to import") + onFileChanged: { + importPasswordPopup.file = file + importPasswordPopup.open() + } + } + } + } + + HPasswordPopup { + property url file: "" + + id: importPasswordPopup + label.text: qsTr( + "Please enter the passphrase that was used to protect this " + + "file.\n\n" + + "The import can take a few minutes. " + + "You can leave the account settings page while it is running. " + + "Messages may not be sent or received until the operation is done." + ) + onPasswordChanged: importKeys(file, password) + } +} diff --git a/src/themes/Default.qpl b/src/themes/Default.qpl index c2e86d92..64d81caf 100644 --- a/src/themes/Default.qpl +++ b/src/themes/Default.qpl @@ -72,6 +72,9 @@ controls: color background: colors.strongBackground int radius: theme.radius + popup: + color background: colors.strongBackground + header: color background: colors.strongBackground