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.stores 1.0 as AppLayoutStores
import AppLayouts.Profile.stores 1.0 as ProfileStores import AppLayouts.Profile.stores 1.0 as ProfileStores
import AppLayouts.Profile.helpers 1.0
import AppLayouts.Wallet.stores 1.0 import AppLayouts.Wallet.stores 1.0
import Storybook 1.0 import Storybook 1.0
@ -22,23 +23,17 @@ SplitView {
id: root id: root
property bool globalUtilsReady: false property bool globalUtilsReady: false
property bool mainModuleReady: false
// globalUtilsInst mock // globalUtilsInst mock
QtObject { 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) { function addTimestampToURL(url) {
return url return url
} }
function isCompressedPubKey() {
return false
}
Component.onCompleted: { Component.onCompleted: {
Utils.globalUtilsInst = this Utils.globalUtilsInst = this
root.globalUtilsReady = true 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 { ListModel {
id: linksModel id: linksModel
ListElement { ListElement {
@ -147,144 +103,6 @@ SplitView {
Logs { id: logs } 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 { SplitView {
orientation: Qt.Vertical orientation: Qt.Vertical
SplitView.fillWidth: true SplitView.fillWidth: true
@ -299,15 +117,38 @@ SplitView {
clip: true clip: true
Loader { Loader {
active: root.globalUtilsReady && root.mainModuleReady active: root.globalUtilsReady
width: parent.availableWidth width: parent.availableWidth
height: parent.availableHeight height: parent.availableHeight
sourceComponent: ProfileDialogView { sourceComponent: ProfileDialogView {
implicitWidth: 640 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 readOnly: ctrlReadOnly.checked
publicKey: switchOwnProfile.checked ? "0xdeadbeef" : "0xrandomguy"
onCloseRequested: logs.logEvent("closeRequested()") onCloseRequested: logs.logEvent("closeRequested()")
@ -323,50 +164,38 @@ SplitView {
collectiblesModel: CollectiblesModel {} collectiblesModel: CollectiblesModel {}
profileStore: ProfileStores.ProfileStore { profileStore: ProfileStores.ProfileStore {
readonly property string pubkey: "0xdeadbeef"
readonly property string ensName: name.text
function getQrCodeSource() { function getQrCodeSource() {
return "https://upload.wikimedia.org/wikipedia/commons/4/41/QR_Code_Example.svg" return "https://upload.wikimedia.org/wikipedia/commons/4/41/QR_Code_Example.svg"
} }
} }
contactsStore: ProfileStores.ContactsStore { contactsStore: ProfileStores.ContactsStore {
readonly property string myPublicKey: "0xdeadbeef"
function joinPrivateChat(publicKey) { function joinPrivateChat(publicKey) {
logs.logEvent("contactsStore::joinPrivateChat", ["publicKey"], arguments) logs.logEvent("contactsStore::joinPrivateChat", ["publicKey"], arguments)
} }
function markUntrustworthy(publicKey) { function markUntrustworthy(publicKey) {
logs.logEvent("contactsStore::markUntrustworthy", ["publicKey"], arguments) logs.logEvent("contactsStore::markUntrustworthy", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.untrustworthy)
} }
function removeContact(publicKey) { function removeContact(publicKey) {
logs.logEvent("contactsStore::removeContact", ["publicKey"], arguments) logs.logEvent("contactsStore::removeContact", ["publicKey"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.None)
ctrlIsContact.checked = false
} }
function acceptContactRequest(publicKey, contactRequestId) { function acceptContactRequest(publicKey, contactRequestId) {
logs.logEvent("contactsStore::acceptContactRequest", ["publicKey, contactRequestId"], arguments) logs.logEvent("contactsStore::acceptContactRequest", ["publicKey, contactRequestId"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.Mutual)
} }
function dismissContactRequest(publicKey, contactRequestId) { function dismissContactRequest(publicKey, contactRequestId) {
logs.logEvent("contactsStore::dismissContactRequest", ["publicKey, contactRequestId"], arguments) logs.logEvent("contactsStore::dismissContactRequest", ["publicKey, contactRequestId"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.Dismissed)
} }
function removeTrustStatus(publicKey) { function removeTrustStatus(publicKey) {
logs.logEvent("contactsStore::removeTrustStatus", ["publicKey"], arguments) logs.logEvent("contactsStore::removeTrustStatus", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.unknown)
} }
function removeTrustVerificationStatus(publicKey) { function removeTrustVerificationStatus(publicKey) {
logs.logEvent("contactsStore::removeTrustVerificationStatus", ["publicKey"], arguments) logs.logEvent("contactsStore::removeTrustVerificationStatus", ["publicKey"], arguments)
ctrlTrustStatus.currentIndex = ctrlTrustStatus.indexOfValue(Constants.trustStatus.unknown)
} }
function verifiedUntrustworthy(publicKey) { function verifiedUntrustworthy(publicKey) {
@ -380,8 +209,6 @@ SplitView {
function cancelVerificationRequest(pubKey) { function cancelVerificationRequest(pubKey) {
logs.logEvent("contactsStore::cancelVerificationRequest", ["pubKey"], arguments) logs.logEvent("contactsStore::cancelVerificationRequest", ["pubKey"], arguments)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
ctrlIncomingVerificationStatus.currentIndex = ctrlIncomingVerificationStatus.indexOfValue(Constants.verificationStatus.unverified)
} }
function getLinkToProfile(publicKey) { function getLinkToProfile(publicKey) {
@ -390,7 +217,6 @@ SplitView {
function changeContactNickname(publicKey, newNickname, displayName, isEdit) { function changeContactNickname(publicKey, newNickname, displayName, isEdit) {
logs.logEvent("contactsStore::changeContactNickname", ["publicKey", "newNickname", "displayName", "isEdit"], arguments) logs.logEvent("contactsStore::changeContactNickname", ["publicKey", "newNickname", "displayName", "isEdit"], arguments)
localNickname.text = newNickname
} }
function requestProfileShowcase(publicKey) { function requestProfileShowcase(publicKey) {
@ -431,48 +257,64 @@ SplitView {
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Switch { Switch {
id: switchOwnProfile id: ownProfileSwitch
text: "Own profile" text: "Own profile"
checked: false checked: false
} }
Switch { Switch {
id: ctrlReadOnly id: ctrlReadOnly
text: "Readonly (preview)" text: "Readonly (preview)"
visible: switchOwnProfile.checked visible: ownProfileSwitch.checked
checked: false checked: false
} }
} }
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Label { text: "localNickname:" } Label { text: "localNickname:" }
TextField { TextField {
id: localNickname id: localNicknameTextField
text: "Alex" text: "Alex"
placeholderText: "Local Nickname" placeholderText: "Local Nickname"
} }
Label { text: "displayName:" }
Label {
text: "displayName:"
}
TextField { TextField {
id: displayName id: displayNameTextField
text: "Alex Pella" text: "Alex Pella"
placeholderText: "Display Name" placeholderText: "Display Name"
} }
CheckBox { CheckBox {
id: ensVerified id: ensVerifiedCheckBox
checked: true checked: true
text: "ensVerified" text: "ensVerified"
} }
Label { text: "name:" } Label {
text: "name:"
}
TextField { TextField {
id: name id: ensNameTextField
enabled: ensVerified.checked
text: ensVerified.checked ? "8⃣6⃣.eth" : "" enabled: ensVerifiedCheckBox.checked
text: ensVerifiedCheckBox.checked ? "8⃣6⃣.eth" : ""
placeholderText: "ENS name" placeholderText: "ENS name"
} }
} }
RowLayout { RowLayout {
CheckBox { CheckBox {
id: userImage id: userImageCheckBox
text: "User image" text: "User image"
checked: true checked: true
} }
@ -481,18 +323,25 @@ SplitView {
text: "or" text: "or"
} }
Label { Label {
enabled: !userImage.checked enabled: !userImageCheckBox.checked
text: "colorId" text: "colorId"
} }
SpinBox { SpinBox {
id: colorId id: colorIdSpinBox
enabled: !userImage.checked
enabled: !userImageCheckBox.checked
from: 0 from: 0
to: 11 // Theme.palette.userCustomizationColors.length to: 11 // Theme.palette.userCustomizationColors.length
} }
Label { text: "onlineStatus" }
Label {
text: "onlineStatus"
}
ComboBox { ComboBox {
id: ctrlOnlineStatus id: onlineStatusComboBox
textRole: "text" textRole: "text"
valueRole: "value" valueRole: "value"
model: [ model: [
@ -504,15 +353,19 @@ SplitView {
} }
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
enabled: !switchOwnProfile.checked enabled: !ownProfileSwitch.checked
CheckBox { CheckBox {
id: ctrlIsContact id: ctrlIsContact
enabled: true enabled: true
checked: ctrlContactRequestState.currentValue === Constants.ContactRequestState.Mutual checked: ctrlContactRequestState.currentValue === Constants.ContactRequestState.Mutual
text: "isContact" text: "isContact"
} }
ComboBox { ComboBox {
id: ctrlContactRequestState id: ctrlContactRequestState
textRole: "text" textRole: "text"
valueRole: "value" valueRole: "value"
model: [ model: [
@ -523,9 +376,14 @@ SplitView {
{ value: Constants.ContactRequestState.Dismissed, text: "Dismissed" } { value: Constants.ContactRequestState.Dismissed, text: "Dismissed" }
] ]
} }
Label { text: "trustStatus:" }
Label {
text: "trustStatus:"
}
ComboBox { ComboBox {
id: ctrlTrustStatus id: ctrlTrustStatus
textRole: "text" textRole: "text"
valueRole: "value" valueRole: "value"
model: [ model: [
@ -534,8 +392,10 @@ SplitView {
{ value: Constants.trustStatus.untrustworthy, text: "untrustworthy" } { value: Constants.trustStatus.untrustworthy, text: "untrustworthy" }
] ]
} }
CheckBox { CheckBox {
id: ctrlIsBlocked id: isBlockedCheckBox
text: "isBlocked" 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=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=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 // 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 QtObject {
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 required property string publicKey
property string displayName
readonly property alias loading: d.loading property string ensName
property bool ensVerified
// model properties property string localNickname
readonly property string displayName: d.contactDetails.displayName ?? "" property string alias
readonly property string ensName: d.contactDetails.ensName ?? "" property string icon
readonly property bool ensVerified: d.contactDetails.isEnsVerified ?? false property int colorId
readonly property string localNickname: d.contactDetails.localNickname ?? "" property var colorHash
readonly property string alias: d.contactDetails.alias ?? "" property int onlineStatus
readonly property string icon: d.contactDetails.icon ?? "" property bool isContact
readonly property int colorId: d.contactDetails.colorId ?? 0 property bool isCurrentUser
readonly property var colorHash: d.contactDetails.colorHash ?? [] property bool isVerified
readonly property int onlineStatus: d.contactDetails.onlineStatus ?? Constants.onlineStatus.inactive property bool isUntrustworthy
readonly property bool isContact: d.contactDetails.isContact ?? false property bool isBlocked
readonly property bool isCurrentUser: d.contactDetails.isCurrentUser ?? false property int contactRequestState
readonly property bool isVerified: d.contactDetails.isVerified ?? false property string preferredDisplayName
readonly property bool isUntrustworthy: d.contactDetails.isUntrustworthy ?? false property int lastUpdated
readonly property bool isBlocked: d.contactDetails.isBlocked ?? false property int lastUpdatedLocally
readonly property int contactRequestState: d.contactDetails.contactRequest ?? Constants.ContactRequestState.None property string thumbnailImage
readonly property string preferredDisplayName: d.contactDetails.preferredDisplayName ?? "" property string largeImage
readonly property int lastUpdated: d.contactDetails.lastUpdated ?? 0 property bool isContactRequestReceived
readonly property int lastUpdatedLocally: d.contactDetails.lastUpdatedLocally ?? 0 property bool isContactRequestSent
readonly property string thumbnailImage: d.contactDetails.thumbnailImage ?? "" property bool removed
readonly property string largeImage: d.contactDetails.largeImage ?? "" property int trustStatus
readonly property bool isContactRequestReceived: d.contactDetails.isContactRequestReceived ?? false property string bio
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 ?? ""
// Backwards compatibility properties - Don't use in new code // Backwards compatibility properties - Don't use in new code
// TODO: #14965 - Try to remove these properties // TODO: #14965 - Try to remove these properties
readonly property string name: ensName 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
}
} }

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 ContactDetails 1.0 ContactDetails.qml
ContactModelEntry 1.0 ContactModelEntry.qml
ProfileShowcaseDirtyState 1.0 ProfileShowcaseDirtyState.qml ProfileShowcaseDirtyState 1.0 ProfileShowcaseDirtyState.qml
ProfileShowcaseModelAdapter 1.0 ProfileShowcaseModelAdapter.qml ProfileShowcaseModelAdapter 1.0 ProfileShowcaseModelAdapter.qml
ProfileShowcaseModels 1.0 ProfileShowcaseModels.qml ProfileShowcaseModels 1.0 ProfileShowcaseModels.qml

View File

@ -49,12 +49,6 @@ SettingsContentBase {
property bool toastClashesWithDirtyBubble property bool toastClashesWithDirtyBubble
readonly property alias sideBySidePreviewComponent: myProfilePreviewComponent 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 { enum TabIndex {
Identity = 0, Identity = 0,
Communities = 1, Communities = 1,
@ -133,6 +127,17 @@ SettingsContentBase {
property QObject priv: QObject { property QObject priv: QObject {
id: priv 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 hasAnyProfileShowcaseChanges: showcaseModels.dirty
readonly property bool isIdentityTabDirty: (!descriptionPanel.isEnsName && readonly property bool isIdentityTabDirty: (!descriptionPanel.isEnsName &&
descriptionPanel.displayName.text !== profileStore.displayName) || descriptionPanel.displayName.text !== profileStore.displayName) ||
@ -403,16 +408,16 @@ SettingsContentBase {
Component { Component {
id: profilePreview id: profilePreview
ProfileDialog { ProfileDialog {
publicKey: root.contactsStore.myPublicKey contactDetails: priv.liveContactDetails
profileStore: root.profileStore profileStore: root.profileStore
contactsStore: root.contactsStore contactsStore: root.contactsStore
walletStore: WalletStores.RootStore walletStore: WalletStores.RootStore
utilsStore: root.utilsStore utilsStore: root.utilsStore
sendToAccountEnabled: root.sendToAccountEnabled sendToAccountEnabled: root.sendToAccountEnabled
onClosed: destroy() onClosed: destroy()
dirtyValues: root.liveValues
dirty: root.dirty
showcaseCommunitiesModel: priv.showcaseModels.communitiesVisibleModel showcaseCommunitiesModel: priv.showcaseModels.communitiesVisibleModel
showcaseAccountsModel: priv.showcaseModels.accountsVisibleModel showcaseAccountsModel: priv.showcaseModels.accountsVisibleModel
@ -427,13 +432,14 @@ SettingsContentBase {
Component { Component {
id: myProfilePreviewComponent id: myProfilePreviewComponent
MyProfilePreview { MyProfilePreview {
contactDetails: priv.liveContactDetails
profileStore: root.profileStore profileStore: root.profileStore
contactsStore: root.contactsStore contactsStore: root.contactsStore
utilsStore: root.utilsStore utilsStore: root.utilsStore
sendToAccountEnabled: root.sendToAccountEnabled sendToAccountEnabled: root.sendToAccountEnabled
dirtyValues: root.liveValues
dirty: root.dirty
showcaseCommunitiesModel: priv.showcaseModels.communitiesVisibleModel showcaseCommunitiesModel: priv.showcaseModels.communitiesVisibleModel
showcaseAccountsModel: priv.showcaseModels.accountsVisibleModel showcaseAccountsModel: priv.showcaseModels.accountsVisibleModel

View File

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

View File

@ -105,6 +105,25 @@ Item {
// set from main.qml // set from main.qml
property var sysPalette 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 { ContactsModelAdaptor {
id: contactsModelAdaptor id: contactsModelAdaptor
@ -601,6 +620,7 @@ Item {
buyCryptoStore: appMain.buyCryptoStore buyCryptoStore: appMain.buyCryptoStore
networkConnectionStore: appMain.networkConnectionStore networkConnectionStore: appMain.networkConnectionStore
allContactsModel: allContacsAdaptor.allContactsModel
mutualContactsModel: contactsModelAdaptor.mutualContacts mutualContactsModel: contactsModelAdaptor.mutualContacts
isDevBuild: !production 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.buy 1.0
import AppLayouts.Wallet.popups 1.0 import AppLayouts.Wallet.popups 1.0
import AppLayouts.Communities.stores 1.0 import AppLayouts.Communities.stores 1.0
import AppLayouts.Profile.helpers 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStores import AppLayouts.Wallet.stores 1.0 as WalletStores
import AppLayouts.Chat.stores 1.0 as ChatStores import AppLayouts.Chat.stores 1.0 as ChatStores
@ -53,6 +54,7 @@ QtObject {
property NetworkConnectionStore networkConnectionStore property NetworkConnectionStore networkConnectionStore
property WalletStores.BuyCryptoStore buyCryptoStore property WalletStores.BuyCryptoStore buyCryptoStore
property var allContactsModel
property var mutualContactsModel property var mutualContactsModel
property bool isDevBuild property bool isDevBuild
@ -548,7 +550,16 @@ QtObject {
ProfileDialog { ProfileDialog {
id: profilePopup 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 profileStore: rootStore.profileSectionStore.profileStore
contactsStore: rootStore.profileSectionStore.contactsStore contactsStore: rootStore.profileSectionStore.contactsStore
@ -557,10 +568,14 @@ QtObject {
sendToAccountEnabled: root.networkConnectionStore.sendBuyBridgeEnabled sendToAccountEnabled: root.networkConnectionStore.sendBuyBridgeEnabled
showcaseCommunitiesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCommunitiesModel : rootStore.profileSectionStore.contactShowcaseCommunitiesModel showcaseCommunitiesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCommunitiesModel
showcaseAccountsModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseAccountsModel : rootStore.profileSectionStore.contactShowcaseAccountsModel : rootStore.profileSectionStore.contactShowcaseCommunitiesModel
showcaseCollectiblesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCollectiblesModel : rootStore.profileSectionStore.contactShowcaseCollectiblesModel showcaseAccountsModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseAccountsModel
showcaseSocialLinksModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseSocialLinksModel : rootStore.profileSectionStore.contactShowcaseSocialLinksModel : rootStore.profileSectionStore.contactShowcaseAccountsModel
showcaseCollectiblesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCollectiblesModel
: rootStore.profileSectionStore.contactShowcaseCollectiblesModel
showcaseSocialLinksModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseSocialLinksModel
: rootStore.profileSectionStore.contactShowcaseSocialLinksModel
assetsModel: rootStore.globalAssetsModel assetsModel: rootStore.globalAssetsModel
collectiblesModel: rootStore.globalCollectiblesModel 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 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 QtQuick.Controls 2.15
import StatusQ.Popups.Dialog 0.1 import StatusQ.Popups.Dialog 0.1
@ -11,7 +11,7 @@ StatusDialog {
property var parentPopup property var parentPopup
property alias publicKey: profileView.publicKey property alias contactDetails: profileView.contactDetails
property alias profileStore: profileView.profileStore property alias profileStore: profileView.profileStore
property alias contactsStore: profileView.contactsStore property alias contactsStore: profileView.contactsStore
@ -28,9 +28,6 @@ StatusDialog {
property alias assetsModel: profileView.assetsModel property alias assetsModel: profileView.assetsModel
property alias collectiblesModel: profileView.collectiblesModel property alias collectiblesModel: profileView.collectiblesModel
property alias dirtyValues: profileView.dirtyValues
property alias dirty: profileView.dirty
implicitHeight: implicitContentHeight + (header.visible ? header.height : 0) implicitHeight: implicitContentHeight + (header.visible ? header.height : 0)
width: 640 width: 640

View File

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