fix(profile-settings): Add usage dirty values for preview and load image profile on save

Closes: #7920 #7917
This commit is contained in:
Boris Melnik 2022-11-08 21:30:50 +03:00
parent 7e7daa56e1
commit 13acb5730d
12 changed files with 90 additions and 12 deletions

View File

@ -73,30 +73,44 @@ QtObject:
proc getSocialLinksJson(self: View): string {.slot.} = proc getSocialLinksJson(self: View): string {.slot.} =
$(%*self.socialLinksModel.items) $(%*self.socialLinksModel.items)
proc temporarySocialLinksJsonChanged*(self: View) {.signal.}
proc getTemporarySocialLinksJson(self: View): string {.slot.} =
$(%*self.temporarySocialLinksModel.items)
QtProperty[string] socialLinksJson: QtProperty[string] socialLinksJson:
read = getSocialLinksJson read = getSocialLinksJson
notify = socialLinksJsonChanged notify = socialLinksJsonChanged
QtProperty[string] temporarySocialLinksJson:
read = getTemporarySocialLinksJson
notify = temporarySocialLinksJsonChanged
QtProperty[bool] socialLinksDirty: QtProperty[bool] socialLinksDirty:
read = areSocialLinksDirty read = areSocialLinksDirty
notify = socialLinksDirtyChanged notify = socialLinksDirtyChanged
proc createCustomLink(self: View, text: string, url: string) {.slot.} = proc createCustomLink(self: View, text: string, url: string) {.slot.} =
self.temporarySocialLinksModel.appendItem(initSocialLinkItem(text, url, LinkType.Custom)) self.temporarySocialLinksModel.appendItem(initSocialLinkItem(text, url, LinkType.Custom))
self.temporarySocialLinksJsonChanged()
self.socialLinksDirtyChanged() self.socialLinksDirtyChanged()
proc removeCustomLink(self: View, uuid: string) {.slot.} = proc removeCustomLink(self: View, uuid: string) {.slot.} =
if (self.temporarySocialLinksModel.removeItem(uuid)): if (self.temporarySocialLinksModel.removeItem(uuid)):
self.temporarySocialLinksJsonChanged()
self.socialLinksDirtyChanged() self.socialLinksDirtyChanged()
proc updateLink(self: View, uuid: string, text: string, url: string): bool {.slot.} = proc updateLink(self: View, uuid: string, text: string, url: string): bool {.slot.} =
if (self.temporarySocialLinksModel.updateItem(uuid, text, url)): if (self.temporarySocialLinksModel.updateItem(uuid, text, url)):
self.temporarySocialLinksJsonChanged()
self.socialLinksDirtyChanged() self.socialLinksDirtyChanged()
proc resetSocialLinks(self: View): bool {.slot.} = proc resetSocialLinks(self: View): bool {.slot.} =
if (self.areSocialLinksDirty()): if (self.areSocialLinksDirty()):
self.temporarySocialLinksModel.setItems(self.socialLinksModel.items) self.temporarySocialLinksModel.setItems(self.socialLinksModel.items)
self.socialLinksDirtyChanged() self.socialLinksDirtyChanged()
self.temporarySocialLinksJsonChanged()
proc saveSocialLinks(self: View): bool {.slot.} = proc saveSocialLinks(self: View): bool {.slot.} =
result = self.delegate.saveSocialLinks() result = self.delegate.saveSocialLinks()
@ -104,6 +118,7 @@ QtObject:
self.socialLinksModel.setItems(self.temporarySocialLinksModel.items) self.socialLinksModel.setItems(self.temporarySocialLinksModel.items)
self.socialLinksDirtyChanged() self.socialLinksDirtyChanged()
self.socialLinksJsonChanged() self.socialLinksJsonChanged()
self.temporarySocialLinksJsonChanged()
proc bioChanged*(self: View) {.signal.} proc bioChanged*(self: View) {.signal.}
proc getBio(self: View): string {.slot.} = proc getBio(self: View): string {.slot.} =

View File

@ -42,6 +42,13 @@ Loader {
color: root.asset.imgIsIdenticon ? color: root.asset.imgIsIdenticon ?
Theme.palette.statusRoundedImage.backgroundColor : Theme.palette.statusRoundedImage.backgroundColor :
root.asset.bgColor root.asset.bgColor
image.fillMode: root.asset.cropRect ? Image.PreserveAspectCrop
: Image.PreserveAspectFit
image.scale: root.asset.scale
image.x: root.asset.cropRectangle ? -root.asset.cropRectangle.x
: 0
image.y: root.asset.cropRectangle ? -root.asset.cropRectangle.y
: 0
} }
Loader { Loader {
anchors.centerIn: parent anchors.centerIn: parent

View File

@ -34,4 +34,7 @@ QtObject {
property bool isImage: false property bool isImage: false
property int imgStatus property int imgStatus
property bool imgIsIdenticon: false property bool imgIsIdenticon: false
// crop
property rect cropRect
} }

View File

@ -79,6 +79,8 @@ SettingsContentBase {
Layout.fillWidth: true Layout.fillWidth: true
profileStore: root.profileStore profileStore: root.profileStore
contactsStore: root.contactsStore contactsStore: root.contactsStore
dirtyValues: settingsView.dirtyValues
dirty: settingsView.dirty
} }
} }

View File

