feat(profile): Break profile settings page into tabs
- Each section of the current profile settings view is moved into the corresponding tab - The Preview tab becomes the Preview button - Password button becomes a separate page: PR: [Settings]: Added change password view #13284 (I kept the Change password button for now until this is merged) - Also creates the new Web (Social links) tab as a result Fixes #13330 Fixes #13406
This commit is contained in:
parent
bb391a68ba
commit
3ebd4509bb
|
@ -253,6 +253,9 @@ Control {
|
|||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: empty ? Math.floor(hiddenTargetDropArea.height + hiddenTargetDropArea.anchors.topMargin)
|
||||
: d.defaultDelegateHeight * Math.min(count, 4)
|
||||
implicitHeight: contentHeight
|
||||
interactive: false
|
||||
|
||||
model: root.baseModel
|
||||
|
||||
readonly property bool empty: !contentHeight
|
||||
|
@ -333,5 +336,7 @@ Control {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,5 +161,7 @@ Control {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
ProfileDescriptionPanel 1.0 ProfileDescriptionPanel.qml
|
||||
ProfileSocialLinksPanel 1.0 ProfileSocialLinksPanel.qml
|
||||
ProfileShowcaseCommunitiesPanel 1.0 ProfileShowcaseCommunitiesPanel.qml
|
||||
ProfileShowcaseCollectiblesPanel 1.0 ProfileShowcaseCollectiblesPanel.qml
|
||||
|
|
|
@ -19,6 +19,7 @@ import StatusQ.Core.Theme 0.1
|
|||
import StatusQ.Components 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import AppLayouts.Profile.panels 1.0
|
||||
import AppLayouts.Wallet.stores 1.0
|
||||
|
||||
SettingsContentBase {
|
||||
|
@ -34,86 +35,221 @@ SettingsContentBase {
|
|||
|
||||
property var communitiesModel
|
||||
|
||||
titleRowComponentLoader.sourceComponent: StatusButton {
|
||||
objectName: "profileSettingsChangePasswordButton"
|
||||
text: qsTr("Change Password")
|
||||
onClicked: Global.openPopup(changePasswordModal)
|
||||
enabled: !userProfile.isKeycardUser
|
||||
titleRowComponentLoader.sourceComponent: RowLayout {
|
||||
StatusButton {
|
||||
objectName: "profileSettingsChangePasswordButton"
|
||||
text: qsTr("Change Password")
|
||||
onClicked: Global.openPopup(changePasswordModal)
|
||||
enabled: !userProfile.isKeycardUser
|
||||
}
|
||||
StatusButton {
|
||||
text: qsTr("Preview")
|
||||
onClicked: Global.openPopup(profilePreview)
|
||||
}
|
||||
}
|
||||
|
||||
dirty: settingsView.dirty
|
||||
saveChangesButtonEnabled: settingsView.valid
|
||||
dirty: (!descriptionPanel.isEnsName &&
|
||||
descriptionPanel.displayName.text !== profileStore.displayName) ||
|
||||
descriptionPanel.bio.text !== profileStore.bio ||
|
||||
profileStore.socialLinksDirty ||
|
||||
profileHeader.icon !== profileStore.profileLargeImage ||
|
||||
priv.hasAnyProfileShowcaseChanges
|
||||
saveChangesButtonEnabled: !!descriptionPanel.displayName.text && descriptionPanel.displayName.valid
|
||||
|
||||
onResetChangesClicked: {
|
||||
settingsView.reset()
|
||||
profilePreview.reload()
|
||||
}
|
||||
onSaveChangesClicked: {
|
||||
settingsView.save()
|
||||
profilePreview.reload()
|
||||
}
|
||||
onResetChangesClicked: priv.reset()
|
||||
|
||||
onSaveChangesClicked: priv.save()
|
||||
|
||||
bottomHeaderComponents: StatusTabBar {
|
||||
id: editPreviwTabBar
|
||||
id: profileTabBar
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
leftPadding: 0
|
||||
width: implicitWidth
|
||||
text: qsTr("Edit")
|
||||
text: qsTr("Identity")
|
||||
}
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: qsTr("Preview")
|
||||
text: qsTr("Communities")
|
||||
}
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: qsTr("Accounts")
|
||||
}
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: qsTr("Collectibles")
|
||||
}
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: qsTr("Assets")
|
||||
}
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: qsTr("Web")
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: if (visible) profileStore.requestProfileShowcasePreferences()
|
||||
Component.onCompleted: profileStore.requestProfileShowcasePreferences()
|
||||
|
||||
readonly property var priv: QtObject {
|
||||
id: priv
|
||||
|
||||
property bool hasAnyProfileShowcaseChanges: false
|
||||
|
||||
function reset() {
|
||||
descriptionPanel.displayName.text = Qt.binding(() => { return profileStore.displayName })
|
||||
descriptionPanel.bio.text = Qt.binding(() => { return profileStore.bio })
|
||||
profileStore.resetSocialLinks()
|
||||
profileHeader.icon = Qt.binding(() => { return profileStore.profileLargeImage })
|
||||
|
||||
profileShowcaseCommunitiesPanel.reset()
|
||||
profileShowcaseAccountsPanel.reset()
|
||||
profileShowcaseCollectiblesPanel.reset()
|
||||
profileShowcaseAssetsPanel.reset()
|
||||
root.profileStore.requestProfileShowcasePreferences()
|
||||
hasAnyProfileShowcaseChanges = false
|
||||
}
|
||||
|
||||
function save() {
|
||||
if (hasAnyProfileShowcaseChanges)
|
||||
profileStore.storeProfileShowcasePreferences()
|
||||
|
||||
if (!descriptionPanel.isEnsName)
|
||||
profileStore.setDisplayName(descriptionPanel.displayName.text)
|
||||
profileStore.setBio(descriptionPanel.bio.text.trim())
|
||||
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());
|
||||
}
|
||||
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
spacing: Constants.settingsSection.itemSpacing
|
||||
width: root.contentWidth
|
||||
|
||||
StackLayout {
|
||||
id: stackLayout
|
||||
currentIndex: editPreviwTabBar.currentIndex
|
||||
currentIndex: profileTabBar.currentIndex
|
||||
|
||||
MyProfileSettingsView {
|
||||
id: settingsView
|
||||
// identity
|
||||
ColumnLayout {
|
||||
objectName: "myProfileSettingsView"
|
||||
profileStore: root.profileStore
|
||||
privacyStore: root.privacyStore
|
||||
walletStore: root.walletStore
|
||||
communitiesModel: root.communitiesModel
|
||||
walletAssetsStore: root.walletAssetsStore
|
||||
currencyStore: root.currencyStore
|
||||
ProfileHeader {
|
||||
id: profileHeader
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.current.padding
|
||||
Layout.rightMargin: Style.current.padding
|
||||
|
||||
onVisibleChanged: if (visible) stackLayout.Layout.preferredHeight = settingsView.implicitHeight
|
||||
Component.onCompleted: stackLayout.Layout.preferredHeight = Qt.binding(() => settingsView.implicitHeight)
|
||||
store: root.profileStore
|
||||
|
||||
displayName: profileStore.name
|
||||
pubkey: profileStore.pubkey
|
||||
icon: profileStore.profileLargeImage
|
||||
imageSize: ProfileHeader.ImageSize.Big
|
||||
|
||||
displayNameVisible: false
|
||||
pubkeyVisible: false
|
||||
emojiHashVisible: false
|
||||
editImageButtonVisible: true
|
||||
}
|
||||
|
||||
ProfileDescriptionPanel {
|
||||
id: descriptionPanel
|
||||
|
||||
readonly property bool isEnsName: profileStore.preferredName
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
displayName.focus: !isEnsName
|
||||
displayName.input.edit.readOnly: isEnsName
|
||||
displayName.text: profileStore.name
|
||||
displayName.validationMode: StatusInput.ValidationMode.Always
|
||||
displayName.validators: isEnsName ? [] : Constants.validators.displayName
|
||||
bio.text: profileStore.bio
|
||||
}
|
||||
}
|
||||
|
||||
MyProfilePreview {
|
||||
// communities
|
||||
ProfileShowcaseCommunitiesPanel {
|
||||
id: profileShowcaseCommunitiesPanel
|
||||
baseModel: root.communitiesModel
|
||||
showcaseModel: root.profileStore.profileShowcaseCommunitiesModel
|
||||
onShowcaseEntryChanged: priv.hasAnyProfileShowcaseChanges = true
|
||||
}
|
||||
|
||||
// accounts
|
||||
ProfileShowcaseAccountsPanel {
|
||||
id: profileShowcaseAccountsPanel
|
||||
baseModel: root.walletStore.accounts
|
||||
showcaseModel: root.profileStore.profileShowcaseAccountsModel
|
||||
currentWallet: root.walletStore.overview.mixedcaseAddress
|
||||
onShowcaseEntryChanged: priv.hasAnyProfileShowcaseChanges = true
|
||||
}
|
||||
|
||||
// collectibles
|
||||
ProfileShowcaseCollectiblesPanel {
|
||||
id: profileShowcaseCollectiblesPanel
|
||||
baseModel: root.profileStore.collectiblesModel
|
||||
showcaseModel: root.profileStore.profileShowcaseCollectiblesModel
|
||||
onShowcaseEntryChanged: priv.hasAnyProfileShowcaseChanges = true
|
||||
}
|
||||
|
||||
// assets
|
||||
ProfileShowcaseAssetsPanel {
|
||||
id: profileShowcaseAssetsPanel
|
||||
baseModel: root.walletAssetsStore.groupedAccountAssetsModel // TODO: instantiate an assets model in profile module
|
||||
showcaseModel: root.profileStore.profileShowcaseAssetsModel
|
||||
onShowcaseEntryChanged: priv.hasAnyProfileShowcaseChanges = true
|
||||
formatCurrencyAmount: function(amount, symbol) {
|
||||
return root.currencyStore.formatCurrencyAmount(amount, symbol)
|
||||
}
|
||||
}
|
||||
|
||||
// web
|
||||
ProfileSocialLinksPanel {
|
||||
profileStore: root.profileStore
|
||||
socialLinksModel: root.profileStore.temporarySocialLinksModel
|
||||
}
|
||||
|
||||
Component {
|
||||
id: changePasswordModal
|
||||
ChangePasswordModal {
|
||||
privacyStore: root.privacyStore
|
||||
onPasswordChanged: Global.openPopup(successPopup)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: successPopup
|
||||
ChangePasswordSuccessModal {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: profilePreview
|
||||
|
||||
profileStore: root.profileStore
|
||||
contactsStore: root.contactsStore
|
||||
networkConnectionStore: root.networkConnectionStore
|
||||
communitiesModel: root.communitiesModel
|
||||
dirtyValues: settingsView.dirtyValues
|
||||
dirty: settingsView.dirty
|
||||
|
||||
onVisibleChanged: if (visible) stackLayout.Layout.preferredHeight = Qt.binding(() => profilePreview.implicitHeight)
|
||||
ProfileDialog {
|
||||
publicKey: root.contactsStore.myPublicKey
|
||||
profileStore: root.profileStore
|
||||
contactsStore: root.contactsStore
|
||||
networkConnectionStore: root.networkConnectionStore
|
||||
communitiesModel: root.communitiesModel
|
||||
onClosed: destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: changePasswordModal
|
||||
ChangePasswordModal {
|
||||
privacyStore: root.privacyStore
|
||||
onPasswordChanged: Global.openPopup(successPopup);
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: successPopup
|
||||
ChangePasswordSuccessModal { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,259 +0,0 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.13
|
||||
|
||||
import utils 1.0
|
||||
import shared 1.0
|
||||
import shared.stores 1.0
|
||||
import shared.panels 1.0
|
||||
import shared.popups 1.0
|
||||
import shared.controls.chat 1.0
|
||||
|
||||
import "../../popups"
|
||||
import "../../stores"
|
||||
import "../../controls"
|
||||
import "../../panels"
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import AppLayouts.Wallet.stores 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
spacing: 20
|
||||
|
||||
property PrivacyStore privacyStore
|
||||
property ProfileStore profileStore
|
||||
property WalletStore walletStore
|
||||
required property WalletAssetsStore walletAssetsStore
|
||||
required property CurrenciesStore currencyStore
|
||||
property var communitiesModel
|
||||
|
||||
property bool hasAnyProfileShowcaseChanges: false
|
||||
|
||||
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.previewIcon
|
||||
}
|
||||
|
||||
readonly property bool dirty: (!descriptionPanel.isEnsName &&
|
||||
descriptionPanel.displayName.text !== profileStore.displayName) ||
|
||||
descriptionPanel.bio.text !== profileStore.bio ||
|
||||
profileStore.socialLinksDirty ||
|
||||
biometricsSwitch.checked !== biometricsSwitch.currentStoredValue ||
|
||||
profileHeader.icon !== profileStore.profileLargeImage ||
|
||||
hasAnyProfileShowcaseChanges
|
||||
|
||||
readonly property bool valid: !!descriptionPanel.displayName.text && descriptionPanel.displayName.valid
|
||||
|
||||
function reset() {
|
||||
descriptionPanel.displayName.text = Qt.binding(() => { return profileStore.displayName })
|
||||
descriptionPanel.bio.text = Qt.binding(() => { return profileStore.bio })
|
||||
profileStore.resetSocialLinks()
|
||||
biometricsSwitch.checked = Qt.binding(() => { return biometricsSwitch.currentStoredValue })
|
||||
profileHeader.icon = Qt.binding(() => { return profileStore.profileLargeImage })
|
||||
|
||||
profileShowcaseCommunitiesPanel.reset()
|
||||
profileShowcaseAccountsPanel.reset()
|
||||
profileShowcaseCollectiblesPanel.reset()
|
||||
profileShowcaseAssetsPanel.reset()
|
||||
root.profileStore.requestProfileShowcasePreferences()
|
||||
hasAnyProfileShowcaseChanges = false
|
||||
}
|
||||
|
||||
function save() {
|
||||
if (hasAnyProfileShowcaseChanges)
|
||||
profileStore.storeProfileShowcasePreferences()
|
||||
|
||||
if (!descriptionPanel.isEnsName)
|
||||
profileStore.setDisplayName(descriptionPanel.displayName.text)
|
||||
profileStore.setBio(descriptionPanel.bio.text.trim())
|
||||
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 && !biometricsSwitch.currentStoredValue)
|
||||
root.privacyStore.tryStoreToKeyChain()
|
||||
else if (!biometricsSwitch.checked)
|
||||
root.privacyStore.tryRemoveFromKeyChain()
|
||||
|
||||
reset()
|
||||
}
|
||||
|
||||
onVisibleChanged: if (visible) profileStore.requestProfileShowcasePreferences()
|
||||
Component.onCompleted: profileStore.requestProfileShowcasePreferences()
|
||||
|
||||
readonly property Connections privacyStoreConnections: Connections {
|
||||
target: Qt.platform.os === Constants.mac ? root.privacyStore.privacyModule : null
|
||||
|
||||
function onStoreToKeychainError(errorDescription: string) {
|
||||
root.reset()
|
||||
}
|
||||
|
||||
function onStoreToKeychainSuccess() {
|
||||
root.reset()
|
||||
}
|
||||
}
|
||||
|
||||
ProfileHeader {
|
||||
id: profileHeader
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.current.padding
|
||||
Layout.rightMargin: Style.current.padding
|
||||
|
||||
store: root.profileStore
|
||||
|
||||
displayName: profileStore.name
|
||||
pubkey: profileStore.pubkey
|
||||
icon: profileStore.profileLargeImage
|
||||
imageSize: ProfileHeader.ImageSize.Big
|
||||
|
||||
displayNameVisible: false
|
||||
pubkeyVisible: false
|
||||
emojiHashVisible: false
|
||||
editImageButtonVisible: true
|
||||
}
|
||||
|
||||
ProfileDescriptionPanel {
|
||||
id: descriptionPanel
|
||||
|
||||
readonly property bool isEnsName: profileStore.preferredName
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
displayName.focus: !isEnsName
|
||||
displayName.input.edit.readOnly: isEnsName
|
||||
displayName.text: profileStore.name
|
||||
displayName.validationMode: StatusInput.ValidationMode.Always
|
||||
displayName.validators: isEnsName ? [] : Constants.validators.displayName
|
||||
bio.text: profileStore.bio
|
||||
}
|
||||
|
||||
Separator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ProfileSocialLinksPanel {
|
||||
Layout.fillWidth: true
|
||||
profileStore: root.profileStore
|
||||
socialLinksModel: root.profileStore.temporarySocialLinksModel
|
||||
}
|
||||
|
||||
Separator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
visible: Qt.platform.os === Constants.mac
|
||||
text: qsTr("Security")
|
||||
color: Theme.palette.baseColor1
|
||||
}
|
||||
|
||||
StatusListItem {
|
||||
Layout.fillWidth: true
|
||||
visible: Qt.platform.os === Constants.mac
|
||||
title: qsTr("Biometric login and transaction authentication")
|
||||
asset.name: "touch-id"
|
||||
components: [ StatusSwitch {
|
||||
id: biometricsSwitch
|
||||
horizontalPadding: 0
|
||||
readonly property bool currentStoredValue: localAccountSettings.storeToKeychainValue === Constants.keychain.storedValue.store
|
||||
checked: currentStoredValue
|
||||
} ]
|
||||
onClicked: biometricsSwitch.toggle()
|
||||
}
|
||||
|
||||
Separator {
|
||||
Layout.fillWidth: true
|
||||
visible: Qt.platform.os === Constants.mac
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
text: qsTr("Showcase")
|
||||
color: Theme.palette.baseColor1
|
||||
}
|
||||
|
||||
StatusTabBar {
|
||||
id: showcaseTabBar
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
leftPadding: 0
|
||||
text: qsTr("Communities")
|
||||
}
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: qsTr("Accounts")
|
||||
}
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: qsTr("Collectibles")
|
||||
}
|
||||
|
||||
StatusTabButton {
|
||||
width: implicitWidth
|
||||
text: qsTr("Assets")
|
||||
}
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
id: showcaseStack
|
||||
Layout.fillWidth: true
|
||||
currentIndex: showcaseTabBar.currentIndex
|
||||
|
||||
ProfileShowcaseCommunitiesPanel {
|
||||
id: profileShowcaseCommunitiesPanel
|
||||
Layout.minimumHeight: implicitHeight
|
||||
Layout.maximumHeight: implicitHeight
|
||||
baseModel: root.communitiesModel
|
||||
showcaseModel: root.profileStore.profileShowcaseCommunitiesModel
|
||||
onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true
|
||||
}
|
||||
|
||||
ProfileShowcaseAccountsPanel {
|
||||
id: profileShowcaseAccountsPanel
|
||||
Layout.minimumHeight: implicitHeight
|
||||
Layout.maximumHeight: implicitHeight
|
||||
baseModel: root.walletStore.accounts
|
||||
showcaseModel: root.profileStore.profileShowcaseAccountsModel
|
||||
currentWallet: root.walletStore.overview.mixedcaseAddress
|
||||
onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true
|
||||
}
|
||||
|
||||
ProfileShowcaseCollectiblesPanel {
|
||||
id: profileShowcaseCollectiblesPanel
|
||||
Layout.minimumHeight: implicitHeight
|
||||
Layout.maximumHeight: implicitHeight
|
||||
baseModel: root.profileStore.collectiblesModel
|
||||
showcaseModel: root.profileStore.profileShowcaseCollectiblesModel
|
||||
onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true
|
||||
}
|
||||
|
||||
ProfileShowcaseAssetsPanel {
|
||||
id: profileShowcaseAssetsPanel
|
||||
Layout.minimumHeight: implicitHeight
|
||||
Layout.maximumHeight: implicitHeight
|
||||
baseModel: root.walletAssetsStore.groupedAccountAssetsModel // TODO: instantiate an assets model in profile module
|
||||
showcaseModel: root.profileStore.profileShowcaseAssetsModel
|
||||
onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true
|
||||
formatCurrencyAmount: function(amount, symbol) {
|
||||
return root.currencyStore.formatCurrencyAmount(amount, symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue