Rename EditAccount to AccountSettings
This commit is contained in:
62
src/qml/Pages/AccountSettings/AccountSettings.qml
Normal file
62
src/qml/Pages/AccountSettings/AccountSettings.qml
Normal file
@@ -0,0 +1,62 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../utils.js" as Utils
|
||||
|
||||
HPage {
|
||||
id: accountSettings
|
||||
|
||||
property int avatarPreferredSize: 256
|
||||
|
||||
property string userId: ""
|
||||
|
||||
readonly property bool ready:
|
||||
accountInfo !== "waiting" && Boolean(accountInfo.profile_updated)
|
||||
|
||||
readonly property var accountInfo: Utils.getItem(
|
||||
modelSources["Account"] || [], "user_id", userId
|
||||
) || "waiting"
|
||||
|
||||
property string headerName: ready ? accountInfo.display_name : userId
|
||||
|
||||
hideHeaderUnderHeight: avatarPreferredSize
|
||||
headerLabel.text: qsTr("Account settings for %1").arg(
|
||||
Utils.coloredNameHtml(headerName, userId)
|
||||
)
|
||||
|
||||
|
||||
HSpacer {}
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: ["Profile.qml", "Encryption.qml"]
|
||||
|
||||
Rectangle {
|
||||
color: ready ? theme.controls.box.background : "transparent"
|
||||
Behavior on color { HColorAnimation {} }
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: header.visible || index > 0 ? theme.spacing : 0
|
||||
Layout.bottomMargin:
|
||||
header.visible || index < repeater.count - 1? theme.spacing : 0
|
||||
|
||||
Layout.maximumWidth: Math.min(parent.width, 640)
|
||||
Layout.preferredWidth:
|
||||
pageLoader.isWide ? parent.width : avatarPreferredSize
|
||||
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
|
||||
HLoader {
|
||||
anchors.centerIn: parent
|
||||
width: ready ? parent.width : 96
|
||||
source: ready ?
|
||||
modelData :
|
||||
(modelData == "Profile.qml" ?
|
||||
"../../Base/HBusyIndicator.qml" : "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HSpacer {}
|
||||
}
|
23
src/qml/Pages/AccountSettings/Encryption.qml
Normal file
23
src/qml/Pages/AccountSettings/Encryption.qml
Normal file
@@ -0,0 +1,23 @@
|
||||
import QtQuick 2.12
|
||||
import "../../Base"
|
||||
|
||||
HLoader {
|
||||
id: encryptionUI
|
||||
source:
|
||||
accountInfo.import_error[0] ? "ImportError.qml" :
|
||||
accountInfo.total_keys_to_import ? "ImportingKeys.qml" :
|
||||
"ImportExportKeys.qml"
|
||||
|
||||
onSourceChanged: animation.running = true
|
||||
|
||||
|
||||
SequentialAnimation {
|
||||
id: animation
|
||||
HNumberAnimation {
|
||||
target: encryptionUI; property: "scale"; to: 0;
|
||||
}
|
||||
HNumberAnimation {
|
||||
target: encryptionUI; property: "scale"; to: 1; overshoot: 3;
|
||||
}
|
||||
}
|
||||
}
|
36
src/qml/Pages/AccountSettings/ImportError.qml
Normal file
36
src/qml/Pages/AccountSettings/ImportError.qml
Normal file
@@ -0,0 +1,36 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../utils.js" as Utils
|
||||
|
||||
HBox {
|
||||
horizontalSpacing: currentSpacing
|
||||
verticalSpacing: currentSpacing
|
||||
|
||||
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
|
||||
}
|
||||
}
|
50
src/qml/Pages/AccountSettings/ImportExportKeys.qml
Normal file
50
src/qml/Pages/AccountSettings/ImportExportKeys.qml
Normal file
@@ -0,0 +1,50 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../utils.js" as Utils
|
||||
|
||||
HBox {
|
||||
horizontalSpacing: currentSpacing
|
||||
verticalSpacing: currentSpacing
|
||||
|
||||
buttonModel: [
|
||||
{ name: "export", text: qsTr("Export"), iconName: "export-keys"},
|
||||
{ name: "import", text: qsTr("Import"), iconName: "import-keys"},
|
||||
]
|
||||
|
||||
buttonCallbacks: ({
|
||||
export: button => {
|
||||
Utils.makeObject(
|
||||
"Dialogs/ExportKeys.qml",
|
||||
accountSettings,
|
||||
{ userId: accountSettings.userId },
|
||||
obj => {
|
||||
button.loading = Qt.binding(() => obj.exporting)
|
||||
obj.dialog.open()
|
||||
}
|
||||
)
|
||||
},
|
||||
import: button => {
|
||||
Utils.makeObject(
|
||||
"Dialogs/ImportKeys.qml",
|
||||
accountSettings,
|
||||
{ userId: accountSettings.userId },
|
||||
obj => { obj.dialog.open() }
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
HLabel {
|
||||
wrapMode: Text.Wrap
|
||||
text: qsTr(
|
||||
"The decryption keys for messages you received in encrypted " +
|
||||
"rooms can be exported to a passphrase-protected file.\n\n" +
|
||||
|
||||
"You can then import this file on any Matrix account or " +
|
||||
"client, to be able to decrypt these messages again."
|
||||
)
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
57
src/qml/Pages/AccountSettings/ImportingKeys.qml
Normal file
57
src/qml/Pages/AccountSettings/ImportingKeys.qml
Normal file
@@ -0,0 +1,57 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
|
||||
HColumnLayout {
|
||||
readonly property int progress: accountInfo.importing_key
|
||||
|
||||
onProgressChanged: iconAnimation.restart()
|
||||
|
||||
|
||||
HRowLayout {
|
||||
HIcon {
|
||||
id: icon
|
||||
svgName: "import-keys"
|
||||
|
||||
Layout.margins: currentSpacing
|
||||
|
||||
SequentialAnimation {
|
||||
id: iconAnimation
|
||||
|
||||
HNumberAnimation { target: icon; property: "opacity"; to: 0.6 }
|
||||
HNumberAnimation { target: icon; property: "opacity"; to: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
HLabel {
|
||||
text: qsTr("Importing decryption keys...")
|
||||
elide: Text.ElideRight
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: currentSpacing
|
||||
Layout.leftMargin: 0
|
||||
Layout.rightMargin: 0
|
||||
}
|
||||
|
||||
HLabel {
|
||||
text: progressBar.indeterminate ?
|
||||
qsTr("Preparing...") :
|
||||
qsTr("%1/%2")
|
||||
.arg(Math.ceil(progressBar.value)).arg(progressBar.to)
|
||||
|
||||
Layout.margins: currentSpacing
|
||||
}
|
||||
}
|
||||
|
||||
HProgressBar {
|
||||
id: progressBar
|
||||
from: 0
|
||||
value: progress
|
||||
to: accountInfo.total_keys_to_import
|
||||
indeterminate: accountInfo.total_keys_to_import < 0
|
||||
|
||||
Behavior on value { HNumberAnimation { factor: 5 } }
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
221
src/qml/Pages/AccountSettings/Profile.qml
Normal file
221
src/qml/Pages/AccountSettings/Profile.qml
Normal file
@@ -0,0 +1,221 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../Dialogs"
|
||||
import "../../utils.js" as Utils
|
||||
|
||||
HGridLayout {
|
||||
function applyChanges() {
|
||||
if (nameField.changed) {
|
||||
saveButton.nameChangeRunning = true
|
||||
|
||||
py.callClientCoro(
|
||||
userId, "set_displayname", [nameField.field.text], () => {
|
||||
saveButton.nameChangeRunning = false
|
||||
accountSettings.headerName =
|
||||
Qt.binding(() => accountInfo.display_name)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (aliasField.changed) {
|
||||
window.settings.writeAliases[userId] = aliasField.field.text
|
||||
window.settingsChanged()
|
||||
}
|
||||
|
||||
if (avatar.changed) {
|
||||
saveButton.avatarChangeRunning = true
|
||||
|
||||
let path =
|
||||
Qt.resolvedUrl(avatar.sourceOverride).replace(/^file:/, "")
|
||||
|
||||
py.callClientCoro(userId, "set_avatar_from_file", [path], () => {
|
||||
saveButton.avatarChangeRunning = false
|
||||
}, (errType, [httpCode]) => {
|
||||
console.error("Avatar upload failed:", httpCode, errType)
|
||||
saveButton.avatarChangeRunning = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function cancelChanges() {
|
||||
nameField.field.text = accountInfo.display_name
|
||||
aliasField.field.text = aliasField.currentAlias
|
||||
fileDialog.selectedFile = ""
|
||||
fileDialog.file = ""
|
||||
|
||||
accountSettings.headerName = Qt.binding(() => accountInfo.display_name)
|
||||
}
|
||||
|
||||
columns: 2
|
||||
flow: pageLoader.isWide ? GridLayout.LeftToRight : GridLayout.TopToBottom
|
||||
rowSpacing: currentSpacing
|
||||
|
||||
Component.onCompleted: nameField.field.forceActiveFocus()
|
||||
|
||||
HUserAvatar {
|
||||
property bool changed: Boolean(sourceOverride)
|
||||
|
||||
id: avatar
|
||||
clientUserId: accountSettings.userId
|
||||
userId: accountSettings.userId
|
||||
displayName: nameField.field.text
|
||||
mxc: accountInfo.avatar_url
|
||||
toolTipMxc: ""
|
||||
sourceOverride: fileDialog.selectedFile || fileDialog.file
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Layout.preferredWidth: Math.min(flickable.height, avatarPreferredSize)
|
||||
Layout.preferredHeight: Layout.preferredWidth
|
||||
|
||||
Rectangle {
|
||||
z: 10
|
||||
visible: opacity > 0
|
||||
opacity: ! fileDialog.dialog.visible &&
|
||||
((! avatar.mxc && ! avatar.changed) || avatar.hovered) ?
|
||||
1 : 0
|
||||
|
||||
anchors.fill: parent
|
||||
color: Utils.hsluv(0, 0, 0,
|
||||
(! avatar.mxc && overlayHover.hovered) ? 0.8 : 0.7
|
||||
)
|
||||
|
||||
Behavior on opacity { HNumberAnimation {} }
|
||||
Behavior on color { HColorAnimation {} }
|
||||
|
||||
HoverHandler { id: overlayHover }
|
||||
|
||||
HColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: currentSpacing
|
||||
width: parent.width
|
||||
|
||||
HIcon {
|
||||
svgName: "upload-avatar"
|
||||
colorize: (! avatar.mxc && overlayHover.hovered) ?
|
||||
theme.colors.accentText : theme.icons.colorize
|
||||
dimension: 64
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: theme.spacing }
|
||||
|
||||
HLabel {
|
||||
text: avatar.mxc ?
|
||||
qsTr("Change profile picture") :
|
||||
qsTr("Upload profile picture")
|
||||
|
||||
color: (! avatar.mxc && overlayHover.hovered) ?
|
||||
theme.colors.accentText : theme.colors.brightText
|
||||
Behavior on color { HColorAnimation {} }
|
||||
|
||||
font.pixelSize: theme.fontSize.big *
|
||||
avatar.height / avatarPreferredSize
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HFileDialogOpener {
|
||||
id: fileDialog
|
||||
fileType: HFileDialogOpener.FileType.Images
|
||||
dialog.title: qsTr("Select profile picture for %1")
|
||||
.arg(accountInfo.display_name)
|
||||
}
|
||||
}
|
||||
|
||||
HColumnLayout {
|
||||
id: profileInfo
|
||||
spacing: theme.spacing
|
||||
|
||||
HColumnLayout {
|
||||
spacing: theme.spacing
|
||||
Layout.margins: currentSpacing
|
||||
|
||||
HLabel {
|
||||
text: qsTr("User ID:<br>%1")
|
||||
.arg(Utils.coloredNameHtml(userId, userId, userId))
|
||||
textFormat: Text.StyledText
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
HLabeledTextField {
|
||||
property bool changed: field.text != accountInfo.display_name
|
||||
|
||||
readonly property string fText: field.text
|
||||
onFTextChanged: accountSettings.headerName = field.text
|
||||
|
||||
id: nameField
|
||||
label.text: qsTr("Display name:")
|
||||
field.onAccepted: applyChanges()
|
||||
|
||||
Component.onCompleted: field.text = accountInfo.display_name
|
||||
|
||||
Keys.onEscapePressed: cancelChanges()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 480
|
||||
}
|
||||
|
||||
HLabeledTextField {
|
||||
property string currentAlias:
|
||||
window.settings.writeAliases[userId] || ""
|
||||
|
||||
property bool changed: field.text != currentAlias
|
||||
|
||||
id: aliasField
|
||||
label.text: qsTr("Write alias:")
|
||||
field.onAccepted: applyChanges()
|
||||
|
||||
Component.onCompleted: field.text = currentAlias
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 480
|
||||
|
||||
Keys.onEscapePressed: cancelChanges()
|
||||
}
|
||||
}
|
||||
|
||||
HSpacer {}
|
||||
|
||||
HRowLayout {
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
|
||||
HButton {
|
||||
property bool nameChangeRunning: false
|
||||
property bool avatarChangeRunning: false
|
||||
|
||||
id: saveButton
|
||||
icon.name: "apply"
|
||||
icon.color: theme.colors.positiveBackground
|
||||
text: qsTr("Save")
|
||||
loading: nameChangeRunning || avatarChangeRunning
|
||||
enabled:
|
||||
nameField.changed || aliasField.changed || avatar.changed
|
||||
onClicked: applyChanges()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
}
|
||||
|
||||
HButton {
|
||||
icon.name: "cancel"
|
||||
icon.color: theme.colors.negativeBackground
|
||||
text: qsTr("Cancel")
|
||||
enabled: saveButton.enabled && ! saveButton.loading
|
||||
onClicked: cancelChanges()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user