@ -8,6 +8,8 @@ import StatusQ.Core.Theme 0.1
Item { Item {
property alias profileStore: profilePreview.profileStore property alias profileStore: profilePreview.profileStore
property alias contactsStore: profilePreview.contactsStore property alias contactsStore: profilePreview.contactsStore
property alias dirtyValues: profilePreview.dirtyValues
property alias dirty: profilePreview.dirty
implicitHeight: profilePreview.implicitHeight implicitHeight: profilePreview.implicitHeight
+ profilePreview.anchors.topMargin + profilePreview.anchors.topMargin

View File

@ -28,10 +28,18 @@ ColumnLayout {
property ProfileStore profileStore property ProfileStore profileStore
property WalletStore walletStore property WalletStore walletStore
property QtObject dirtyValues: QtObject {
property string displayName: descriptionPanel.displayName.text
property string bio: descriptionPanel.bio.text
property bool biomentricValue: biometricsSwitch.checked
property url profileLargeImage: profileHeader.icon
}
readonly property bool dirty: descriptionPanel.displayName.text !== profileStore.displayName || readonly property bool dirty: descriptionPanel.displayName.text !== profileStore.displayName ||
descriptionPanel.bio.text !== profileStore.bio || descriptionPanel.bio.text !== profileStore.bio ||
profileStore.socialLinksDirty || profileStore.socialLinksDirty ||
biometricsSwitch.checked != biometricsSwitch.currentStoredValue biometricsSwitch.checked != biometricsSwitch.currentStoredValue ||
profileHeader.icon !== profileStore.profileLargeImage
readonly property bool valid: !!descriptionPanel.displayName.text && descriptionPanel.displayName.valid readonly property bool valid: !!descriptionPanel.displayName.text && descriptionPanel.displayName.valid
@ -41,17 +49,28 @@ ColumnLayout {
profileStore.resetSocialLinks() profileStore.resetSocialLinks()
descriptionPanel.reevaluateSocialLinkInputs() descriptionPanel.reevaluateSocialLinkInputs()
biometricsSwitch.checked = Qt.binding(() => { return biometricsSwitch.currentStoredValue }) biometricsSwitch.checked = Qt.binding(() => { return biometricsSwitch.currentStoredValue })
profileHeader.icon = Qt.binding(() => { return profileStore.profileLargeImage })
} }
function save() { function save() {
profileStore.setDisplayName(descriptionPanel.displayName.text) profileStore.setDisplayName(descriptionPanel.displayName.text)
profileStore.setBio(descriptionPanel.bio.text) profileStore.setBio(descriptionPanel.bio.text)
profileStore.saveSocialLinks() profileStore.saveSocialLinks()
if (profileHeader.icon === "") {
root.profileStore.removeImage()
} else {
profileStore.uploadImage(profileHeader.icon,
profileHeader.cropRect.x.toFixed(),
profileHeader.cropRect.y.toFixed(),
(profileHeader.cropRect.x + profileHeader.cropRect.width).toFixed(),
(profileHeader.cropRect.y + profileHeader.cropRect.height).toFixed());
}
if (biometricsSwitch.checked) if (biometricsSwitch.checked)
Global.openPopup(storePasswordModal) Global.openPopup(storePasswordModal)
else else
localAccountSettings.storeToKeychainValue = Constants.keychain.storedValue.never; localAccountSettings.storeToKeychainValue = Constants.keychain.storedValue.never;
reset()
} }
function offerToStorePassword(password, runStoreToKeyChainPopup) function offerToStorePassword(password, runStoreToKeyChainPopup)
@ -64,6 +83,7 @@ ColumnLayout {
} }
ProfileHeader { ProfileHeader {
id: profileHeader
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: Style.current.padding Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding Layout.rightMargin: Style.current.padding

View File

@ -145,7 +145,7 @@ Item {
} }
onOpenChangeProfilePicPopup: { onOpenChangeProfilePicPopup: {
var popup = changeProfilePicComponent.createObject(appMain); var popup = changeProfilePicComponent.createObject(appMain, {callback: cb});
popup.chooseImageToCrop(); popup.chooseImageToCrop();
} }
onOpenBackUpSeedPopup: Global.openPopup(backupSeedModalComponent) onOpenBackUpSeedPopup: Global.openPopup(backupSeedModalComponent)
@ -236,6 +236,15 @@ Item {
title: qsTr("Profile Picture") title: qsTr("Profile Picture")
acceptButtonText: qsTr("Make this my Profile Pic") acceptButtonText: qsTr("Make this my Profile Pic")
onImageCropped: { onImageCropped: {
if (callback) {
callback(image,
cropRect.x.toFixed(),
cropRect.y.toFixed(),
(cropRect.x + cropRect.width).toFixed(),
(cropRect.y + cropRect.height).toFixed())
return
}
appMain.rootStore.profileSectionStore.profileStore.uploadImage(image, appMain.rootStore.profileSectionStore.profileStore.uploadImage(image,
cropRect.x.toFixed(), cropRect.x.toFixed(),
cropRect.y.toFixed(), cropRect.y.toFixed(),

View File

@ -27,6 +27,7 @@ Item {
property bool isContact: false property bool isContact: false
property bool isCurrentUser property bool isCurrentUser
property bool userIsEnsVerified property bool userIsEnsVerified
property rect cropRect: undefined
property int imageSize: ProfileHeader.ImageSize.Compact property int imageSize: ProfileHeader.ImageSize.Compact
property bool displayNameVisible: true property bool displayNameVisible: true
@ -82,9 +83,11 @@ Item {
imageWidth: d.getSize(36, 64, 160) imageWidth: d.getSize(36, 64, 160)
imageHeight: imageWidth imageHeight: imageWidth
showRing: !root.userIsEnsVerified showRing: !root.userIsEnsVerified
cropRect: root.cropRect
} }
StatusRoundButton { StatusRoundButton {
id: editButton
visible: root.editImageButtonVisible visible: root.editImageButtonVisible
anchors.bottom: userImage.bottom anchors.bottom: userImage.bottom
anchors.right: userImage.right anchors.right: userImage.right
@ -102,7 +105,12 @@ Item {
if (!!root.store.profileLargeImage) if (!!root.store.profileLargeImage)
imageEditMenu.popup(this, mouse.x, mouse.y); imageEditMenu.popup(this, mouse.x, mouse.y);
else else
Global.openChangeProfilePicPopup(); Global.openChangeProfilePicPopup(tempIcon);
}
function tempIcon(image, aX, aY, bX, bY) {
root.icon = image
root.cropRect = Qt.rect(aX, aY, bX - aX, bY - aY)
} }
} }
} }
@ -211,14 +219,14 @@ Item {
text: qsTr("Upload a file") text: qsTr("Upload a file")
icon.name: "download" icon.name: "download"
iconRotation: 180 iconRotation: 180
onTriggered: Global.openChangeProfilePicPopup() onTriggered: Global.openChangeProfilePicPopup(editButton.tempIcon)
} }
StatusMenuItem { StatusMenuItem {
text: qsTr("Remove image") text: qsTr("Remove image")
type: StatusMenuItem.Danger type: StatusMenuItem.Danger
icon.name: "delete" icon.name: "delete"
onTriggered: root.store.removeImage() onTriggered: root.icon = ""
} }
} }
} }

