diff --git a/storybook/pages/ContactDetailsPage.qml b/storybook/pages/ContactDetailsPage.qml index 0ebe2cd5a..c0b1c088a 100644 --- a/storybook/pages/ContactDetailsPage.qml +++ b/storybook/pages/ContactDetailsPage.qml @@ -20,100 +20,102 @@ import QtTest 1.15 SplitView { id: root - ColumnLayout { + Pane { SplitView.fillWidth: true SplitView.fillHeight: true - clip: true - spacing: 5 - Label { - Layout.fillWidth: true - text: "publicKey: " + contactDetails.publicKey - font.bold: true - } - Label { - Layout.fillWidth: true - text: "loading: " + contactDetails.loading - font.bold: true - } - Label { - Layout.fillWidth: true - text: "displayName: " + contactDetails.displayName - } - Label { - Layout.fillWidth: true - text: "ensName: " + contactDetails.ensName - } - Label { - Layout.fillWidth: true - text: "ensVerified: " + contactDetails.ensVerified - } - Label { - Layout.fillWidth: true - text: "localNickname: " + contactDetails.localNickname - } - Label { - Layout.fillWidth: true - text: "alias: " + contactDetails.alias - } - Label { - Layout.fillWidth: true - text: "icon: " + contactDetails.icon - } - Label { - Layout.fillWidth: true - text: "colorId: " + contactDetails.colorId - } - Label { - Layout.fillWidth: true - text: "colorHash: " + contactDetails.colorHash - } - Label { - Layout.fillWidth: true - text: "onlineStatus: " + contactDetails.onlineStatus - } - Label { - Layout.fillWidth: true - text: "isContact: " + contactDetails.isContact - } - Label { - Layout.fillWidth: true - text: "isCurrentUser: " + contactDetails.isCurrentUser - } - Label { - Layout.fillWidth: true - text: "isVerified: " + contactDetails.isVerified - } - Label { - Layout.fillWidth: true - text: "isUntrustworthy: " + contactDetails.isUntrustworthy - } - Label { - Layout.fillWidth: true - text: "isBlocked: " + contactDetails.isBlocked - } - Label { - Layout.fillWidth: true - text: "contactRequestState: " + contactDetails.contactRequestState - } - Label { - Layout.fillWidth: true - text: "incomingVerificationStatus: " + contactDetails.incomingVerificationStatus - } - Label { - Layout.fillWidth: true - text: "outgoingVerificationStatus: " + contactDetails.outgoingVerificationStatus - } + contentItem: ColumnLayout { + clip: true + spacing: 5 + Label { + Layout.fillWidth: true + text: "publicKey: " + contactDetails.publicKey + font.bold: true + } + Label { + Layout.fillWidth: true + text: "loading: " + contactDetails.loading + font.bold: true + } + Label { + Layout.fillWidth: true + text: "displayName: " + contactDetails.displayName + } + Label { + Layout.fillWidth: true + text: "ensName: " + contactDetails.ensName + } + Label { + Layout.fillWidth: true + text: "ensVerified: " + contactDetails.ensVerified + } + Label { + Layout.fillWidth: true + text: "localNickname: " + contactDetails.localNickname + } + Label { + Layout.fillWidth: true + text: "alias: " + contactDetails.alias + } + Label { + Layout.fillWidth: true + text: "icon: " + contactDetails.icon + } + Label { + Layout.fillWidth: true + text: "colorId: " + contactDetails.colorId + } + Label { + Layout.fillWidth: true + text: "colorHash: " + contactDetails.colorHash + } + Label { + Layout.fillWidth: true + text: "onlineStatus: " + contactDetails.onlineStatus + } + Label { + Layout.fillWidth: true + text: "isContact: " + contactDetails.isContact + } + Label { + Layout.fillWidth: true + text: "isCurrentUser: " + contactDetails.isCurrentUser + } + Label { + Layout.fillWidth: true + text: "isVerified: " + contactDetails.isVerified + } + Label { + Layout.fillWidth: true + text: "isUntrustworthy: " + contactDetails.isUntrustworthy + } + Label { + Layout.fillWidth: true + text: "isBlocked: " + contactDetails.isBlocked + } + Label { + Layout.fillWidth: true + text: "contactRequestState: " + contactDetails.contactRequestState + } + Label { + Layout.fillWidth: true + text: "incomingVerificationStatus: " + contactDetails.incomingVerificationStatus + } + Label { + Layout.fillWidth: true + text: "outgoingVerificationStatus: " + contactDetails.outgoingVerificationStatus + } - Pane { - contentItem: RowLayout { - ComboBox { - id: pubKeySelector - model: [...ModelUtils.modelToFlatArray(myContactsModel, "pubKey"), "myPubKey", "none"] - ModelChangeTracker { - id: modelChangeTracker - model: myContactsModel - onRevisionChanged: { - pubKeySelector.model = [...ModelUtils.modelToFlatArray(myContactsModel, "pubKey"), "myPubKey", "none"] + Pane { + contentItem: RowLayout { + ComboBox { + id: pubKeySelector + model: [...ModelUtils.modelToFlatArray(myContactsModel, "pubKey"), "myPubKey", "none"] + ModelChangeTracker { + id: modelChangeTracker + model: myContactsModel + onRevisionChanged: { + pubKeySelector.model = [...ModelUtils.modelToFlatArray(myContactsModel, "pubKey"), "myPubKey", "none"] + } } } } @@ -121,20 +123,22 @@ SplitView { } } - UsersModelEditor { - id: myContactsModelEditor + Pane { SplitView.fillHeight: true SplitView.preferredWidth: 500 - model: myContactsModel + contentItem: UsersModelEditor { + id: myContactsModelEditor + model: myContactsModel - onRemoveClicked: (index) => { - myContactsModel.remove(index, 1) - } - onRemoveAllClicked: () => { - myContactsModel.clear() - } - onAddClicked: () => { - myContactsModel.append(getNewUser(myContactsModel.count)) + onRemoveClicked: (index) => { + myContactsModel.remove(index, 1) + } + onRemoveAllClicked: () => { + myContactsModel.clear() + } + onAddClicked: () => { + myContactsModel.append(getNewUser(myContactsModel.count)) + } } } diff --git a/ui/StatusQ/include/StatusQ/concatmodel.h b/ui/StatusQ/include/StatusQ/concatmodel.h index 7c7373148..e0b39ee6e 100644 --- a/ui/StatusQ/include/StatusQ/concatmodel.h +++ b/ui/StatusQ/include/StatusQ/concatmodel.h @@ -67,7 +67,7 @@ public: // QAbstractItemModel interface int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; QHash roleNames() const override; // QQmlParserStatus interface diff --git a/ui/StatusQ/src/concatmodel.cpp b/ui/StatusQ/src/concatmodel.cpp index 84534a478..67d8dc7a3 100644 --- a/ui/StatusQ/src/concatmodel.cpp +++ b/ui/StatusQ/src/concatmodel.cpp @@ -310,27 +310,27 @@ bool ConcatModel::setData(const QModelIndex &index, const QVariant &value, int r if (!checkIndex(index, CheckIndexOption::IndexIsValid)) return false; - auto row = index.row(); + const auto row = index.row(); - auto source = sourceForIndex(row); + const auto source = sourceForIndex(row); if (source.first == nullptr) return false; - auto model = source.first->model(); + const auto model = source.first->model(); if (model == nullptr) return false; - auto sourcePosition = m_sources.indexOf(source.first); + const auto sourcePosition = m_sources.indexOf(source.first); if (sourcePosition == -1) return false; - auto& mapping = m_rolesMappingToSource[sourcePosition]; - auto it = mapping.find(role); + const auto& mapping = m_rolesMappingToSource[sourcePosition]; + const auto it = mapping.find(role); if (it == mapping.end()) return false; - auto sourceIndex = model->index(source.second, 0); + const auto sourceIndex = model->index(source.second, 0); if(!sourceIndex.isValid()) return false; diff --git a/ui/app/AppLayouts/Profile/helpers/ContactDetails.qml b/ui/app/AppLayouts/Profile/helpers/ContactDetails.qml index 01aa389f4..3e3a00f55 100644 --- a/ui/app/AppLayouts/Profile/helpers/ContactDetails.qml +++ b/ui/app/AppLayouts/Profile/helpers/ContactDetails.qml @@ -67,7 +67,7 @@ QObject { QObject { id: d - property bool loading: !itemData.available && !isMe + readonly property bool loading: !itemData.available && !isMe onLoadingChanged: { if (loading) { contactsStore.requestContactInfo(root.publicKey) diff --git a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml index 41c0967ab..58f2d07bb 100644 --- a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml @@ -8,23 +8,23 @@ QtObject { property var profileModule - property string pubkey: !!Global.userProfile? Global.userProfile.pubKey : "" - property string name: !!Global.userProfile? Global.userProfile.name : "" - property string username: !!Global.userProfile? Global.userProfile.username : "" - property string displayName: !!Global.userProfile? Global.userProfile.displayName : "" - property string preferredName: !!Global.userProfile? Global.userProfile.preferredName : "" - property string profileLargeImage: !!Global.userProfile? Global.userProfile.largeImage : "" - property string icon: !!Global.userProfile? Global.userProfile.icon : "" + property string pubkey: userProfile.pubKey + property string name: userProfile.name + property string username: userProfile.username + property string displayName: userProfile.displayName + property string preferredName: userProfile.preferredName + property string profileLargeImage: userProfile.largeImage + property string icon: userProfile.icon property bool userDeclinedBackupBanner: Global.appIsReady? localAccountSensitiveSettings.userDeclinedBackupBanner : false property var privacyStore: profileSectionModule.privacyModule - readonly property string keyUid: !!Global.userProfile ? Global.userProfile.keyUid : "" - readonly property bool isKeycardUser: !!Global.userProfile ? Global.userProfile.isKeycardUser : false - readonly property int currentUserStatus: !!Global.userProfile ? Global.userProfile.currentUserStatus : 0 - readonly property var thumbnailImage: !!Global.userProfile ? Global.userProfile.thumbnailImage : "" - readonly property var largeImage: !!Global.userProfile ? Global.userProfile.largeImage : "" + readonly property string keyUid: userProfile.keyUid + readonly property bool isKeycardUser: userProfile.isKeycardUser + readonly property int currentUserStatus: userProfile.currentUserStatus + readonly property var thumbnailImage: userProfile.thumbnailImage + readonly property var largeImage: userProfile.largeImage readonly property int colorId: Utils.colorIdForPubkey(root.pubkey) readonly property var colorHash: Utils.getColorHashAsJson(root.pubkey, name != "") - readonly property string defaultDisplayName: Utils.getDefaultDisplayName("", name, displayName, username) + readonly property string defaultDisplayName: ProfileUtils.displayName("", name, displayName, username) readonly property string bio: profileModule.bio readonly property string socialLinksJson: profileModule.socialLinksJson diff --git a/ui/imports/shared/views/ProfileDialogView.qml b/ui/imports/shared/views/ProfileDialogView.qml index 43bd53600..b5a9ebc1e 100644 --- a/ui/imports/shared/views/ProfileDialogView.qml +++ b/ui/imports/shared/views/ProfileDialogView.qml @@ -22,6 +22,7 @@ import shared.views.profile 1.0 import SortFilterProxyModel 0.2 import AppLayouts.Wallet.stores 1.0 as WalletNS +import AppLayouts.Profile.helpers 1.0 Pane { id: root @@ -60,13 +61,15 @@ Pane { id: background } + ContactDetails { + id: contactDetails + publicKey: root.publicKey + contactsStore: root.contactsStore + profileStore: root.profileStore + } + QtObject { id: d - property var contactDetails: Utils.getContactDetailsAsJson(root.publicKey, !isCurrentUser, !isCurrentUser, true) - - function reload() { - contactDetails = Utils.getContactDetailsAsJson(root.publicKey, !isCurrentUser, !isCurrentUser, true) - } readonly property bool isCurrentUser: root.profileStore.pubkey === root.publicKey readonly property string userDisplayName: contactDetails.displayName @@ -81,7 +84,7 @@ Pane { readonly property int contactRequestState: contactDetails.contactRequestState - readonly property int outgoingVerificationStatus: contactDetails.verificationStatus + readonly property int outgoingVerificationStatus: contactDetails.outgoingVerificationStatus readonly property int incomingVerificationStatus: contactDetails.incomingVerificationStatus readonly property bool isVerificationRequestSent: @@ -93,46 +96,10 @@ Pane { readonly property bool isTrusted: outgoingVerificationStatus === Constants.verificationStatus.trusted || incomingVerificationStatus === Constants.verificationStatus.trusted + readonly property bool isLocallyTrusted: contactDetails.trustStatus === Constants.trustStatus.trusted readonly property string linkToProfile: root.contactsStore.getLinkToProfile(root.publicKey) - - readonly property var conns: Connections { - target: root.contactsStore.myContactsModel ?? null - - function onItemChanged(pubKey) { - if (pubKey === root.publicKey) - d.reload() - } - } - - // FIXME: use myContactsModel for identity verification - readonly property var conns2: Connections { - target: root.contactsStore.receivedContactRequestsModel ?? null - - function onItemChanged(pubKey) { - if (pubKey === root.publicKey) - d.reload() - } - } - - readonly property var conns3: Connections { - target: root.contactsStore.sentContactRequestsModel ?? null - - function onItemChanged(pubKey) { - if (pubKey === root.publicKey) - d.reload() - } - } - } - - function reload() { - d.reload() - } - - onDirtyChanged: { - if (!dirty) - d.reload() } Component { @@ -168,8 +135,7 @@ Pane { objectName: "profileDialog_reviewContactRequestButton" size: StatusButton.Size.Small text: qsTr("Review contact request") - onClicked: Global.openReviewContactRequestPopup(root.publicKey, d.contactDetails, - popup => popup.closed.connect(d.reload)) + onClicked: Global.openReviewContactRequestPopup(root.publicKey, contactDetails, null) } } @@ -179,8 +145,7 @@ Pane { objectName: "profileDialog_sendContactRequestButton" size: StatusButton.Size.Small text: qsTr("Send contact request") - onClicked: Global.openContactRequestPopup(root.publicKey, d.contactDetails, - popup => popup.accepted.connect(d.reload)) + onClicked: Global.openContactRequestPopup(root.publicKey, contactDetails, null) } } @@ -190,7 +155,7 @@ Pane { size: StatusButton.Size.Small type: StatusBaseButton.Type.Danger text: qsTr("Block user") - onClicked: Global.blockContactRequested(root.publicKey, d.contactDetails) + onClicked: Global.blockContactRequested(root.publicKey, contactDetails) } } @@ -199,7 +164,7 @@ Pane { StatusButton { size: StatusButton.Size.Small text: qsTr("Unblock user") - onClicked: Global.unblockContactRequested(root.publicKey, d.contactDetails) + onClicked: Global.unblockContactRequested(root.publicKey, contactDetails) } } @@ -229,8 +194,7 @@ Pane { text: qsTr("Reply to ID verification request") objectName: "respondToIDRequest_StatusItem" icon.name: "checkmark-circle" - onClicked: Global.openIncomingIDRequestPopup(root.publicKey, d.contactDetails, - popup => popup.closed.connect(d.reload)) + onClicked: Global.openIncomingIDRequestPopup(root.publicKey, contactDetails, null) } } @@ -241,8 +205,7 @@ Pane { text: qsTr("Request ID verification") objectName: "requestIDVerification_StatusItem" icon.name: "checkmark-circle" - onClicked: Global.openSendIDRequestPopup(root.publicKey, d.contactDetails, - popup => popup.accepted.connect(d.reload)) + onClicked: Global.openSendIDRequestPopup(root.publicKey, contactDetails, null) } } @@ -253,8 +216,7 @@ Pane { text: d.incomingVerificationStatus !== Constants.verificationStatus.verified ? qsTr("ID verification pending") : qsTr("Review ID verification reply") icon.name: d.incomingVerificationStatus !== Constants.verificationStatus.verified ? "history" : "checkmark-circle" - onClicked: Global.openOutgoingIDRequestPopup(root.publicKey, d.contactDetails, - popup => popup.closed.connect(d.reload)) + onClicked: Global.openOutgoingIDRequestPopup(root.publicKey, contactDetails, null) } } @@ -302,14 +264,14 @@ Pane { : d.mainDisplayName pubkey: root.publicKey image: root.dirty ? root.dirtyValues.profileLargeImage - : Utils.addTimestampToURL(d.contactDetails.largeImage) + : Utils.addTimestampToURL(contactDetails.largeImage) interactive: false imageWidth: 90 imageHeight: imageWidth - ensVerified: d.contactDetails.ensVerified + ensVerified: contactDetails.ensVerified Binding on onlineStatus { - value: d.contactDetails.onlineStatus + value: contactDetails.onlineStatus when: !d.isCurrentUser } } @@ -400,24 +362,22 @@ Pane { SendContactRequestMenuItem { enabled: !d.isContact && !d.isBlocked && d.contactRequestState !== Constants.ContactRequestState.Sent && - d.contactDetails.trustStatus === Constants.trustStatus.untrustworthy // we have an action button otherwise + contactDetails.trustStatus === Constants.trustStatus.untrustworthy // we have an action button otherwise onTriggered: { - Global.openContactRequestPopup(root.publicKey, d.contactDetails, null) + Global.openContactRequestPopup(root.publicKey, contactDetails, null) } } StatusAction { text: qsTr("Mark as ID verified") icon.name: "checkmark-circle" enabled: root.idVerificationFlowsEnabled && d.isContact && !d.isBlocked && !(d.isTrusted || d.isLocallyTrusted) - onTriggered: Global.openMarkAsIDVerifiedPopup(root.publicKey, d.contactDetails, - popup => popup.accepted.connect(d.reload)) + onTriggered: Global.openMarkAsIDVerifiedPopup(root.publicKey, contactDetails, null) } StatusAction { text: d.userNickName ? qsTr("Edit nickname") : qsTr("Add nickname") icon.name: "edit_pencil" onTriggered: { - Global.openNicknamePopupRequested(root.publicKey, d.contactDetails, - popup => popup.closed.connect(d.reload)) + Global.openNicknamePopupRequested(root.publicKey, contactDetails, null) } } StatusAction { @@ -441,23 +401,22 @@ Pane { icon.name: "delete" type: StatusAction.Type.Danger enabled: root.idVerificationFlowsEnabled && d.isContact && (d.isTrusted || d.isLocallyTrusted) - onTriggered: Global.openRemoveIDVerificationDialog(root.publicKey, d.contactDetails, - popup => popup.accepted.connect(d.reload)) + onTriggered: Global.openRemoveIDVerificationDialog(root.publicKey, contactDetails, null) } StatusAction { text: qsTr("Remove nickname") icon.name: "delete" type: StatusAction.Type.Danger - enabled: !d.isCurrentUser && !!d.contactDetails.localNickname + enabled: !d.isCurrentUser && !!contactDetails.localNickname onTriggered: root.contactsStore.changeContactNickname(root.publicKey, "", d.optionalDisplayName, true) } StatusAction { text: qsTr("Mark as untrusted") icon.name: "warning" type: StatusAction.Type.Danger - enabled: d.contactDetails.trustStatus !== Constants.trustStatus.untrustworthy && !d.isBlocked + enabled: contactDetails.trustStatus !== Constants.trustStatus.untrustworthy && !d.isBlocked onTriggered: { - Global.markAsUntrustedRequested(root.publicKey, d.contactDetails) + Global.markAsUntrustedRequested(root.publicKey, contactDetails) } } StatusAction { @@ -471,10 +430,9 @@ Pane { text: qsTr("Remove untrusted mark") icon.name: "warning" type: StatusAction.Type.Danger - enabled: d.contactDetails.trustStatus === Constants.trustStatus.untrustworthy && !d.isBlocked + enabled: contactDetails.trustStatus === Constants.trustStatus.untrustworthy && !d.isBlocked onTriggered: { root.contactsStore.removeTrustStatus(root.publicKey) - d.reload() } } StatusAction { @@ -483,7 +441,7 @@ Pane { type: StatusAction.Type.Danger enabled: d.isContact && !d.isBlocked && d.contactRequestState !== Constants.ContactRequestState.Sent onTriggered: { - Global.removeContactRequested(root.publicKey, d.contactDetails) + Global.removeContactRequested(root.publicKey, contactDetails) } } StatusAction { @@ -492,7 +450,7 @@ Pane { type: StatusAction.Type.Danger enabled: !d.isBlocked onTriggered: { - Global.blockContactRequested(root.publicKey, d.contactDetails) + Global.blockContactRequested(root.publicKey, contactDetails) } } } @@ -524,7 +482,7 @@ Pane { objectName: "ProfileDialog_userVerificationIcons" visible: !d.isCurrentUser isContact: d.isContact - trustIndicator: d.contactDetails.trustStatus + trustIndicator: contactDetails.trustStatus isBlocked: d.isBlocked tiny: false } @@ -580,7 +538,7 @@ Pane { id: bioText width: bioScrollView.availableWidth wrapMode: Text.WrapAtWordBoundaryOrAnywhere - text: root.dirty ? root.dirtyValues.bio.trim() : d.contactDetails.bio.trim() + text: root.dirty ? root.dirtyValues.bio.trim() : contactDetails.bio.trim() } } EmojiHash {