2020-09-24 09:57:54 +10:00
|
|
|
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
2020-06-25 22:32:08 +10:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
|
|
|
|
import QtQuick 2.12
|
|
|
|
import QtQuick.Controls 2.12
|
|
|
|
import QtQuick.Layouts 1.12
|
|
|
|
import "../.."
|
|
|
|
import "../../Base"
|
2020-07-12 12:52:14 +10:00
|
|
|
import "../../Base/Buttons"
|
2020-06-25 22:32:08 +10:00
|
|
|
import "../../Dialogs"
|
|
|
|
|
|
|
|
HFlickableColumnPage {
|
|
|
|
id: page
|
|
|
|
|
|
|
|
property string userId
|
|
|
|
readonly property QtObject account: ModelStore.get("accounts").find(userId)
|
2020-06-25 23:59:40 +10:00
|
|
|
readonly property bool ready: account && account.profile_updated >= new Date(1)
|
2020-06-25 22:32:08 +10:00
|
|
|
|
|
|
|
function takeFocus() {
|
|
|
|
nameField.item.forceActiveFocus()
|
|
|
|
}
|
|
|
|
|
|
|
|
function applyChanges() {
|
|
|
|
if (nameField.item.changed) {
|
|
|
|
saveButton.nameChangeRunning = true
|
|
|
|
|
|
|
|
py.callClientCoro(
|
|
|
|
userId, "set_displayname", [nameField.item.text], () => {
|
|
|
|
py.callClientCoro(userId, "update_own_profile", [], () => {
|
|
|
|
saveButton.nameChangeRunning = false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-11-06 13:00:08 +11:00
|
|
|
if (aliasFieldItem.changed) {
|
2020-11-15 02:30:03 +11:00
|
|
|
window.settings.Chat.Composer.Aliases[userId] =
|
2020-10-08 11:12:32 +11:00
|
|
|
aliasFieldItem.text
|
|
|
|
|
|
|
|
window.saveSettings()
|
2020-06-25 22:32:08 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
if (avatar.changed) {
|
|
|
|
saveButton.avatarChangeRunning = true
|
|
|
|
|
|
|
|
const path =
|
|
|
|
Qt.resolvedUrl(avatar.sourceOverride).replace(/^file:/, "")
|
|
|
|
|
|
|
|
py.callClientCoro(userId, "set_avatar_from_file", [path], () => {
|
|
|
|
py.callClientCoro(userId, "update_own_profile", [], () => {
|
|
|
|
saveButton.avatarChangeRunning = false
|
|
|
|
})
|
|
|
|
}, (errType, [httpCode]) => {
|
|
|
|
console.error("Avatar upload failed:", httpCode, errType)
|
|
|
|
saveButton.avatarChangeRunning = false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function cancel() {
|
|
|
|
nameField.item.reset()
|
2020-11-06 13:00:08 +11:00
|
|
|
aliasFieldItem.reset()
|
2020-06-25 22:32:08 +10:00
|
|
|
fileDialog.selectedFile = ""
|
|
|
|
fileDialog.file = ""
|
|
|
|
}
|
|
|
|
|
2020-07-12 12:52:14 +10:00
|
|
|
footer: AutoDirectionLayout {
|
2020-06-25 22:32:08 +10:00
|
|
|
ApplyButton {
|
|
|
|
id: saveButton
|
|
|
|
|
|
|
|
property bool nameChangeRunning: false
|
|
|
|
property bool avatarChangeRunning: false
|
|
|
|
|
|
|
|
disableWhileLoading: false
|
|
|
|
loading: nameChangeRunning || avatarChangeRunning
|
|
|
|
enabled:
|
|
|
|
avatar.changed ||
|
|
|
|
nameField.item.changed ||
|
2020-11-06 13:00:08 +11:00
|
|
|
(aliasFieldItem.changed && ! aliasFieldItem.error)
|
2020-06-25 22:32:08 +10:00
|
|
|
|
|
|
|
onClicked: applyChanges()
|
|
|
|
}
|
|
|
|
|
|
|
|
CancelButton {
|
|
|
|
enabled: saveButton.enabled && ! saveButton.loading
|
|
|
|
onClicked: cancel()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 19:08:12 +10:00
|
|
|
onKeyboardAccept: if (saveButton.enabled) saveButton.clicked()
|
2020-06-26 00:27:24 +10:00
|
|
|
onKeyboardCancel: cancel()
|
2020-06-25 22:32:08 +10:00
|
|
|
|
|
|
|
HUserAvatar {
|
2020-07-12 14:25:57 +10:00
|
|
|
id: avatar
|
|
|
|
|
2020-06-25 22:32:08 +10:00
|
|
|
property bool changed: Boolean(sourceOverride)
|
|
|
|
|
2020-08-24 06:57:53 +10:00
|
|
|
clientUserId: page.userId
|
2020-06-25 22:32:08 +10:00
|
|
|
userId: page.userId
|
|
|
|
displayName: nameField.item.text
|
2020-06-25 23:59:40 +10:00
|
|
|
mxc: account ? account.avatar_url : ""
|
2020-06-25 22:32:08 +10:00
|
|
|
toolTipMxc: ""
|
|
|
|
sourceOverride: fileDialog.selectedFile || fileDialog.file
|
|
|
|
|
|
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
Layout.fillWidth: true
|
|
|
|
// Layout.preferredWidth: 256 * theme.uiScale
|
|
|
|
Layout.preferredHeight: width
|
|
|
|
|
|
|
|
Rectangle {
|
2020-06-25 23:59:40 +10:00
|
|
|
anchors.fill: parent
|
2020-06-25 22:32:08 +10:00
|
|
|
z: 10
|
|
|
|
visible: opacity > 0
|
2020-06-25 23:59:40 +10:00
|
|
|
opacity:
|
|
|
|
! fileDialog.dialog.visible &&
|
|
|
|
(
|
|
|
|
(! avatar.mxc && ! avatar.changed) ||
|
|
|
|
avatar.hovered ||
|
2020-07-11 03:04:40 +10:00
|
|
|
! ready ||
|
|
|
|
account.presence === "offline"
|
2020-06-25 23:59:40 +10:00
|
|
|
) ?
|
2020-07-11 03:04:40 +10:00
|
|
|
1 :
|
|
|
|
0
|
2020-06-25 22:32:08 +10:00
|
|
|
|
|
|
|
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 }
|
|
|
|
|
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
2020-07-11 03:04:40 +10:00
|
|
|
enabled: ready && account.presence !== "offline"
|
2020-06-25 22:32:08 +10:00
|
|
|
acceptedButtons: Qt.NoButton
|
|
|
|
cursorShape:
|
|
|
|
overlayHover.hovered ?
|
|
|
|
Qt.PointingHandCursor : Qt.ArrowCursor
|
|
|
|
}
|
|
|
|
|
2020-06-25 23:59:40 +10:00
|
|
|
HLoader {
|
|
|
|
anchors.centerIn: parent
|
|
|
|
width: avatar.width / 3
|
|
|
|
height: width
|
|
|
|
|
|
|
|
source: "../../Base/HBusyIndicator.qml"
|
|
|
|
active: ! ready
|
|
|
|
opacity: active ? 1 : 0
|
|
|
|
visible: opacity > 0
|
|
|
|
|
|
|
|
Behavior on opacity { HNumberAnimation {} }
|
|
|
|
}
|
|
|
|
|
2020-06-25 22:32:08 +10:00
|
|
|
HColumnLayout {
|
|
|
|
anchors.centerIn: parent
|
|
|
|
spacing: currentSpacing
|
|
|
|
width: parent.width
|
2020-07-11 03:04:40 +10:00
|
|
|
opacity: ready && account.presence !== "offline" ? 1 : 0
|
2020-06-25 23:59:40 +10:00
|
|
|
visible: opacity > 0
|
|
|
|
|
|
|
|
Behavior on opacity { HNumberAnimation {} }
|
2020-06-25 22:32:08 +10:00
|
|
|
|
|
|
|
HIcon {
|
|
|
|
svgName: "upload-avatar"
|
|
|
|
colorize: (! avatar.mxc && overlayHover.hovered) ?
|
|
|
|
theme.colors.accentText : theme.icons.colorize
|
|
|
|
dimension: avatar.width / 3
|
|
|
|
|
|
|
|
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 {} }
|
|
|
|
|
2020-06-26 21:24:37 +10:00
|
|
|
font.pixelSize: Math.max(
|
|
|
|
theme.fontSize.big * avatar.width / 300,
|
|
|
|
theme.fontSize.small,
|
|
|
|
)
|
2020-07-17 15:45:02 +10:00
|
|
|
wrapMode: HLabel.WordWrap
|
2020-06-25 22:32:08 +10:00
|
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HFileDialogOpener {
|
|
|
|
id: fileDialog
|
2020-06-25 23:59:40 +10:00
|
|
|
enabled: ready
|
2020-06-25 22:32:08 +10:00
|
|
|
fileType: HFileDialogOpener.FileType.Images
|
|
|
|
dialog.title: qsTr("Select profile picture for %1")
|
2020-06-25 23:59:40 +10:00
|
|
|
.arg(account ? account.display_name : "")
|
2020-06-25 22:32:08 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-06 12:19:07 +11:00
|
|
|
HLabeledItem {
|
|
|
|
label.text: qsTr("User ID:")
|
2020-06-25 22:32:08 +10:00
|
|
|
|
|
|
|
Layout.fillWidth: true
|
2020-11-06 11:47:17 +11:00
|
|
|
|
2020-11-06 12:19:07 +11:00
|
|
|
HRowLayout {
|
|
|
|
width: parent.width
|
|
|
|
|
|
|
|
HTextArea {
|
|
|
|
id: idArea
|
|
|
|
textFormat: HSelectableLabel.RichText
|
|
|
|
wrapMode: HLabel.Wrap
|
|
|
|
readOnly: true
|
|
|
|
radius: 0
|
|
|
|
text: utils.coloredNameHtml("", userId, userId)
|
2020-11-06 11:47:17 +11:00
|
|
|
|
2020-11-06 12:19:07 +11:00
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
}
|
|
|
|
|
|
|
|
FieldCopyButton {
|
|
|
|
textControl: idArea
|
|
|
|
}
|
2020-11-06 11:47:17 +11:00
|
|
|
}
|
2020-06-25 22:32:08 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
HLabeledItem {
|
|
|
|
id: nameField
|
2020-06-25 23:59:40 +10:00
|
|
|
loading: ! ready
|
2020-06-25 22:32:08 +10:00
|
|
|
label.text: qsTr("Display name:")
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
|
|
|
HTextField {
|
|
|
|
width: parent.width
|
2020-07-11 03:04:40 +10:00
|
|
|
enabled: ready && account.presence !== "offline"
|
2020-06-25 23:59:40 +10:00
|
|
|
defaultText: ready ? account.display_name : ""
|
2020-06-25 22:32:08 +10:00
|
|
|
maximumLength: 255
|
|
|
|
|
|
|
|
// TODO: Qt 5.14+: use a Binding enabled when text not empty
|
|
|
|
color: utils.nameColor(text)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HLabeledItem {
|
2020-07-12 14:25:57 +10:00
|
|
|
id: aliasField
|
|
|
|
|
2020-11-15 02:30:03 +11:00
|
|
|
readonly property var aliases: window.settings.Chat.Composer.Aliases
|
2020-06-25 22:32:08 +10:00
|
|
|
readonly property string currentAlias: aliases[userId] || ""
|
|
|
|
|
2020-08-24 20:01:09 +10:00
|
|
|
readonly property bool hasWhiteSpace: /\s/.test(item.text)
|
|
|
|
|
2020-06-25 22:32:08 +10:00
|
|
|
readonly property string alreadyTakenBy: {
|
|
|
|
if (! item.text) return ""
|
|
|
|
|
|
|
|
for (const [id, idAlias] of Object.entries(aliases))
|
|
|
|
if (id !== userId && idAlias === item.text) return id
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
label.text: qsTr("Composer alias:")
|
|
|
|
|
|
|
|
errorLabel.text:
|
2020-08-24 20:01:09 +10:00
|
|
|
hasWhiteSpace ? qsTr("Alias cannot include spaces") :
|
|
|
|
alreadyTakenBy ? qsTr("Taken by %1").arg(alreadyTakenBy) :
|
2020-06-25 22:32:08 +10:00
|
|
|
""
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
2020-11-06 13:00:08 +11:00
|
|
|
HRowLayout {
|
2020-06-25 22:32:08 +10:00
|
|
|
width: parent.width
|
2020-11-06 13:00:08 +11:00
|
|
|
|
|
|
|
HTextField {
|
|
|
|
id: aliasFieldItem
|
|
|
|
error: aliasField.hasWhiteSpace || aliasField.alreadyTakenBy
|
|
|
|
defaultText: aliasField.currentAlias
|
|
|
|
placeholderText: qsTr("e.g. %1").arg((
|
|
|
|
nameField.item.text ||
|
|
|
|
(ready && account.display_name) ||
|
|
|
|
userId.substring(1)
|
|
|
|
)[0])
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
}
|
|
|
|
|
|
|
|
FieldHelpButton {
|
|
|
|
helpText: qsTr(
|
|
|
|
"From any chat, start a message with specified alias " +
|
|
|
|
"followed by a space to type and send as this account.\n" +
|
|
|
|
"The account must have permission to talk in the room.\n"+
|
|
|
|
"To ignore the alias when typing, prepend it with a space."
|
|
|
|
)
|
|
|
|
}
|
2020-06-25 22:32:08 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|