View File

@ -20,6 +20,8 @@ Loader {
property bool interactive: true property bool interactive: true
property bool disabled: false property bool disabled: false
property rect cropRect: undefined
property int colorId: Utils.colorIdForPubkey(pubkey) property int colorId: Utils.colorIdForPubkey(pubkey)
property var colorHash: Utils.getColorHashAsJson(pubkey) property var colorHash: Utils.getColorHashAsJson(pubkey)
@ -34,6 +36,7 @@ Loader {
name: root.image name: root.image
charactersLen: 2 charactersLen: 2
isImage: true isImage: true
cropRect: root.cropRect
} }
ringSettings { ringSettings {
ringSpecModel: root.showRing ? root.colorHash : undefined ringSpecModel: root.showRing ? root.colorHash : undefined

View File

@ -14,6 +14,7 @@ Item {
id: root id: root
objectName: "imageCropWorkflow" objectName: "imageCropWorkflow"
property var callback: null
property alias aspectRatio: imageCropper.aspectRatio property alias aspectRatio: imageCropper.aspectRatio
property alias windowStyle: imageCropper.windowStyle property alias windowStyle: imageCropper.windowStyle
/*required*/ property string imageFileDialogTitle: "" /*required*/ property string imageFileDialogTitle: ""

View File

@ -27,6 +27,9 @@ Pane {
property var profileStore property var profileStore
property var contactsStore property var contactsStore
property QtObject dirtyValues: null
property bool dirty: false
signal closeRequested() signal closeRequested()
padding: 0 padding: 0
@ -249,9 +252,11 @@ Pane {
UserImage { UserImage {
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
objectName: "ProfileDialog_userImage" objectName: "ProfileDialog_userImage"
name: d.userDisplayName name: root.dirty ? root.dirtyValues.displayName
: d.userDisplayName
pubkey: root.publicKey pubkey: root.publicKey
image: d.contactDetails.largeImage image: root.dirty ? root.dirtyValues.profileLargeImage
: d.contactDetails.largeImage
interactive: false interactive: false
imageWidth: 80 imageWidth: 80
imageHeight: imageWidth imageHeight: imageWidth
@ -275,7 +280,8 @@ Pane {
font.bold: true font.bold: true
font.pixelSize: 22 font.pixelSize: 22
elide: Text.ElideRight elide: Text.ElideRight
text: d.userDisplayName text: root.dirty ? root.dirtyValues.displayName
: d.userDisplayName
} }
StatusContactVerificationIcons { StatusContactVerificationIcons {
id: verificationIcons id: verificationIcons
@ -543,8 +549,10 @@ Pane {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: column.anchors.leftMargin + Style.current.halfPadding Layout.leftMargin: column.anchors.leftMargin + Style.current.halfPadding
Layout.rightMargin: column.anchors.rightMargin + Style.current.halfPadding Layout.rightMargin: column.anchors.rightMargin + Style.current.halfPadding
bio: d.contactDetails.bio bio: root.dirty ? root.dirtyValues.bio
userSocialLinksJson: d.contactDetails.socialLinks : d.contactDetails.bio
userSocialLinksJson: root.dirty ? root.profileStore.temporarySocialLinksJson
: d.contactDetails.socialLinks
} }
GridLayout { GridLayout {

View File

@ -44,7 +44,7 @@ QtObject {
signal unblockContactRequested(string publicKey, string contactName) signal unblockContactRequested(string publicKey, string contactName)
signal contactUnblocked(string publicKey) signal contactUnblocked(string publicKey)
signal openChangeProfilePicPopup() signal openChangeProfilePicPopup(var cb)
signal displayToastMessage(string title, string subTitle, string icon, bool loading, int ephNotifType, string url) signal displayToastMessage(string title, string subTitle, string icon, bool loading, int ephNotifType, string url)
signal openEditDisplayNamePopup() signal openEditDisplayNamePopup()
signal openActivityCenterPopupRequested signal openActivityCenterPopupRequested