ContactDetails decomposed into smaller, more specialized components

Closes: #16793
This commit is contained in:
Michał Cieślak 2024-11-21 16:10:58 +01:00 committed by Michał
parent 4a36c71f3b
commit 7323889a8c
15 changed files with 475 additions and 877 deletions

View File

@ -1,194 +0,0 @@
import QtTest 1.15
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Core.Utils 0.1
import Models 1.0
import AppLayouts.Profile.helpers 1.0
import AppLayouts.Profile.stores 1.0
SplitView {
id: root
Pane {
SplitView.fillWidth: true
SplitView.fillHeight: true
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
}
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 {
SplitView.fillHeight: true
SplitView.preferredWidth: 500
contentItem: UsersModelEditor {
id: myContactsModelEditor
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,
preferredDisplayName: "preferredDisplayName",
lastUpdated: 1234567890,
lastUpdatedLocally: 1234567890,
thumbnailImage: "thumbnailImage",
largeImage: "largeImage",
isContactRequestReceived: false,
isContactRequestSent: 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 preferredDisplayName: "myPreferredDisplayName"
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
// Page is working in general but throwing multiple "Cannot read property" when changing id via combo box
// status: decent

View File

@ -13,6 +13,7 @@ import StatusQ.Core.Utils 0.1 as StatusQUtils
import AppLayouts.stores 1.0 as AppLayoutStores
import AppLayouts.Profile.stores 1.0 as ProfileStores
import AppLayouts.Profile.helpers 1.0
import AppLayouts.Wallet.stores 1.0
import Storybook 1.0
@ -22,23 +23,17 @@ SplitView {
id: root
property bool globalUtilsReady: false
property bool mainModuleReady: false
// globalUtilsInst mock
QtObject {
function getColorId(publicKey) { return colorId.value }
function getColorHashAsJson(publicKey, skipEnsVerification=false) {
if (skipEnsVerification)
return
return JSON.stringify([{colorId: 0, segmentLength: 1},
{colorId: 19, segmentLength: 2}])
}
function addTimestampToURL(url) {
return url
}
function isCompressedPubKey() {
return false
}
Component.onCompleted: {
Utils.globalUtilsInst = this
root.globalUtilsReady = true
@ -50,45 +45,6 @@ SplitView {
}
}
// mainModuleInst mock
QtObject {
function isEnsVerified(publicKey) {
return ensVerified.checked
}
function getContactDetailsAsJson(publicKey, getVerificationRequest=true, getOnlineStatus=false, includeDetails=false) {
return JSON.stringify({ displayName: displayName.text,
optionalName: "",
displayIcon: "",
publicKey: publicKey,
name: name.text,
ensVerified: ensVerified.checked,
alias: "Mock Alias Triplet",
lastUpdated: Date.now(),
lastUpdatedLocally: Date.now(),
localNickname: localNickname.text,
thumbnailImage: "",
largeImage: userImage.checked ? Theme.png("status-logo") : "",
isContact: ctrlIsContact.checked,
isBlocked: ctrlIsBlocked.checked,
isSyncing: false,
trustStatus: ctrlTrustStatus.currentValue,
verificationStatus: ctrlVerificationStatus.currentValue,
contactRequestState: ctrlContactRequestState.currentValue,
bio: bio.text,
onlineStatus: ctrlOnlineStatus.currentValue
})
}
Component.onCompleted: {
Utils.mainModuleInst = this
root.mainModuleReady = true
}
Component.onDestruction: {
root.mainModuleReady = false
Utils.mainModuleInst = {}
}
}
ListModel {
id: linksModel
ListElement {
@ -147,144 +103,6 @@ SplitView {
Logs { id: logs }
Popups {
popupParent: root
sharedRootStore: SharedStores.RootStore {}
rootStore: AppLayoutStores.RootStore {
property var contactStore: QtObject {
property var contactsModule: null
function changeContactNickname(publicKey, newNickname, displayName, isEdit) {
logs.logEvent("rootStore::contactsStore::changeContactNickname", ["publicKey", "newNickname", "displayName", "isEdit"], arguments)
localNickname.text = newNickname
}
function blockContact(publicKey) {
logs.logEvent("rootStore::contactStore::blockContact", ["publicKey"], arguments)
ctrlIsBlocked.checked = true
}
function unblockContact(publicKey) {
logs.logEvent("rootStore::contactStore::unblockContact", ["publicKey"], arguments)
ctrlIsBlocked.checked = false
}
function sendContactRequest(publicKey, message) {
logs.logEvent("rootStore::contactStore::sendContactRequest", ["publicKey", "message"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.Sent)
}
function acceptContactRequest(publicKey, contactRequestId) {
logs.logEvent("rootStore::contactStore::acceptContactRequest", ["publicKey, contactRequestId"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.Mutual)
}
function getLatestContactRequestForContactAsJson(pubKey) {
logs.logEvent("rootStore::contactStore::getLatestContactRequestForContactAsJson", ["pubKey"], arguments)
return {
id: "123456789",
from: pubKey,
clock: Date.now(),
text: "Hey Jo, its Alex here, we met at devcon last week!",
contactRequestState: Constants.ContactRequestState.Received
}
}
function sendVerificationRequest(publicKey, challenge) {
logs.logEvent("rootStore::contactStore::sendVerificationRequest", ["publicKey", "challenge"], arguments)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.verifying)
}
function markUntrustworthy(publicKey) {
logs.logEvent("rootStore::contactStore::markUntrustworthy", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.untrustworthy)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
}
function markAsTrusted(publicKey) {
logs.logEvent("rootStore::contactStore::markAsTrusted", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.trusted)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.trusted)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.trusted)
}
function removeContact(publicKey) {
logs.logEvent("rootStore::contactStore::removeContact", ["publicKey"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.None)
ctrlIsContact.checked = false
}
function verifiedTrusted(publicKey) {
logs.logEvent("rootStore::contactStore::verifiedTrusted", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.trusted)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.trusted)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.trusted)
}
function removeTrustStatus(publicKey) {
logs.logEvent("rootStore::contactStore::removeTrustStatus", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.unknown)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
}
function removeTrustVerificationStatus(publicKey) {
logs.logEvent("rootStore::contactStore::removeTrustVerificationStatus", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.unknown)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
}
function cancelVerificationRequest(pubKey) {
logs.logEvent("rootStore::contactStore::cancelVerificationRequest", ["pubKey"], arguments)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
}
function declineVerificationRequest(pubKey) {
logs.logEvent("rootStore::contactStore::declineVerificationRequest", ["pubKey"], arguments)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
}
function acceptVerificationRequest(pubKey, response) {
logs.logEvent("rootStore::contactStore::acceptVerificationRequest", ["pubKey"], arguments)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.verifying)
}
function verifiedUntrustworthy(pubKey) {
logs.logEvent("rootStore::contactStore::verifiedUntrustworthy", ["pubKey"], arguments)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.untrustworthy)
}
function getSentVerificationDetailsAsJson(pubKey) {
return {
requestStatus: ctrlVerificationStatus.currentValue,
challenge: "The real Alex would know this 100%! Whats my favourite colour?",
response: ctrlIncomingVerificationStatus.currentValue === Constants.verificationStatus.verified ? "Yellow!" : "",
displayName: ProfileUtils.displayName(localNickname.text, name.text, displayName.text),
icon: Theme.png("status-logo"),
requestedAt: Date.now() - 86400000,
repliedAt: Date.now()
}
}
function getVerificationDetailsFromAsJson(pubKey) {
return {
from: "0xdeadbeef",
challenge: "The real Alex would know this 100%! Whats my favourite colour?",
response: "",
requestedAt: Date.now() - 86400000,
}
}
}
}
communityTokensStore: SharedStores.CommunityTokensStore {}
}
SplitView {
orientation: Qt.Vertical
SplitView.fillWidth: true
@ -299,15 +117,38 @@ SplitView {
clip: true
Loader {
active: root.globalUtilsReady && root.mainModuleReady
active: root.globalUtilsReady
width: parent.availableWidth
height: parent.availableHeight
sourceComponent: ProfileDialogView {
implicitWidth: 640
contactDetails: ContactDetails {
publicKey: "0x0000x"
displayName: displayNameTextField.text
localNickname: localNicknameTextField.text
ensVerified: ensVerifiedCheckBox.checked
ensName: ensNameTextField.text
name: ensNameTextField.text
isCurrentUser: ownProfileSwitch.checked
largeImage: userImageCheckBox.checked ? Theme.png("status-logo") : ""
onlineStatus: onlineStatusComboBox.currentValue
isBlocked: isBlockedCheckBox.checked
colorHash: [{colorId: 0, segmentLength: 1},
{colorId: 4, segmentLength: 2}]
colorId: colorIdSpinBox.value
}
readOnly: ctrlReadOnly.checked
publicKey: switchOwnProfile.checked ? "0xdeadbeef" : "0xrandomguy"
onCloseRequested: logs.logEvent("closeRequested()")
@ -323,50 +164,38 @@ SplitView {
collectiblesModel: CollectiblesModel {}
profileStore: ProfileStores.ProfileStore {
readonly property string pubkey: "0xdeadbeef"
readonly property string ensName: name.text
function getQrCodeSource() {
return "https://upload.wikimedia.org/wikipedia/commons/4/41/QR_Code_Example.svg"
}
}
contactsStore: ProfileStores.ContactsStore {
readonly property string myPublicKey: "0xdeadbeef"
function joinPrivateChat(publicKey) {
logs.logEvent("contactsStore::joinPrivateChat", ["publicKey"], arguments)
}
function markUntrustworthy(publicKey) {
logs.logEvent("contactsStore::markUntrustworthy", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.untrustworthy)
}
function removeContact(publicKey) {
logs.logEvent("contactsStore::removeContact", ["publicKey"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.None)
ctrlIsContact.checked = false
}
function acceptContactRequest(publicKey, contactRequestId) {
logs.logEvent("contactsStore::acceptContactRequest", ["publicKey, contactRequestId"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.Mutual)
}
function dismissContactRequest(publicKey, contactRequestId) {
logs.logEvent("contactsStore::dismissContactRequest", ["publicKey, contactRequestId"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.Dismissed)
}
function removeTrustStatus(publicKey) {
logs.logEvent("contactsStore::removeTrustStatus", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.unknown)
}
function removeTrustVerificationStatus(publicKey) {
logs.logEvent("contactsStore::removeTrustVerificationStatus", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.unknown)
}
function verifiedUntrustworthy(publicKey) {
@ -380,8 +209,6 @@ SplitView {
function cancelVerificationRequest(pubKey) {
logs.logEvent("contactsStore::cancelVerificationRequest", ["pubKey"], arguments)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
}
function getLinkToProfile(publicKey) {
@ -390,7 +217,6 @@ SplitView {
function changeContactNickname(publicKey, newNickname, displayName, isEdit) {
logs.logEvent("contactsStore::changeContactNickname", ["publicKey", "newNickname", "displayName", "isEdit"], arguments)
localNickname.text = newNickname
}
function requestProfileShowcase(publicKey) {
@ -431,48 +257,64 @@ SplitView {
RowLayout {
Layout.fillWidth: true
Switch {
id: switchOwnProfile
id: ownProfileSwitch
text: "Own profile"
checked: false
}
Switch {
id: ctrlReadOnly
text: "Readonly (preview)"
visible: switchOwnProfile.checked
visible: ownProfileSwitch.checked
checked: false
}
}
RowLayout {
Layout.fillWidth: true
Label { text: "localNickname:" }
TextField {
id: localNickname
id: localNicknameTextField
text: "Alex"
placeholderText: "Local Nickname"
}
Label { text: "displayName:" }
Label {
text: "displayName:"
}
TextField {
id: displayName
id: displayNameTextField
text: "Alex Pella"
placeholderText: "Display Name"
}
CheckBox {
id: ensVerified
id: ensVerifiedCheckBox
checked: true
text: "ensVerified"
}
Label { text: "name:" }
Label {
text: "name:"
}
TextField {
id: name
enabled: ensVerified.checked
text: ensVerified.checked ? "8⃣6⃣.eth" : ""
id: ensNameTextField
enabled: ensVerifiedCheckBox.checked
text: ensVerifiedCheckBox.checked ? "8⃣6⃣.eth" : ""
placeholderText: "ENS name"
}
}
RowLayout {
CheckBox {
id: userImage
id: userImageCheckBox
text: "User image"
checked: true
}
@ -481,18 +323,25 @@ SplitView {
text: "or"
}
Label {
enabled: !userImage.checked
enabled: !userImageCheckBox.checked
text: "colorId"
}
SpinBox {
id: colorId
enabled: !userImage.checked
id: colorIdSpinBox
enabled: !userImageCheckBox.checked
from: 0
to: 11 // Theme.palette.userCustomizationColors.length
}
Label { text: "onlineStatus" }
Label {
text: "onlineStatus"
}
ComboBox {
id: ctrlOnlineStatus
id: onlineStatusComboBox
textRole: "text"
valueRole: "value"
model: [
@ -504,15 +353,19 @@ SplitView {
}
RowLayout {
Layout.fillWidth: true
enabled: !switchOwnProfile.checked
enabled: !ownProfileSwitch.checked
CheckBox {
id: ctrlIsContact
enabled: true
checked: ctrlContactRequestState.currentValue === Constants.ContactRequestState.Mutual
text: "isContact"
}
ComboBox {
id: ctrlContactRequestState
textRole: "text"
valueRole: "value"
model: [
@ -523,9 +376,14 @@ SplitView {
{ value: Constants.ContactRequestState.Dismissed, text: "Dismissed" }
]
}
Label { text: "trustStatus:" }
Label {
text: "trustStatus:"
}
ComboBox {
id: ctrlTrustStatus
textRole: "text"
valueRole: "value"
model: [
@ -534,8 +392,10 @@ SplitView {
{ value: Constants.trustStatus.untrustworthy, text: "untrustworthy" }
]
}
CheckBox {
id: ctrlIsBlocked
id: isBlockedCheckBox
text: "isBlocked"
}
}
@ -615,3 +475,5 @@ Say hi, or find me on Twitter, GitHub, or Mastodon.
// https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=724%3A15511&t=h8DUW6Eysawqe5u0-0
// https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=6%3A16845&t=h8DUW6Eysawqe5u0-0
// https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=4%3A25437&t=h8DUW6Eysawqe5u0-0
// status: decent

View File

@ -0,0 +1,137 @@
import QtQuick 2.15
import QtTest 1.15
import QtQml 2.15
import utils 1.0
import StatusQ.Core.Utils 0.1
import mainui.adaptors 1.0
Item {
id: root
Component {
id: testComponent
AllContactsAdaptor {
selfPubKey: "0x0000x"
}
}
Component {
id: contatsModelComponent
ListModel {
ListElement {
pubKey: "0x0001x"
displayName: "displayName 1"
}
ListElement {
pubKey: "0x0002x"
displayName: "displayName 2"
}
}
}
TestCase {
name: "AllContactsAdaptorTest"
function test_selfEntry() {
const contactDetails = createTemporaryObject(testComponent, root)
const model = contactDetails.allContactsModel
compare(model.rowCount(), 1)
compare(ModelUtils.get(model, 0).pubKey, "0x0000x")
contactDetails.selfDisplayName = "Display name"
contactDetails.selfName = "@name"
contactDetails.selfPreferredDisplayName = "Preferred display name"
contactDetails.selfAlias = "Alias"
contactDetails.selfIcon = "Icon"
contactDetails.selfColorId = 42
contactDetails.selfColorHash = "Color hash"
contactDetails.selfOnlineStatus = Constants.onlineStatus.online
contactDetails.selfThumbnailImage = "Thumbnail image"
contactDetails.selfLargeImage = "Large image"
contactDetails.selfBio = "Bio"
compare(ModelUtils.get(model, 0).displayName, "Display name")
compare(ModelUtils.get(model, 0).alias, "Alias")
compare(ModelUtils.get(model, 0).bio, "Bio")
compare(ModelUtils.get(model, 0).colorHash, "Color hash")
compare(ModelUtils.get(model, 0).colorId, 42)
compare(ModelUtils.get(model, 0).contactRequestState, Constants.ContactRequestState.None)
compare(ModelUtils.get(model, 0).displayName, "Display name")
compare(ModelUtils.get(model, 0).ensName, "@name")
compare(ModelUtils.get(model, 0).isEnsVerified, true)
compare(ModelUtils.get(model, 0).icon, "Icon")
compare(ModelUtils.get(model, 0).isBlocked, false)
compare(ModelUtils.get(model, 0).isContact, false)
compare(ModelUtils.get(model, 0).isContactRequestReceived, false)
compare(ModelUtils.get(model, 0).isContactRequestSent, false)
compare(ModelUtils.get(model, 0).isCurrentUser, true)
compare(ModelUtils.get(model, 0).isUntrustworthy, false)
compare(ModelUtils.get(model, 0).isVerified, false)
compare(ModelUtils.get(model, 0).largeImage, "Large image")
compare(ModelUtils.get(model, 0).lastUpdated, 0)
compare(ModelUtils.get(model, 0).lastUpdatedLocally, 0)
compare(ModelUtils.get(model, 0).localNickname, "")
compare(ModelUtils.get(model, 0).onlineStatus, Constants.onlineStatus.online)
compare(ModelUtils.get(model, 0).preferredDisplayName, "Preferred display name")
compare(ModelUtils.get(model, 0).removed, false)
compare(ModelUtils.get(model, 0).thumbnailImage, "Thumbnail image")
compare(ModelUtils.get(model, 0).trustStatus, Constants.trustStatus.unknown)
}
function test_accessToContacts() {
const contactsModel = createTemporaryObject(contatsModelComponent, root)
const contactDetails = createTemporaryObject(testComponent, root,
{ contactsModel })
const model = contactDetails.allContactsModel
compare(model.rowCount(), 3)
compare(ModelUtils.get(model, 0).pubKey, "0x0000x")
compare(ModelUtils.get(model, 1).pubKey, "0x0001x")
compare(ModelUtils.get(model, 2).pubKey, "0x0002x")
compare(ModelUtils.get(model, 0).displayName, "")
compare(ModelUtils.get(model, 1).displayName, "displayName 1")
compare(ModelUtils.get(model, 2).displayName, "displayName 2")
}
function test_roleNames() {
const contactDetails = createTemporaryObject(testComponent, root)
const model = contactDetails.allContactsModel
const roleNames = ModelUtils.roleNames(model)
verify(roleNames.includes("pubKey"))
verify(roleNames.includes("alias"))
verify(roleNames.includes("bio"))
verify(roleNames.includes("colorHash"))
verify(roleNames.includes("colorId"))
verify(roleNames.includes("contactRequestState"))
verify(roleNames.includes("displayName"))
verify(roleNames.includes("ensName"))
verify(roleNames.includes("isEnsVerified"))
verify(roleNames.includes("icon"))
verify(roleNames.includes("isBlocked"))
verify(roleNames.includes("isContact"))
verify(roleNames.includes("isContactRequestReceived"))
verify(roleNames.includes("isContactRequestSent"))
verify(roleNames.includes("isCurrentUser"))
verify(roleNames.includes("isUntrustworthy"))
verify(roleNames.includes("isVerified"))
verify(roleNames.includes("largeImage"))
verify(roleNames.includes("lastUpdated"))
verify(roleNames.includes("lastUpdatedLocally"))
verify(roleNames.includes("localNickname"))
verify(roleNames.includes("onlineStatus"))
verify(roleNames.includes("preferredDisplayName"))
verify(roleNames.includes("removed"))
verify(roleNames.includes("thumbnailImage"))
verify(roleNames.includes("trustStatus"))
}
}
}

View File

@ -1,320 +0,0 @@
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,
preferredDisplayName: "preferredDisplayName",
lastUpdated: 1234567890,
lastUpdatedLocally: 1234567890,
thumbnailImage: "thumbnailImage",
largeImage: "largeImage",
isContactRequestReceived: false,
isContactRequestSent: 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 preferredDisplayName: "myPreferredDisplayName"
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, false, "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.preferredDisplayName, "preferredDisplayName", "Expected the preferredDisplayName 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.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,
preferredDisplayName: "newPreferredDisplayName",
lastUpdated: 1234567891,
lastUpdatedLocally: 1234567891,
thumbnailImage: "newThumbnailImage",
largeImage: "newLargeImage",
isContactRequestReceived: true,
isContactRequestSent: 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.preferredDisplayName, "newPreferredDisplayName", "Expected the preferredDisplayName 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.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")
}
}
}

View File

@ -1,103 +1,34 @@
import QtQuick 2.15
import QtQml 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
QtObject {
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 string preferredDisplayName: d.contactDetails.preferredDisplayName ?? ""
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 removed: d.contactDetails.isRemoved ?? false
readonly property int trustStatus: d.contactDetails.trustStatus ?? Constants.trustStatus.unknown
readonly property string bio: d.contactDetails.bio ?? ""
property string displayName
property string ensName
property bool ensVerified
property string localNickname
property string alias
property string icon
property int colorId
property var colorHash
property int onlineStatus
property bool isContact
property bool isCurrentUser
property bool isVerified
property bool isUntrustworthy
property bool isBlocked
property int contactRequestState
property string preferredDisplayName
property int lastUpdated
property int lastUpdatedLocally
property string thumbnailImage
property string largeImage
property bool isContactRequestReceived
property bool isContactRequestSent
property bool removed
property int trustStatus
property string bio
// Backwards compatibility properties - Don't use in new code
// TODO: #14965 - Try to remove these properties
readonly property string name: ensName
// 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 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
readonly 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 !== "" && Utils.isValidEns(root.profileStore.name)
readonly property string localNickname: ""
readonly property string preferredDisplayName: root.profileStore.preferredDisplayName
readonly property string name: preferredDisplayName
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 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 removed: false
readonly property int trustStatus: Constants.trustStatus.unknown
readonly property string bio: root.profileStore.bio
}
readonly property var contactDetails: !isMe ? itemData.item : ownProfile
}
property string name//: ensName
}

View File

@ -0,0 +1,57 @@
import StatusQ 0.1
import StatusQ.Core.Utils 0.1
import utils 1.0
/**
* Wrapper over generic ModelEntry to expose entries from model of contacts.
*/
QObject {
id: root
required property string publicKey
required property var contactsModel
readonly property ContactDetails contactDetails: ContactDetails {
readonly property var entry: itemData.item
publicKey: root.publicKey
displayName: entry.displayName ?? ""
ensName: entry.ensName ?? ""
ensVerified: entry.isEnsVerified ?? false
localNickname: entry.localNickname ?? ""
alias: entry.alias ?? ""
icon: entry.icon ?? ""
colorId: entry.colorId ?? 0
colorHash: entry.colorHash ?? []
onlineStatus: entry.onlineStatus ?? Constants.onlineStatus.inactive
isContact: entry.isContact ?? false
isCurrentUser: entry.isCurrentUser ?? false
isVerified: entry.isVerified ?? false
isUntrustworthy: entry.isUntrustworthy ?? false
isBlocked: entry.isBlocked ?? false
contactRequestState: entry.contactRequest ?? Constants.ContactRequestState.None
preferredDisplayName: entry.preferredDisplayName ?? ""
lastUpdated: entry.lastUpdated ?? 0
lastUpdatedLocally: entry.lastUpdatedLocally ?? 0
thumbnailImage: entry.thumbnailImage ?? ""
largeImage: entry.largeImage ?? ""
isContactRequestReceived: entry.isContactRequestReceived ?? false
isContactRequestSent: entry.isContactRequestSent ?? false
removed: entry.isRemoved ?? false
trustStatus: entry.trustStatus ?? Constants.trustStatus.unknown
bio: entry.bio ?? ""
// Backwards compatibility properties - Don't use in new code
// TODO: #14965 - Try to remove these properties
name: ensName
}
ModelEntry {
id: itemData
sourceModel: root.contactsModel
key: "pubKey"
value: root.publicKey
cacheOnRemoval: true
}
}

View File

@ -1,4 +1,5 @@
ContactDetails 1.0 ContactDetails.qml
ContactModelEntry 1.0 ContactModelEntry.qml
ProfileShowcaseDirtyState 1.0 ProfileShowcaseDirtyState.qml
ProfileShowcaseModelAdapter 1.0 ProfileShowcaseModelAdapter.qml
ProfileShowcaseModels 1.0 ProfileShowcaseModels.qml

View File

@ -49,12 +49,6 @@ SettingsContentBase {
property bool toastClashesWithDirtyBubble
readonly property alias sideBySidePreviewComponent: myProfilePreviewComponent
readonly property QtObject liveValues: QtObject {
readonly property string displayName: descriptionPanel.displayName.text
readonly property string bio: descriptionPanel.bio.text
readonly property url profileLargeImage: profileHeader.previewIcon
}
enum TabIndex {
Identity = 0,
Communities = 1,
@ -133,6 +127,17 @@ SettingsContentBase {
property QObject priv: QObject {
id: priv
readonly property ContactDetails liveContactDetails: ContactDetails {
publicKey: root.profileStore.pubkey
colorId: root.profileStore.colorId
colorHash: root.profileStore.colorHash
onlineStatus: root.profileStore.currentUserStatus
displayName: descriptionPanel.displayName.text
bio: descriptionPanel.bio.text
largeImage: profileHeader.previewIcon
}
readonly property bool hasAnyProfileShowcaseChanges: showcaseModels.dirty
readonly property bool isIdentityTabDirty: (!descriptionPanel.isEnsName &&
descriptionPanel.displayName.text !== profileStore.displayName) ||
@ -403,16 +408,16 @@ SettingsContentBase {
Component {
id: profilePreview
ProfileDialog {
publicKey: root.contactsStore.myPublicKey
contactDetails: priv.liveContactDetails
profileStore: root.profileStore
contactsStore: root.contactsStore
walletStore: WalletStores.RootStore
utilsStore: root.utilsStore
sendToAccountEnabled: root.sendToAccountEnabled
onClosed: destroy()
dirtyValues: root.liveValues
dirty: root.dirty
showcaseCommunitiesModel: priv.showcaseModels.communitiesVisibleModel
showcaseAccountsModel: priv.showcaseModels.accountsVisibleModel
@ -427,13 +432,14 @@ SettingsContentBase {
Component {
id: myProfilePreviewComponent
MyProfilePreview {
contactDetails: priv.liveContactDetails
profileStore: root.profileStore
contactsStore: root.contactsStore
utilsStore: root.utilsStore
sendToAccountEnabled: root.sendToAccountEnabled
dirtyValues: root.liveValues
dirty: root.dirty
showcaseCommunitiesModel: priv.showcaseModels.communitiesVisibleModel
showcaseAccountsModel: priv.showcaseModels.accountsVisibleModel

View File

@ -9,13 +9,13 @@ import shared.controls 1.0
import shared.views 1.0 as SharedViews
Item {
property alias contactDetails: profilePreview.contactDetails
property alias profileStore: profilePreview.profileStore
property alias contactsStore: profilePreview.contactsStore
property alias utilsStore: profilePreview.utilsStore
property alias sendToAccountEnabled: profilePreview.sendToAccountEnabled
property alias dirtyValues: profilePreview.dirtyValues
property alias dirty: profilePreview.dirty
property alias showcaseCommunitiesModel: profilePreview.showcaseCommunitiesModel
property alias showcaseAccountsModel: profilePreview.showcaseAccountsModel

View File

@ -105,6 +105,25 @@ Item {
// set from main.qml
property var sysPalette
AllContactsAdaptor {
id: allContacsAdaptor
contactsModel: appMain.rootStore.contactStore.contactsModel
selfPubKey: appMain.profileStore.pubkey
selfDisplayName : appMain.profileStore.displayName
selfName: appMain.profileStore.name
selfPreferredDisplayName: appMain.profileStore.preferredName
selfAlias: appMain.profileStore.username
selfIcon: appMain.profileStore.icon
selfColorId: appMain.profileStore.colorId
selfColorHash: appMain.profileStore.colorHash
selfOnlineStatus: appMain.profileStore.currentUserStatus
selfThumbnailImage: appMain.profileStore.thumbnailImage
selfLargeImage: appMain.profileStore.largeImage
selfBio: appMain.profileStore.bio
}
ContactsModelAdaptor {
id: contactsModelAdaptor
@ -601,6 +620,7 @@ Item {
buyCryptoStore: appMain.buyCryptoStore
networkConnectionStore: appMain.networkConnectionStore
allContactsModel: allContacsAdaptor.allContactsModel
mutualContactsModel: contactsModelAdaptor.mutualContacts
isDevBuild: !production

View File

@ -23,6 +23,7 @@ import AppLayouts.Wallet.popups.swap 1.0
import AppLayouts.Wallet.popups.buy 1.0
import AppLayouts.Wallet.popups 1.0
import AppLayouts.Communities.stores 1.0
import AppLayouts.Profile.helpers 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStores
import AppLayouts.Chat.stores 1.0 as ChatStores
@ -53,6 +54,7 @@ QtObject {
property NetworkConnectionStore networkConnectionStore
property WalletStores.BuyCryptoStore buyCryptoStore
property var allContactsModel
property var mutualContactsModel
property bool isDevBuild
@ -548,7 +550,16 @@ QtObject {
ProfileDialog {
id: profilePopup
property bool isCurrentUser: publicKey === rootStore.profileSectionStore.profileStore.pubkey
property alias publicKey: contactModelEntry.publicKey
readonly property bool isCurrentUser: contactDetails.isCurrentUser
ContactModelEntry {
id: contactModelEntry
contactsModel: root.allContactsModel
}
contactDetails: contactModelEntry.contactDetails
profileStore: rootStore.profileSectionStore.profileStore
contactsStore: rootStore.profileSectionStore.contactsStore
@ -557,10 +568,14 @@ QtObject {
sendToAccountEnabled: root.networkConnectionStore.sendBuyBridgeEnabled
showcaseCommunitiesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCommunitiesModel : rootStore.profileSectionStore.contactShowcaseCommunitiesModel
showcaseAccountsModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseAccountsModel : rootStore.profileSectionStore.contactShowcaseAccountsModel
showcaseCollectiblesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCollectiblesModel : rootStore.profileSectionStore.contactShowcaseCollectiblesModel
showcaseSocialLinksModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseSocialLinksModel : rootStore.profileSectionStore.contactShowcaseSocialLinksModel
showcaseCommunitiesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCommunitiesModel
: rootStore.profileSectionStore.contactShowcaseCommunitiesModel
showcaseAccountsModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseAccountsModel
: rootStore.profileSectionStore.contactShowcaseAccountsModel
showcaseCollectiblesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCollectiblesModel
: rootStore.profileSectionStore.contactShowcaseCollectiblesModel
showcaseSocialLinksModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseSocialLinksModel
: rootStore.profileSectionStore.contactShowcaseSocialLinksModel
assetsModel: rootStore.globalAssetsModel
collectiblesModel: rootStore.globalCollectiblesModel

View File

@ -0,0 +1,97 @@
import QtQuick 2.15
import StatusQ 0.1
import StatusQ.Core.Utils 0.1
import utils 1.0
import SortFilterProxyModel 0.2
/**
* Adaptor concatenating model of contacts with own profile details into single
model in order to use it as a complete source of profile info, with no
distinction between own and contat's profiles.
*/
QObject {
id: root
/* Model with details (not including self) */
property alias contactsModel: mainSource.model
/* Self-profile details */
property string selfPubKey
property string selfDisplayName
property string selfName
property string selfPreferredDisplayName
property string selfAlias
property string selfIcon
property int selfColorId
property var selfColorHash
property int selfOnlineStatus
property string selfThumbnailImage
property string selfLargeImage
property string selfBio
readonly property ConcatModel allContactsModel: ConcatModel {
id: concatModel
expectedRoles: [
"pubKey", "displayName", "ensName", "isEnsVerified", "localNickname",
"alias", "icon", "colorId", "colorHash", "onlineStatus",
"isContact", "isCurrentUser", "isVerified", "isUntrustworthy",
"isBlocked", "contactRequestState", "preferredDisplayName",
"lastUpdated", "lastUpdatedLocally", "thumbnailImage", "largeImage",
"isContactRequestReceived", "isContactRequestSent", "removed",
"trustStatus", "bio"
]
markerRoleName: ""
sources: [
SourceModel {
model: ObjectProxyModel {
sourceModel: ListModel {
ListElement {
_: "" // empty role to prevent warning
}
}
delegate: QtObject {
readonly property string pubKey: root.selfPubKey
readonly property string displayName: root.selfDisplayName
readonly property string ensName: root.selfName
readonly property bool isEnsVerified: root.selfName !== ""
&& Utils.isValidEns(root.selfName)
readonly property string localNickname: ""
readonly property string preferredDisplayName: root.selfPreferredDisplayName
readonly property string name: preferredDisplayName
readonly property string alias: root.selfAlias
readonly property string icon: root.selfIcon
readonly property int colorId: root.selfColorId
readonly property var colorHash: root.selfColorHash
readonly property int onlineStatus: root.selfOnlineStatus
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 lastUpdated: 0
readonly property int lastUpdatedLocally: 0
readonly property string thumbnailImage: root.selfThumbnailImage
readonly property string largeImage: root.selfLargeImage
readonly property bool isContactRequestReceived: Constants.ContactRequestState.None
readonly property bool isContactRequestSent: Constants.ContactRequestState.None
readonly property bool removed: false
readonly property int trustStatus: Constants.trustStatus.unknown
readonly property string bio: root.selfBio
}
exposedRoles: concatModel.expectedRoles
}
},
SourceModel {
id: mainSource
}
]
}
}

View File

@ -1 +1,2 @@
AllContactsAdaptor 1.0 AllContactsAdaptor.qml
ContactsModelAdaptor 1.0 ContactsModelAdaptor.qml

View File

@ -1,4 +1,4 @@
import QtQuick 2.14
import QtQuick 2.15
import QtQuick.Controls 2.15
import StatusQ.Popups.Dialog 0.1
@ -11,7 +11,7 @@ StatusDialog {
property var parentPopup
property alias publicKey: profileView.publicKey
property alias contactDetails: profileView.contactDetails
property alias profileStore: profileView.profileStore
property alias contactsStore: profileView.contactsStore
@ -29,9 +29,6 @@ StatusDialog {
property alias assetsModel: profileView.assetsModel
property alias collectiblesModel: profileView.collectiblesModel
property alias dirtyValues: profileView.dirtyValues
property alias dirty: profileView.dirty
implicitHeight: implicitContentHeight + (header.visible ? header.height : 0)
width: 640
padding: 0

View File

@ -30,9 +30,10 @@ import AppLayouts.Wallet.stores 1.0 as WalletStores
Pane {
id: root
required property ContactDetails contactDetails
property bool readOnly // inside settings/profile/preview
property string publicKey: contactsStore.myPublicKey
readonly property string publicKey: contactDetails.publicKey
readonly property alias isCurrentUser: d.isCurrentUser
property ProfileStores.ProfileStore profileStore
@ -42,9 +43,6 @@ Pane {
property alias sendToAccountEnabled: showcaseView.sendToAccountEnabled
property var dirtyValues: ({})
property bool dirty: false
property var showcaseCommunitiesModel
property var showcaseAccountsModel
property var showcaseCollectiblesModel
@ -65,17 +63,10 @@ Pane {
id: background
}
ContactDetails {
id: contactDetails
publicKey: root.publicKey
contactsStore: root.contactsStore
profileStore: root.profileStore
}
QtObject {
id: d
readonly property bool isCurrentUser: root.profileStore.pubkey === root.publicKey
readonly property bool isCurrentUser: contactDetails.isCurrentUser
readonly property string userDisplayName: contactDetails.displayName
readonly property string userNickName: contactDetails.localNickname
readonly property string prettyEnsName: contactDetails.name
@ -225,10 +216,8 @@ Pane {
id: userImage
Layout.alignment: Qt.AlignTop
objectName: "ProfileDialog_userImage"
name: root.dirty ? root.dirtyValues.displayName
: d.mainDisplayName
image: root.dirty ? root.dirtyValues.profileLargeImage
: Utils.addTimestampToURL(contactDetails.largeImage)
name: d.mainDisplayName
image: Utils.addTimestampToURL(contactDetails.largeImage)
colorId: contactDetails.colorId
colorHash: contactDetails.colorHash
@ -399,7 +388,7 @@ Pane {
font.bold: true
font.pixelSize: 22
elide: Text.ElideRight
text: StatusQUtils.Emoji.parse(root.dirty ? root.dirtyValues.displayName : d.mainDisplayName, StatusQUtils.Emoji.size.middle)
text: StatusQUtils.Emoji.parse(d.mainDisplayName, StatusQUtils.Emoji.size.middle)
}
StatusContactVerificationIcons {
id: verificationIcons
@ -465,7 +454,7 @@ Pane {
id: bioText
width: bioScrollView.availableWidth
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: root.dirty ? root.dirtyValues.bio.trim() : contactDetails.bio.trim()
text: contactDetails.bio.trim()
}
}
EmojiHash {
@ -527,8 +516,7 @@ Pane {
Layout.preferredHeight: 300
currentTabIndex: showcaseTabBar.currentIndex
mainDisplayName: root.dirty ? root.dirtyValues.displayName
: d.mainDisplayName
mainDisplayName: d.mainDisplayName
readOnly: root.readOnly
communitiesModel: root.showcaseCommunitiesModel