Improve profile editing UX, especially around unsaved changes
As seen with a real life user (and myself) I will sometimes back out of editing user information, despite there being a Save button. That's because we make no attempt to warn or stop the user before doing so. Now that is fixed, and the window will be prevented from closing or the page popping. Additionally, there's now a "Reset Changes" button that works as you'd expect. I also made it so this new button and the existing "Save" button are only enabled when there's unsaved changes. I also did some work on the UX flow to get to this account editing page. There used to be a dedicated button in the account menu, but that's duplicative with the new "Open Profile" option. That's removed, but I also replaced the useless "Message" and "Ignore" (what? ignoring yourself?) buttons with a button to edit the account. Related to removing UI cruft, the "Show QR code" button on this page is removed. There's an easier way to access that through your own profile.
This commit is contained in:
@@ -40,12 +40,6 @@ KirigamiComponents.ConvergentContextMenu {
|
||||
})
|
||||
}
|
||||
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:inmenu", "Edit This Account")
|
||||
icon.name: "document-edit"
|
||||
onTriggered: NeoChatSettingsView.openWithInitialProperties("accounts", {initialAccount: root.connection});
|
||||
}
|
||||
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:inmenu", "Notification Settings")
|
||||
icon.name: "notifications"
|
||||
|
||||
@@ -149,15 +149,24 @@ Kirigami.Dialog {
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:intoolbar Message this user directly", "Message")
|
||||
icon.name: "document-send-symbolic"
|
||||
visible: !root.isSelf
|
||||
|
||||
onTriggered: {
|
||||
root.close();
|
||||
root.connection.requestDirectChat(root.user.id);
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:intoolbar Edit This Account", "Edit")
|
||||
icon.name: "document-edit"
|
||||
visible: root.isSelf
|
||||
|
||||
onTriggered: NeoChatSettingsView.openWithInitialProperties("accounts", {initialAccount: root.connection});
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "im-invisible-user-symbolic"
|
||||
text: root.connection.isIgnored(root.user.id) ? i18nc("@action:intoolbar Unignore or 'unblock' this user", "Unignore") : i18nc("@action:intoolbar Ignore or 'block' this user", "Ignore")
|
||||
visible: !root.isSelf
|
||||
|
||||
onTriggered: {
|
||||
root.close();
|
||||
|
||||
@@ -19,6 +19,91 @@ FormCard.FormCardPage {
|
||||
|
||||
title: i18nc("@title:window", "Edit Account")
|
||||
property NeoChatConnection connection
|
||||
readonly property bool hasUnsavedChanges: root.connection.localUser.displayName !== name.text
|
||||
|| avatar.source != avatar.findOriginalAvatarUrl()
|
||||
|| root.connection.label !== accountLabel.text;
|
||||
|
||||
function resetChanges(): void {
|
||||
name.text = root.connection ? root.connection.localUser.displayName : "";
|
||||
accountLabel.text = root.connection ? root.connection.label : "";
|
||||
avatar.source = avatar.findOriginalAvatarUrl();
|
||||
}
|
||||
|
||||
function saveChanges(): void {
|
||||
if (avatar.source != avatar.findOriginalAvatarUrl() && !root.connection.setAvatar(avatar.source)) {
|
||||
(root.Window.window as Kirigami.ApplicationWindow).showPassiveNotification(i18nc("@info", "New avatar could not be set."));
|
||||
}
|
||||
if (root.connection.localUser.displayName !== name.text) {
|
||||
root.connection.localUser.rename(name.text);
|
||||
}
|
||||
if (root.connection.label !== accountLabel.text) {
|
||||
root.connection.label = accountLabel.text;
|
||||
}
|
||||
}
|
||||
|
||||
function checkForUnsavedChanges(): bool {
|
||||
if (root.hasUnsavedChanges) {
|
||||
resetChangesDialog.open();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
onBackRequested: event => {
|
||||
if (checkForUnsavedChanges(event)) {
|
||||
event.accepted = true; // Prevent the page from popping
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.Window.window
|
||||
|
||||
function onClosing(event): void {
|
||||
if (root.checkForUnsavedChanges(event)) {
|
||||
event.accepted = false; // Prevent the window from closing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.PromptDialog {
|
||||
id: resetChangesDialog
|
||||
|
||||
parent: root.QQC2.Overlay.overlay
|
||||
preferredWidth: Kirigami.Units.gridUnit * 24
|
||||
|
||||
title: i18nc("@title:dialog Apply unsaved settings", "Apply Settings")
|
||||
subtitle: i18nc("@info", "There are unsaved changes to user information. Apply the changes or discard them?")
|
||||
|
||||
standardButtons: QQC2.Dialog.Cancel
|
||||
|
||||
footer: QQC2.DialogButtonBox {
|
||||
QQC2.Button {
|
||||
text: i18nc("@action:button As in 'Remove this device'", "Apply")
|
||||
icon.name: "dialog-ok-apply"
|
||||
|
||||
onClicked: {
|
||||
root.saveChanges();
|
||||
resetChangesDialog.close();
|
||||
}
|
||||
|
||||
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.ApplyRole
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
text: i18nc("@action:button As in 'Remove this device'", "Reset")
|
||||
icon.name: "edit-reset-symbolic"
|
||||
|
||||
onClicked: {
|
||||
root.resetChanges();
|
||||
resetChangesDialog.close();
|
||||
}
|
||||
|
||||
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.ResetRole
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: resetChanges()
|
||||
|
||||
KirigamiComponents.AvatarButton {
|
||||
id: avatar
|
||||
@@ -34,8 +119,6 @@ FormCard.FormCardPage {
|
||||
|
||||
padding: 0
|
||||
|
||||
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl.
|
||||
source: findOriginalAvatarUrl()
|
||||
name: root.connection.localUser.displayName
|
||||
|
||||
function findOriginalAvatarUrl(): string {
|
||||
@@ -109,14 +192,12 @@ FormCard.FormCardPage {
|
||||
FormCard.FormTextFieldDelegate {
|
||||
id: name
|
||||
label: i18n("Display Name:")
|
||||
text: root.connection ? root.connection.localUser.displayName : ""
|
||||
}
|
||||
FormCard.FormDelegateSeparator {}
|
||||
FormCard.FormTextFieldDelegate {
|
||||
id: accountLabel
|
||||
label: i18n("Label:")
|
||||
placeholderText: i18n("Work")
|
||||
text: root.connection ? root.connection.label : ""
|
||||
}
|
||||
FormCard.FormDelegateSeparator {}
|
||||
FormCard.FormTextDelegate {
|
||||
@@ -140,34 +221,17 @@ FormCard.FormCardPage {
|
||||
}
|
||||
FormCard.FormDelegateSeparator {}
|
||||
FormCard.FormButtonDelegate {
|
||||
text: i18nc("@action:button", "Show QR Code")
|
||||
icon.name: "view-barcode-qr-symbolic"
|
||||
onClicked: {
|
||||
let qrMax = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||
text: "https://matrix.to/#/" + root.connection.localUser.id,
|
||||
title: root.connection.localUser.displayName,
|
||||
subtitle: root.connection.localUser.id,
|
||||
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl.
|
||||
avatarSource: root.connection && (root.connection.localUser.avatarUrl.toString().length > 0 ? root.connection.makeMediaUrl(root.connection.localUser.avatarUrl) : "")
|
||||
});
|
||||
qrMax.open();
|
||||
}
|
||||
text: i18nc("@action:button", "Reset Changes")
|
||||
icon.name: "edit-reset-symbolic"
|
||||
enabled: root.hasUnsavedChanges
|
||||
onClicked: root.resetChanges()
|
||||
}
|
||||
FormCard.FormDelegateSeparator {}
|
||||
FormCard.FormButtonDelegate {
|
||||
text: i18n("Save")
|
||||
text: i18nc("@action:button Save changes to user", "Save")
|
||||
icon.name: "document-save-symbolic"
|
||||
onClicked: {
|
||||
if (avatar.source != avatar.findOriginalAvatarUrl() && !root.connection.setAvatar(avatar.source)) {
|
||||
(root.Window.window as Kirigami.ApplicationWindow).showPassiveNotification("The Avatar could not be set");
|
||||
}
|
||||
if (root.connection.localUser.displayName !== name.text) {
|
||||
root.connection.localUser.rename(name.text);
|
||||
}
|
||||
if (root.connection.label !== accountLabel.text) {
|
||||
root.connection.label = accountLabel.text;
|
||||
}
|
||||
}
|
||||
enabled: root.hasUnsavedChanges
|
||||
onClicked: root.saveChanges()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user