diff --git a/storybook/pages/ContactDetailsPage.qml b/storybook/pages/ContactDetailsPage.qml new file mode 100644 index 0000000000..0ebe2cd5ad --- /dev/null +++ b/storybook/pages/ContactDetailsPage.qml @@ -0,0 +1,207 @@ +import QtQml 2.15 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import SortFilterProxyModel 0.2 +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Core.Utils 0.1 +import Storybook 1.0 +import utils 1.0 +import Models 1.0 + +import AppLayouts.Profile.helpers 1.0 +import AppLayouts.Profile.stores 1.0 + +import QtTest 1.15 + +SplitView { + id: root + + ColumnLayout { + 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 + } + + 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"] + } + } + } + } + } + } + + UsersModelEditor { + id: myContactsModelEditor + SplitView.fillHeight: true + SplitView.preferredWidth: 500 + model: myContactsModel + + onRemoveClicked: (index) => { + myContactsModel.remove(index, 1) + } + onRemoveAllClicked: () => { + myContactsModel.clear() + } + onAddClicked: () => { + myContactsModel.append(getNewUser(myContactsModel.count)) + } + } + + UsersModel { + id: myContactsModel + } + + ContactsStore { + id: contactsStoreMock + readonly property string myPublicKey: "0x123" + readonly property UsersModel contactsModel: myContactsModel + function requestContactInfo(pubKey) { + myContactsModel.append({ + pubKey: pubKey, + displayName: "displayName", + ensName: "ensName", + ensVerified: true, + localNickname: "localNickname", + alias: "alias", + icon: "icon", + colorId: 1, + colorHash: [], + onlineStatus: 1, + isContact: true, + isCurrentUser: false, + isVerified: true, + isUntrustworthy: false, + isBlocked: false, + contactRequestState: 3, + incomingVerificationStatus: 3, + outgoingVerificationStatus: 2, + defaaaultDisplayName: "defaultDisplayName", + optionalName: "optionalName", + lastUpdated: 1234567890, + lastUpdatedLocally: 1234567890, + thumbnailImage: "thumbnailImage", + largeImage: "largeImage", + isContactRequestReceived: false, + isContactRequestSent: false, + isSyncing: false, + removed: false, + trustStatus: 1, + bio: "bio" + }) + } + } + + ProfileStore { + id: profileStoreMock + readonly property string displayName: "myDisplayName" + readonly property string name: "myEnsName" + readonly property string username: "myUsername" + readonly property string icon: "myIcon" + readonly property int colorId: 1 + readonly property var colorHash: {} + readonly property int currentUserStatus: 1 + readonly property string defaultDisplayName: "myDefaultDisplayName" + readonly property string thumbnailImage: "myThumbnailImage" + readonly property string largeImage: "myLargeImage" + readonly property string bio: "myBio" + } + + ContactDetails { + id: contactDetails + contactsStore: contactsStoreMock + profileStore: profileStoreMock + publicKey: pubKeySelector.currentText === "myPubKey" ? "0x123" : pubKeySelector.currentText + } +} +// category: Contacts diff --git a/storybook/qmlTests/tests/tst_ContactDetails.qml b/storybook/qmlTests/tests/tst_ContactDetails.qml new file mode 100644 index 0000000000..72ab08d254 --- /dev/null +++ b/storybook/qmlTests/tests/tst_ContactDetails.qml @@ -0,0 +1,336 @@ +import QtQuick 2.15 +import QtTest 1.15 +import QtQml 2.15 + +import AppLayouts.Profile.helpers 1.0 +import AppLayouts.Profile.stores 1.0 + +Item { + id: root + + Component { + id: testComponent + ContactDetails { + id: contactDetails + } + } + + Component { + id: failingTestComponent + ContactDetails { + id: contactDetails + } + } + + Component { + id: contactsStore + ContactsStore { + readonly property string myPublicKey: "0x123" + readonly property ListModel contactsModel: ListModel { id: myContactsModel } + property var requestContactInfo: requestContactInfoCall + function requestContactInfoCall(pubKey) { + myContactsModel.append({ + pubKey: pubKey, + displayName: "displayName", + ensName: "ensName", + isEnsVerified: true, + localNickname: "localNickname", + alias: "alias", + icon: "icon", + colorId: 1, + colorHash: [], + onlineStatus: 1, + isContact: true, + isCurrentUser: false, + isVerified: true, + isUntrustworthy: false, + isBlocked: false, + contactRequest: 3, + incomingVerificationStatus: 3, + outgoingVerificationStatus: 2, + defaultDisplayName: "defaultDisplayName", + optionalName: "optionalName", + lastUpdated: 1234567890, + lastUpdatedLocally: 1234567890, + thumbnailImage: "thumbnailImage", + largeImage: "largeImage", + isContactRequestReceived: false, + isContactRequestSent: false, + isSyncing: false, + isRemoved: false, + trustStatus: 1, + bio: "bio" + }) + } + } + } + + Component { + id: profileStore + ProfileStore { + id: profileStoreMock + readonly property string displayName: "myDisplayName" + readonly property string name: "myEnsName" + readonly property string username: "myUsername" + readonly property string icon: "myIcon" + readonly property int colorId: 1 + readonly property var colorHash: {1} + readonly property int currentUserStatus: 1 + readonly property string defaultDisplayName: "myDefaultDisplayName" + readonly property string thumbnailImage: "myThumbnailImage" + readonly property string largeImage: "myLargeImage" + readonly property string bio: "myBio" + } + } + + TestCase { + name: "ContactDetailsTest" + function test_initialization() { + const contactDetails = createTemporaryObject(testComponent, root, { + contactsStore: createTemporaryObject(contactsStore, root), + profileStore: createTemporaryObject(profileStore, root), + publicKey: "" + }) + + verify(!!contactDetails, "Expected the contact details to initialize") + } + + function test_initializationOwnProfile() { + const contactDetails = createTemporaryObject(testComponent, root, { + contactsStore: createTemporaryObject(contactsStore, root), + profileStore: createTemporaryObject(profileStore, root), + publicKey: "0x123" + }) + + compare(contactDetails.loading, false, "Expected the loading flag to be false") + compare(contactDetails.publicKey,"0x123", "Expected the public key to be set") + compare(contactDetails.contactsStore.myPublicKey,"0x123", "Expected the contacts store to be set") + compare(contactDetails.profileStore.displayName,"myDisplayName", "Expected the profile store to be set") + compare(contactDetails.displayName, contactDetails.profileStore.displayName, "Expected the display name to be set") + compare(contactDetails.ensName, contactDetails.profileStore.name, "Expected the ens name to be set") + compare(contactDetails.ensVerified, true, "Expected the ensVerified to be set") + compare(contactDetails.localNickname, "", "Expected the local nickname to be empty") + compare(contactDetails.alias, contactDetails.profileStore.username, "Expected the alias to be set") + compare(contactDetails.icon, contactDetails.profileStore.icon, "Expected the icon to be set") + compare(contactDetails.colorId, contactDetails.profileStore.colorId, "Expected the color id to be set") + compare(contactDetails.colorHash, contactDetails.profileStore.colorHash, "Expected the color hash to be empty") + compare(contactDetails.onlineStatus, contactDetails.profileStore.currentUserStatus, "Expected the online status to be set") + compare(contactDetails.thumbnailImage, contactDetails.profileStore.thumbnailImage, "Expected the is contact flag to be set") + compare(contactDetails.largeImage, contactDetails.profileStore.largeImage, "Expected the is contact flag to be set") + compare(contactDetails.bio, contactDetails.profileStore.bio, "Expected the is contact flag to be set") + compare(contactDetails.isContact, false, "Expected the is contact flag to be set") + compare(contactDetails.isCurrentUser, true, "Expected the is contact flag to be set") + } + + function test_initializationWithContact() { + const contactsStoreMock = createTemporaryObject(contactsStore, root) + contactsStoreMock.requestContactInfo("0x321") //appending new contact to the model + + const contactDetails = createTemporaryObject(testComponent, root, { + contactsStore: contactsStoreMock, + profileStore: createTemporaryObject(profileStore, root), + publicKey: "0x321" + }) + + compare(contactDetails.loading, false, "Expected the loading flag to be false") + compare(contactDetails.publicKey,"0x321", "Expected the public key to be set") + compare(contactDetails.displayName, "displayName", "Expected the display name to be set") + compare(contactDetails.ensName, "ensName", "Expected the ens name to be set") + compare(contactDetails.ensVerified, true, "Expected the ensVerified to be set") + compare(contactDetails.localNickname, "localNickname", "Expected the local nickname to be set") + compare(contactDetails.alias, "alias", "Expected the alias to be set") + compare(contactDetails.icon, "icon", "Expected the icon to be set") + compare(contactDetails.colorId, 1, "Expected the color id to be set") + compare(contactDetails.onlineStatus, 1, "Expected the online status to be set") + compare(contactDetails.thumbnailImage, "thumbnailImage", "Expected the thumbnailImage to be set") + compare(contactDetails.largeImage, "largeImage", "Expected the largeImage to be set") + compare(contactDetails.bio, "bio", "Expected the bio to be set") + compare(contactDetails.isContact, true, "Expected the is contact flag to be set") + compare(contactDetails.isCurrentUser, false, "Expected the isCurrentUser flag to be set") + compare(contactDetails.isVerified, true, "Expected the isVerified flag to be set") + compare(contactDetails.isUntrustworthy, false, "Expected the isUntrustworthy flag to be set") + compare(contactDetails.isBlocked, false, "Expected the isBlocked flag to be set") + compare(contactDetails.contactRequestState, 3, "Expected the contactRequestState flag to be set") + compare(contactDetails.incomingVerificationStatus, 3, "Expected the incomingVerificationStatus flag to be set") + compare(contactDetails.outgoingVerificationStatus, 2, "Expected the outgoingVerificationStatus flag to be set") + compare(contactDetails.defaultDisplayName, "defaultDisplayName", "Expected the defaultDisplayName to be set") + compare(contactDetails.optionalName, "optionalName", "Expected the optionalName to be set") + compare(contactDetails.lastUpdated, 1234567890, "Expected the lastUpdated to be set") + compare(contactDetails.lastUpdatedLocally, 1234567890, "Expected the lastUpdatedLocally to be set") + compare(contactDetails.isContactRequestReceived, false, "Expected the isContactRequestReceived flag to be set") + compare(contactDetails.isContactRequestSent, false, "Expected the isContactRequestSent flag to be set") + compare(contactDetails.isSyncing, false, "Expected the isSyncing to be set") + compare(contactDetails.removed, false, "Expected the removed flag to be set") + compare(contactDetails.trustStatus, 1, "Expected the trustStatus flag to be set") + } + + function test_initFails() { + ignoreWarning(new RegExp("Required property publicKey was not initialized")) + ignoreWarning(new RegExp("Required property contactsStore was not initialized")) + ignoreWarning(new RegExp("Required property profileStore was not initialized")) + + const contactDetails = createTemporaryObject(failingTestComponent, root) + verify(!contactDetails, "Expected the contact details to fail to initialize") + } + + function test_initWithEmptyContacts() { + const contactsStoreMock = createTemporaryObject(contactsStore, root) + let requestContactInfoCallCount = 0 + contactsStoreMock.requestContactInfo = function(pubKey) { + requestContactInfoCallCount++ + } + const contactDetails = createTemporaryObject(testComponent, root, { + contactsStore: contactsStoreMock, + profileStore: createTemporaryObject(profileStore, root), + publicKey: "0x1234" + }) + + compare(requestContactInfoCallCount, 1, "Expected the requestContactInfo to be called") + compare(contactDetails.loading, true, "Expected the loading flag to be true") + compare(contactDetails.publicKey,"0x1234", "Expected the public key to be set") + + //add the contact + contactsStoreMock.requestContactInfo = contactsStoreMock.requestContactInfoCall + contactsStoreMock.requestContactInfo("0x1234") + + compare(contactDetails.loading, false, "Expected the loading flag to be false") + compare(contactDetails.publicKey,"0x1234", "Expected the public key to be set") + compare(contactDetails.displayName, "displayName", "Expected the display name to be set") + compare(contactDetails.ensName, "ensName", "Expected the ens name to be set") + compare(contactDetails.ensVerified, true, "Expected the ensVerified to be set") + } + + function test_contactRemovedFromModel() { + const contactsStoreMock = createTemporaryObject(contactsStore, root) + contactsStoreMock.requestContactInfo("0x1234") //appending new contact to the model + + const contactDetails = createTemporaryObject(testComponent, root, { + contactsStore: contactsStoreMock, + profileStore: createTemporaryObject(profileStore, root), + publicKey: "0x1234" + }) + + compare(contactDetails.loading, false, "Expected the loading flag to be false") + compare(contactDetails.publicKey,"0x1234", "Expected the public key to be set") + compare(contactDetails.displayName, "displayName", "Expected the display name to be set") + compare(contactDetails.ensName, "ensName", "Expected the ens name to be set") + compare(contactDetails.ensVerified, true, "Expected the ensVerified to be set") + + // removing from model should not clear the contact details + contactsStoreMock.contactsModel.remove(0) + + compare(contactDetails.loading, false, "Expected the loading flag to be true") + compare(contactDetails.publicKey,"0x1234", "Expected the public key to be set") + compare(contactDetails.displayName, "displayName", "Expected the display name to be empty") + compare(contactDetails.ensName, "ensName", "Expected the ens name to be empty") + compare(contactDetails.ensVerified, true, "Expected the ensVerified to be false") + } + + function test_liveUpdate() { + const contactsStoreMock = createTemporaryObject(contactsStore, root) + contactsStoreMock.requestContactInfo("0x1234") //appending new contact to the model + + const contactDetails = createTemporaryObject(testComponent, root, { + contactsStore: contactsStoreMock, + profileStore: createTemporaryObject(profileStore, root), + publicKey: "0x1234" + }) + + compare(contactDetails.loading, false, "Expected the loading flag to be false") + compare(contactDetails.publicKey,"0x1234", "Expected the public key to be set") + compare(contactDetails.displayName, "displayName", "Expected the display name to be set") + compare(contactDetails.ensName, "ensName", "Expected the ens name to be set") + compare(contactDetails.ensVerified, true, "Expected the ensVerified to be set") + + // updating the contact should update the contact details + contactsStoreMock.contactsModel.set(0, { + pubKey: "0x1234", + displayName: "newDisplayName", + ensName: "newEnsName", + isEnsVerified: false, + localNickname: "newLocalNickname", + alias: "newAlias", + icon: "newIcon", + colorId: 2, + colorHash: [], + onlineStatus: 2, + isContact: false, + isCurrentUser: true, + isVerified: false, + isUntrustworthy: true, + isBlocked: true, + contactRequest: 2, + incomingVerificationStatus: 2, + outgoingVerificationStatus: 1, + defaultDisplayName: "newDefaultDisplayName", + optionalName: "newOptionalName", + lastUpdated: 1234567891, + lastUpdatedLocally: 1234567891, + thumbnailImage: "newThumbnailImage", + largeImage: "newLargeImage", + isContactRequestReceived: true, + isContactRequestSent: true, + isSyncing: true, + isRemoved: true, + trustStatus: 2, + bio: "newBio" + }) + + compare(contactDetails.loading, false, "Expected the loading flag to be false") + compare(contactDetails.publicKey,"0x1234", "Expected the public key to be set") + compare(contactDetails.displayName, "newDisplayName", "Expected the display name to be set") + compare(contactDetails.ensName, "newEnsName", "Expected the ens name to be set") + compare(contactDetails.ensVerified, false, "Expected the ensVerified to be set") + compare(contactDetails.localNickname, "newLocalNickname", "Expected the local nickname to be set") + compare(contactDetails.alias, "newAlias", "Expected the alias to be set") + compare(contactDetails.icon, "newIcon", "Expected the icon to be set") + compare(contactDetails.colorId, 2, "Expected the color id to be set") + compare(contactDetails.onlineStatus, 2, "Expected the online status to be set") + compare(contactDetails.thumbnailImage, "newThumbnailImage", "Expected the thumbnailImage to be set") + compare(contactDetails.largeImage, "newLargeImage", "Expected the largeImage to be set") + compare(contactDetails.bio, "newBio", "Expected the bio to be set") + compare(contactDetails.isContact, false, "Expected the is contact flag to be set") + compare(contactDetails.isCurrentUser, true, "Expected the isCurrentUser flag to be set") + compare(contactDetails.isVerified, false, "Expected the isVerified flag to be set") + compare(contactDetails.isUntrustworthy, true, "Expected the isUntrustworthy flag to be set") + compare(contactDetails.isBlocked, true, "Expected the isBlocked flag to be set") + compare(contactDetails.contactRequestState, 2, "Expected the contactRequestState flag to be set") + compare(contactDetails.incomingVerificationStatus, 2, "Expected the incomingVerificationStatus flag to be set") + compare(contactDetails.outgoingVerificationStatus, 1, "Expected the outgoingVerificationStatus flag to be set") + compare(contactDetails.defaultDisplayName, "newDefaultDisplayName", "Expected the defaultDisplayName to be set") + compare(contactDetails.optionalName, "newOptionalName", "Expected the optionalName to be set") + compare(contactDetails.lastUpdated, 1234567891, "Expected the lastUpdated to be set") + compare(contactDetails.lastUpdatedLocally, 1234567891, "Expected the lastUpdatedLocally to be set") + compare(contactDetails.isContactRequestReceived, true, "Expected the isContactRequestReceived flag to be set") + compare(contactDetails.isContactRequestSent, true, "Expected the isContactRequestSent flag to be set") + compare(contactDetails.isSyncing, true, "Expected the isSyncing to be set") + compare(contactDetails.removed, true, "Expected the removed flag to be set") + compare(contactDetails.trustStatus, 2, "Expected the trustStatus flag to be set") + } + + function test_changingPublicKeyFromOwnToContact() { + const contactsStoreMock = createTemporaryObject(contactsStore, root) + const contactDetails = createTemporaryObject(testComponent, root, { + contactsStore: contactsStoreMock, + profileStore: createTemporaryObject(profileStore, root), + publicKey: "0x123" + }) + + compare(contactDetails.loading, false, "Expected the loading flag to be false") + compare(contactDetails.publicKey,"0x123", "Expected the public key to be set") + compare(contactDetails.contactsStore.myPublicKey,"0x123", "Expected the contacts store to be set") + compare(contactDetails.profileStore.displayName,"myDisplayName", "Expected the profile store to be set") + compare(contactDetails.displayName, contactDetails.profileStore.displayName, "Expected the display name to be set") + compare(contactDetails.ensName, contactDetails.profileStore.name, "Expected the ens name to be set") + + contactDetails.publicKey = "0x321" + + compare(contactDetails.loading, false, "Expected the loading flag to be false") + compare(contactDetails.publicKey,"0x321", "Expected the public key to be set") + compare(contactDetails.displayName, "displayName", "Expected the display name to be set") + compare(contactDetails.ensName, "ensName", "Expected the ens name to be set") + compare(contactDetails.ensVerified, true, "Expected the ensVerified to be set") + compare(contactDetails.localNickname, "localNickname", "Expected the local nickname to be set") + } + } +} \ No newline at end of file diff --git a/storybook/src/Storybook/StorybookUtils.qml b/storybook/src/Storybook/StorybookUtils.qml index 66c747e9e3..c64ccc5197 100644 --- a/storybook/src/Storybook/StorybookUtils.qml +++ b/storybook/src/Storybook/StorybookUtils.qml @@ -20,4 +20,15 @@ QtObject { const regex = new RegExp(`^[ \\t]{${minIndent}}`, "gm") return code.replace(regex, "") } + + function findChild(parent, name) { + if (!parent || !parent.children) + return null + + for (let i = 0; i < parent.children.length; i++) { + if (parent.children[i].objectName === name) + return parent.children[i] + } + return null + } } diff --git a/storybook/stubs/AppLayouts/Profile/stores/ContactsStore.qml b/storybook/stubs/AppLayouts/Profile/stores/ContactsStore.qml new file mode 100644 index 0000000000..52d5a7a7f7 --- /dev/null +++ b/storybook/stubs/AppLayouts/Profile/stores/ContactsStore.qml @@ -0,0 +1,4 @@ +import QtQuick 2.15 + +QtObject { +} diff --git a/storybook/stubs/AppLayouts/Profile/stores/ProfileStore.qml b/storybook/stubs/AppLayouts/Profile/stores/ProfileStore.qml new file mode 100644 index 0000000000..52d5a7a7f7 --- /dev/null +++ b/storybook/stubs/AppLayouts/Profile/stores/ProfileStore.qml @@ -0,0 +1,4 @@ +import QtQuick 2.15 + +QtObject { +} diff --git a/storybook/stubs/AppLayouts/Profile/stores/qmldir b/storybook/stubs/AppLayouts/Profile/stores/qmldir index 5b658d4a30..be7dded159 100644 --- a/storybook/stubs/AppLayouts/Profile/stores/qmldir +++ b/storybook/stubs/AppLayouts/Profile/stores/qmldir @@ -1,3 +1,5 @@ LanguageStore 1.0 LanguageStore.qml ProfileSectionStore 1.0 ProfileSectionStore.qml WalletStore 1.0 WalletStore.qml +ContactsStore 1.0 ContactsStore.qml +ProfileStore 1.0 ProfileStore.qml diff --git a/ui/app/AppLayouts/Profile/helpers/ContactDetails.qml b/ui/app/AppLayouts/Profile/helpers/ContactDetails.qml new file mode 100644 index 0000000000..01aa389f4f --- /dev/null +++ b/ui/app/AppLayouts/Profile/helpers/ContactDetails.qml @@ -0,0 +1,113 @@ +import QtQuick 2.15 + +import StatusQ 0.1 +import StatusQ.Core.Utils 0.1 + +import AppLayouts.Profile.stores 1.0 + +import utils 1.0 + +QObject { + id: root + + required property ContactsStore contactsStore + required property ProfileStore profileStore + required property string publicKey + + readonly property alias loading: d.loading + + // model properties + readonly property string displayName: d.contactDetails.displayName ?? "" + readonly property string ensName: d.contactDetails.ensName ?? "" + readonly property bool ensVerified: d.contactDetails.isEnsVerified ?? false + readonly property string localNickname: d.contactDetails.localNickname ?? "" + readonly property string alias: d.contactDetails.alias ?? "" + readonly property string icon: d.contactDetails.icon ?? "" + readonly property int colorId: d.contactDetails.colorId ?? 0 + readonly property var colorHash: d.contactDetails.colorHash ?? [] + readonly property int onlineStatus: d.contactDetails.onlineStatus ?? Constants.onlineStatus.inactive + readonly property bool isContact: d.contactDetails.isContact ?? false + readonly property bool isCurrentUser: d.contactDetails.isCurrentUser ?? false + readonly property bool isVerified: d.contactDetails.isVerified ?? false + readonly property bool isUntrustworthy: d.contactDetails.isUntrustworthy ?? false + readonly property bool isBlocked: d.contactDetails.isBlocked ?? false + readonly property int contactRequestState: d.contactDetails.contactRequest ?? Constants.ContactRequestState.None + readonly property int incomingVerificationStatus: d.contactDetails.incomingVerificationStatus ?? Constants.verificationStatus.unverified + readonly property int outgoingVerificationStatus: d.contactDetails.outgoingVerificationStatus ?? Constants.verificationStatus.unverified + readonly property string defaultDisplayName: d.contactDetails.defaultDisplayName ?? "" + readonly property string optionalName: d.contactDetails.optionalName ?? "" + readonly property int lastUpdated: d.contactDetails.lastUpdated ?? 0 + readonly property int lastUpdatedLocally: d.contactDetails.lastUpdatedLocally ?? 0 + readonly property string thumbnailImage: d.contactDetails.thumbnailImage ?? "" + readonly property string largeImage: d.contactDetails.largeImage ?? "" + readonly property bool isContactRequestReceived: d.contactDetails.isContactRequestReceived ?? false + readonly property bool isContactRequestSent: d.contactDetails.isContactRequestSent ?? false + readonly property bool isSyncing: d.contactDetails.isSyncing ?? false + readonly property bool removed: d.contactDetails.isRemoved ?? false + readonly property int trustStatus: d.contactDetails.trustStatus ?? Constants.trustStatus.unknown + readonly property string bio: d.contactDetails.bio ?? "" + + // Backwards compatibility properties - Don't use in new code + // TODO: #14965 - Try to remove these properties + readonly property string name: ensName + readonly property int verificationStatus: outgoingVerificationStatus + + // Extra properties provided by getContactDetailsAsJson, not available in the model + // TODO: #14964 - Review all the model rolenames and fill the rest of the properties with data from the model + //readonly property int verificationStatus: d.contactDetails.verificationStatus ?? Constants.verificationStatus.unverified + //readonly property var socialLinks: d.contactDetails.socialLinks ?? [] + + ModelEntry { + id: itemData + sourceModel: root.publicKey !== "" && !d.isMe ? contactsStore.contactsModel : null + key: "pubKey" + value: root.publicKey + cacheOnRemoval: true + } + + QObject { + id: d + property bool loading: !itemData.available && !isMe + onLoadingChanged: { + if (loading) { + contactsStore.requestContactInfo(root.publicKey) + } + } + + readonly property bool isMe: root.contactsStore.myPublicKey === root.publicKey + readonly property var ownProfile: QObject { + readonly property string displayName: root.profileStore.displayName + readonly property string ensName: root.profileStore.name + readonly property bool isEnsVerified: root.profileStore.name !== "" + readonly property string localNickname: "" + readonly property string alias: root.profileStore.username + readonly property string icon: root.profileStore.icon + readonly property int colorId: root.profileStore.colorId + readonly property var colorHash: root.profileStore.colorHash + readonly property int onlineStatus: root.profileStore.currentUserStatus + readonly property bool isContact: false + readonly property bool isCurrentUser: true + readonly property bool isVerified: false + readonly property bool isUntrustworthy: false + readonly property bool isBlocked: false + readonly property int contactRequestState: Constants.ContactRequestState.None + readonly property int incomingVerificationStatus: Constants.verificationStatus.unverified + readonly property int outgoingVerificationStatus: Constants.verificationStatus.unverified + readonly property string defaultDisplayName: root.profileStore.defaultDisplayName + readonly property string optionalName: defaultDisplayName + readonly property string name: defaultDisplayName + readonly property int lastUpdated: 0 + readonly property int lastUpdatedLocally: 0 + readonly property string thumbnailImage: root.profileStore.thumbnailImage + readonly property string largeImage: root.profileStore.largeImage + readonly property bool isContactRequestReceived: Constants.ContactRequestState.None + readonly property bool isContactRequestSent: Constants.ContactRequestState.None + readonly property bool isSyncing: false + readonly property bool removed: false + readonly property int trustStatus: Constants.trustStatus.unknown + readonly property string bio: root.profileStore.bio + } + + readonly property var contactDetails: !isMe ? itemData.item : ownProfile + } +} diff --git a/ui/app/AppLayouts/Profile/helpers/qmldir b/ui/app/AppLayouts/Profile/helpers/qmldir index 7b4ac1e81c..80023a31f6 100644 --- a/ui/app/AppLayouts/Profile/helpers/qmldir +++ b/ui/app/AppLayouts/Profile/helpers/qmldir @@ -3,3 +3,4 @@ ProfileShowcaseModelAdapter 1.0 ProfileShowcaseModelAdapter.qml ProfileShowcaseSettingsModelAdapter 1.0 ProfileShowcaseSettingsModelAdapter.qml ProfileShowcaseModels 1.0 ProfileShowcaseModels.qml VisibilityAndPositionDirtyStateModel 1.0 VisibilityAndPositionDirtyStateModel.qml +ContactDetails 1.0 ContactDetails.qml diff --git a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml index 1a4e0b095b..93f2db87d9 100644 --- a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml @@ -1,6 +1,8 @@ import QtQuick 2.13 import utils 1.0 +import StatusQ 0.1 + QtObject { id: root @@ -11,6 +13,8 @@ QtObject { property string myPublicKey: !!Global.userProfile? Global.userProfile.pubKey : "" + // contactsModel holds all available contacts + property var contactsModel: contactsModule.contactsModel property var myContactsModel: contactsModule.myMutualContactsModel property var blockedContactsModel: contactsModule.blockedContactsModel property var receivedContactRequestsModel: contactsModule.receivedContactRequestsModel diff --git a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml index 92cec5710a..41c0967abb 100644 --- a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml @@ -19,6 +19,12 @@ QtObject { 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 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 bio: profileModule.bio readonly property string socialLinksJson: profileModule.socialLinksJson diff --git a/ui/app/AppLayouts/Profile/stores/qmldir b/ui/app/AppLayouts/Profile/stores/qmldir index 4b4a8cb32c..017c64b5fd 100644 --- a/ui/app/AppLayouts/Profile/stores/qmldir +++ b/ui/app/AppLayouts/Profile/stores/qmldir @@ -5,3 +5,4 @@ NotificationsStore 1.0 NotificationsStore.qml DevicesStore 1.0 DevicesStore.qml ProfileSectionStore 1.0 ProfileSectionStore.qml WalletStore 1.0 WalletStore.qml +ContactsStore 1.0 ContactsStore.qml