From 9315dd26e0b21f0124111461ba7294b365df2b8e Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Tue, 29 Oct 2024 15:48:59 -0400 Subject: [PATCH] refactor(contacts): refactor 5 contact models into one and filter in QML Fixes #16549 Refactors the 5 types of contact models (all, mutuals, banned, received and sent) into only the `allContacts` and use an Adaptor on the QML side to filter into the needed models. This cleans the Nim side a lot and makes applying updates to the contacts' model way simpler. rthh --- .../main/profile_section/contacts/module.nim | 57 ++------- .../main/profile_section/contacts/view.nim | 114 +----------------- src/app/modules/shared_models/user_model.nim | 14 ++- .../Profile/stores/ContactsModelAdaptor.qml | 81 +++++++++++++ .../Profile/stores/ContactsStore.qml | 21 ++-- 5 files changed, 114 insertions(+), 173 deletions(-) create mode 100644 ui/app/AppLayouts/Profile/stores/ContactsModelAdaptor.qml diff --git a/src/app/modules/main/profile_section/contacts/module.nim b/src/app/modules/main/profile_section/contacts/module.nim index b3c477d52f..3af653d9fa 100644 --- a/src/app/modules/main/profile_section/contacts/module.nim +++ b/src/app/modules/main/profile_section/contacts/module.nim @@ -105,8 +105,7 @@ proc buildModel(self: Module, model: Model, group: ContactsGroup) = var items: seq[UserItem] let contacts = self.controller.getContacts(group) for c in contacts: - let item = self.createItemFromPublicKey(c.id) - items.add(item) + items.add(self.createItemFromPublicKey(c.id)) model.addItems(items) @@ -123,13 +122,6 @@ method viewDidLoad*(self: Module) = method onContactsLoaded*(self: Module) = self.buildModel(self.view.contactsModel(), ContactsGroup.AllKnownContacts) - self.buildModel(self.view.myMutualContactsModel(), ContactsGroup.MyMutualContacts) - self.buildModel(self.view.blockedContactsModel(), ContactsGroup.BlockedContacts) - self.buildModel(self.view.receivedContactRequestsModel(), ContactsGroup.IncomingPendingContactRequests) - self.buildModel(self.view.sentContactRequestsModel(), ContactsGroup.OutgoingPendingContactRequests) - # Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections. - # self.buildModel(self.view.receivedButRejectedContactRequestsModel(), ContactsGroup.IncomingRejectedContactRequests) - # self.buildModel(self.view.sentButRejectedContactRequestsModel(), ContactsGroup.IncomingRejectedContactRequests) method getModuleAsVariant*(self: Module): QVariant = return self.viewVariant @@ -169,35 +161,15 @@ method removeContact*(self: Module, publicKey: string) = method changeContactNickname*(self: Module, publicKey: string, nickname: string) = self.controller.changeContactNickname(publicKey, nickname) +# TODO rename this function proc addItemToAppropriateModel(self: Module, item: UserItem) = - if(singletonInstance.userProfile.getPubKey() == item.pubKey): + if singletonInstance.userProfile.getPubKey() == item.pubKey: return - let contact = self.controller.getContact(item.pubKey()) self.view.contactsModel().addItem(item) - if contact.isBlocked(): - self.view.blockedContactsModel().addItem(item) - return - - case contact.contactRequestState: - of ContactRequestState.Received: - self.view.receivedContactRequestsModel().addItem(item) - of ContactRequestState.Sent: - self.view.sentContactRequestsModel().addItem(item) - of ContactRequestState.Mutual: - self.view.myMutualContactsModel().addItem(item) - else: - return proc removeItemWithPubKeyFromAllModels(self: Module, publicKey: string) = self.view.contactsModel().removeItemById(publicKey) - self.view.myMutualContactsModel().removeItemById(publicKey) - self.view.receivedContactRequestsModel().removeItemById(publicKey) - self.view.sentContactRequestsModel().removeItemById(publicKey) - # Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections. - # self.view.receivedButRejectedContactRequestsModel().removeItemById(publicKey) - # self.view.sentButRejectedContactRequestsModel().removeItemById(publicKey) - self.view.blockedContactsModel().removeItemById(publicKey) proc removeIfExistsAndAddToAppropriateModel(self: Module, publicKey: string) = self.removeItemWithPubKeyFromAllModels(publicKey) @@ -221,29 +193,20 @@ method contactUpdated*(self: Module, publicKey: string) = method contactsStatusUpdated*(self: Module, statusUpdates: seq[StatusUpdateDto]) = for s in statusUpdates: - let status = toOnlineStatus(s.statusType) - self.view.myMutualContactsModel().setOnlineStatus(s.publicKey, status) - self.view.contactsModel().setOnlineStatus(s.publicKey, status) + self.view.contactsModel().setOnlineStatus(s.publicKey, toOnlineStatus(s.statusType)) method contactNicknameChanged*(self: Module, publicKey: string) = let contactDetails = self.controller.getContactDetails(publicKey) - let displayName = contactDetails.dto.displayName - let ensName = contactDetails.dto.name - let localNickname = contactDetails.dto.localNickname - self.view.contactsModel().setName(publicKey, displayName, ensName, localNickname) - self.view.myMutualContactsModel().setName(publicKey, displayName, ensName, localNickname) - self.view.receivedContactRequestsModel().setName(publicKey, displayName, ensName, localNickname) - self.view.sentContactRequestsModel().setName(publicKey, displayName, ensName, localNickname) - # Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections. - # self.view.receivedButRejectedContactRequestsModel().setName(publicKey, displayName, ensName, localNickname) - # self.view.sentButRejectedContactRequestsModel().setName(publicKey, displayName, ensName, localNickname) - self.view.blockedContactsModel().setName(publicKey, displayName, ensName, localNickname) + self.view.contactsModel().setName( + publicKey, + contactDetails.dto.displayName, + contactDetails.dto.name, + contactDetails.dto.localNickname, + ) method contactTrustStatusChanged*(self: Module, publicKey: string, trustStatus: TrustStatus) = self.view.contactsModel().updateTrustStatus(publicKey, trustStatus) - self.view.myMutualContactsModel().updateTrustStatus(publicKey, trustStatus) - self.view.blockedContactsModel().updateTrustStatus(publicKey, trustStatus) method markAsTrusted*(self: Module, publicKey: string): void = self.controller.markAsTrusted(publicKey) diff --git a/src/app/modules/main/profile_section/contacts/view.nim b/src/app/modules/main/profile_section/contacts/view.nim index 0752e5a4b1..09c8c7fd74 100644 --- a/src/app/modules/main/profile_section/contacts/view.nim +++ b/src/app/modules/main/profile_section/contacts/view.nim @@ -1,6 +1,6 @@ import NimQml -import ../../../shared_models/user_model +import ../../../shared_models/[user_model, user_item] import ./io_interface import models/showcase_contact_generic_model @@ -13,19 +13,6 @@ QtObject: delegate: io_interface.AccessInterface contactsModel: Model contactsModelVariant: QVariant - myMutualContactsModel: Model - myMutualContactsModelVariant: QVariant - blockedContactsModel: Model - blockedContactsModelVariant: QVariant - receivedContactRequestsModel: Model - receivedContactRequestsModelVariant: QVariant - sentContactRequestsModel: Model - sentContactRequestsModelVariant: QVariant - # Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections. - # receivedButRejectedContactRequestsModel: Model - # receivedButRejectedContactRequestsModelVariant: QVariant - # sentButRejectedContactRequestsModel: Model - # sentButRejectedContactRequestsModelVariant: QVariant showcaseContactCommunitiesModel: ShowcaseContactGenericModel showcaseContactCommunitiesModelVariant: QVariant showcaseContactAccountsModel: ShowcaseContactAccountModel @@ -41,19 +28,6 @@ QtObject: proc delete*(self: View) = self.contactsModel.delete self.contactsModelVariant.delete - self.myMutualContactsModel.delete - self.myMutualContactsModelVariant.delete - self.blockedContactsModel.delete - self.blockedContactsModelVariant.delete - self.receivedContactRequestsModel.delete - self.receivedContactRequestsModelVariant.delete - self.sentContactRequestsModel.delete - self.sentContactRequestsModelVariant.delete - # Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections. - # self.receivedButRejectedContactRequestsModel.delete - # self.receivedButRejectedContactRequestsModelVariant.delete - # self.sentButRejectedContactRequestsModelVariant.delete - # self.sentButRejectedContactRequestsModel.delete self.showcaseContactCommunitiesModel.delete self.showcaseContactCommunitiesModelVariant.delete self.showcaseContactAccountsModel.delete @@ -72,19 +46,6 @@ QtObject: result.delegate = delegate result.contactsModel = newModel() result.contactsModelVariant = newQVariant(result.contactsModel) - result.myMutualContactsModel = newModel() - result.myMutualContactsModelVariant = newQVariant(result.myMutualContactsModel) - result.blockedContactsModel = newModel() - result.blockedContactsModelVariant = newQVariant(result.blockedContactsModel) - result.receivedContactRequestsModel = newModel() - result.receivedContactRequestsModelVariant = newQVariant(result.receivedContactRequestsModel) - result.sentContactRequestsModel = newModel() - result.sentContactRequestsModelVariant = newQVariant(result.sentContactRequestsModel) - # Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections. - # result.receivedButRejectedContactRequestsModel = newModel() - # result.receivedButRejectedContactRequestsModelVariant = newQVariant(result.receivedButRejectedContactRequestsModel) - # result.sentButRejectedContactRequestsModel = newModel() - # result.sentButRejectedContactRequestsModelVariant = newQVariant(result.sentButRejectedContactRequestsModel) result.showcaseContactCommunitiesModel = newShowcaseContactGenericModel() result.showcaseContactCommunitiesModelVariant = newQVariant(result.showcaseContactCommunitiesModel) result.showcaseContactAccountsModel = newShowcaseContactAccountModel() @@ -102,25 +63,6 @@ QtObject: proc contactsModel*(self: View): Model = return self.contactsModel - proc myMutualContactsModel*(self: View): Model = - return self.myMutualContactsModel - - proc blockedContactsModel*(self: View): Model = - return self.blockedContactsModel - - proc receivedContactRequestsModel*(self: View): Model = - return self.receivedContactRequestsModel - - proc sentContactRequestsModel*(self: View): Model = - return self.sentContactRequestsModel - - # Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections. - # proc receivedButRejectedContactRequestsModel*(self: View): Model = - # return self.receivedButRejectedContactRequestsModel - - # proc sentButRejectedContactRequestsModel*(self: View): Model = - # return self.sentButRejectedContactRequestsModel - proc contactsModelChanged(self: View) {.signal.} proc getContactsModel(self: View): QVariant {.slot.} = return self.contactsModelVariant @@ -128,59 +70,13 @@ QtObject: read = getContactsModel notify = contactsModelChanged - proc myMutualContactsModelChanged(self: View) {.signal.} - proc getMyMutualContactsModel(self: View): QVariant {.slot.} = - return self.myMutualContactsModelVariant - QtProperty[QVariant] myMutualContactsModel: - read = getMyMutualContactsModel - notify = myMutualContactsModelChanged - - proc blockedContactsModelChanged(self: View) {.signal.} - proc getBlockedContactsModel(self: View): QVariant {.slot.} = - return self.blockedContactsModelVariant - QtProperty[QVariant] blockedContactsModel: - read = getBlockedContactsModel - notify = blockedContactsModelChanged - - proc receivedContactRequestsModelChanged(self: View) {.signal.} - proc getReceivedContactRequestsModel(self: View): QVariant {.slot.} = - return self.receivedContactRequestsModelVariant - QtProperty[QVariant] receivedContactRequestsModel: - read = getReceivedContactRequestsModel - notify = receivedContactRequestsModelChanged - - proc sentContactRequestsModelChanged(self: View) {.signal.} - proc getSentContactRequestsModel(self: View): QVariant {.slot.} = - return self.sentContactRequestsModelVariant - QtProperty[QVariant] sentContactRequestsModel: - read = getSentContactRequestsModel - notify = sentContactRequestsModelChanged - proc contactInfoRequestFinished(self: View, publicKey: string, ok: bool) {.signal.} - # Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections. - # proc receivedButRejectedContactRequestsModelChanged(self: View) {.signal.} - # proc getReceivedButRejectedContactRequestsModel(self: View): QVariant {.slot.} = - # return self.receivedButRejectedContactRequestsModelVariant - # QtProperty[QVariant] receivedButRejectedContactRequestsModel: - # read = getReceivedButRejectedContactRequestsModel - # notify = receivedButRejectedContactRequestsModelChanged - - # proc sentButRejectedContactRequestsModelChanged(self: View) {.signal.} - # proc getSentButRejectedContactRequestsModel(self: View): QVariant {.slot.} = - # return self.sentButRejectedContactRequestsModelVariant - # QtProperty[QVariant] sentButRejectedContactRequestsModel: - # read = getSentButRejectedContactRequestsModel - # notify = sentButRejectedContactRequestsModelChanged - - proc isMyMutualContact*(self: View, publicKey: string): bool {.slot.} = - return self.myMutualContactsModel.isContactWithIdAdded(publicKey) - - proc isBlockedContact*(self: View, publicKey: string): bool {.slot.} = - return self.blockedContactsModel.isContactWithIdAdded(publicKey) - proc hasPendingContactRequest*(self: View, publicKey: string): bool {.slot.} = - return self.sentContactRequestsModel.isContactWithIdAdded(publicKey) + if not self.contactsModel.isContactWithIdAdded(publicKey): + return false + let userItem = self.contactsModel.getItemByPubKey(publicKey) + return userItem.contactRequest == ContactRequest.Sent proc sendContactRequest*(self: View, publicKey: string, message: string) {.slot.} = self.delegate.sendContactRequest(publicKey, message) diff --git a/src/app/modules/shared_models/user_model.nim b/src/app/modules/shared_models/user_model.nim index 8c1c3a3b65..6a09998e30 100644 --- a/src/app/modules/shared_models/user_model.nim +++ b/src/app/modules/shared_models/user_model.nim @@ -165,8 +165,10 @@ QtObject: of ModelRole.IsCurrentUser: result = newQVariant(item.isCurrentUser) of ModelRole.DefaultDisplayName: + # TODO this is the same as preferred name result = newQVariant(item.defaultDisplayName) of ModelRole.OptionalName: + # This seems useless result = newQVariant(item.optionalName) of ModelRole.LastUpdated: result = newQVariant(item.lastUpdated) @@ -183,6 +185,7 @@ QtObject: of ModelRole.IsContactRequestSent: result = newQVariant(item.isContactRequestSent) of ModelRole.IsSyncing: + # TODO not sure what that is and it's never used result = newQVariant(item.isSyncing) of ModelRole.IsRemoved: result = newQVariant(item.isRemoved) @@ -237,11 +240,16 @@ QtObject: proc findIndexByPubKey(self: Model, pubKey: string): int = for i in 0 ..< self.items.len: - if(self.items[i].pubKey == pubKey): + if self.items[i].pubKey == pubKey: return i return -1 + proc getItemByPubKey*(self: Model, pubKey: string): UserItem = + for item in self.items: + if item.pubKey == pubKey: + return item + proc removeItemWithIndex(self: Model, index: int) = let parentModelIndex = newQModelIndex() defer: parentModelIndex.delete @@ -254,7 +262,6 @@ QtObject: self.itemChanged(pubKey) -# TODO: rename to `containsItem` proc isContactWithIdAdded*(self: Model, id: string): bool = return self.findIndexByPubKey(id) != -1 @@ -384,6 +391,3 @@ QtObject: # TODO: rename me to getItemsAsPubkeys proc getItemIds*(self: Model): seq[string] = return self.items.map(i => i.pubKey) - - proc containsItemWithPubKey*(self: Model, pubKey: string): bool = - return self.findIndexByPubKey(pubKey) != -1 diff --git a/ui/app/AppLayouts/Profile/stores/ContactsModelAdaptor.qml b/ui/app/AppLayouts/Profile/stores/ContactsModelAdaptor.qml new file mode 100644 index 0000000000..5be2c2a488 --- /dev/null +++ b/ui/app/AppLayouts/Profile/stores/ContactsModelAdaptor.qml @@ -0,0 +1,81 @@ +import QtQml 2.15 + +import StatusQ 0.1 +import StatusQ.Models 0.1 +import StatusQ.Core.Utils 0.1 + +import utils 1.0 + +import SortFilterProxyModel 0.2 + +QObject { + id: root + + /** + Expected model structure: + + pubKey [string] - unique identifier of a member, e.g "0x3234235" + displayName [string] - member's chosen name + preferredDisplayName [string] - calculated member name according to priorities (eg: nickname has higher priority) + ensName [string] - member's ENS name + isEnsVerified [bool] - whether the ENS name was verified on chain + localNickname [string] - local nickname set by the current user + alias [string] - generated 3 word name + icon [string] - thumbnail image of the user + colorId [string] - generated color ID for the user's profile + colorHash [string] - generated color hash for the user's profile + onlineStatus [int] - the online status of the member + isContact [bool] - whether the user is a mutual contact or not + isVerified [bool] - wheter the user has been marked as verified or not + isUntrustworthy [bool] - wheter the user has been marked as untrustworthy or not + isBlocked [bool] - whether the user has been blocked or not + contactRequest [int] - state of the contact request that was sent + isCurrentUser [bool] - whether the contact is actually ourselves + lastUpdated [int64] - clock of when last the contact was updated + lastUpdatedLocally [int64] - clock of when last the contact was updated locally + bio [string] - contacts's chosen bio text + thumbnailImage [string] - local url of the user's thumbnail image + largeImage [string] - local url of the user's large image + isContactRequestReceived [bool] - whether we received a contact request from that user + isContactRequestSent [bool] - whether we send a contact request to that user + isRemoved [bool] - whether we removed that contact + trustStatus [int] - the trust status of the user as an enum + **/ + property var allContacts + + readonly property var mutualContacts: SortFilterProxyModel { + sourceModel: root.allContacts ?? null + + filters: ValueFilter { + roleName: "isContact" + value: true + } + } + + readonly property var blockedContacts: SortFilterProxyModel { + sourceModel: root.allContacts ?? null + + filters: ValueFilter { + roleName: "isBlocked" + value: true + } + } + + readonly property var pendingReceivedRequestContacts: SortFilterProxyModel { + sourceModel: root.allContacts ?? null + + filters: ValueFilter { + roleName: "contactRequest" + value: Constants.ContactRequestState.Received + } + } + + readonly property var pendingSentRequestContacts: SortFilterProxyModel { + sourceModel: root.allContacts ?? null + + filters: ValueFilter { + roleName: "contactRequest" + value: Constants.ContactRequestState.Sent + } + } +} diff --git a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml index 15e2d46ebe..1592fdd68f 100644 --- a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml @@ -15,10 +15,15 @@ QtObject { // contactsModel holds all available contacts property var contactsModel: contactsModule.contactsModel - property var myContactsModel: contactsModule.myMutualContactsModel - property var blockedContactsModel: contactsModule.blockedContactsModel - property var receivedContactRequestsModel: contactsModule.receivedContactRequestsModel - property var sentContactRequestsModel: contactsModule.sentContactRequestsModel + + readonly property var contactsModelAdaptor: ContactsModelAdaptor { + allContacts: contactsModel + } + + property var myContactsModel: contactsModelAdaptor.mutualContacts + property var blockedContactsModel: contactsModelAdaptor.blockedContacts + property var receivedContactRequestsModel: contactsModelAdaptor.pendingReceivedRequestContacts + property var sentContactRequestsModel: contactsModelAdaptor.pendingSentRequestContacts readonly property var showcasePublicKey: contactsModule.showcasePublicKey @@ -51,14 +56,6 @@ QtObject { return root.globalUtilsInst.generateAlias(pubKey) } - function isMyMutualContact(pubKey) { - return root.contactsModule.isMyMutualContact(pubKey) - } - - function isBlockedContact(pubKey) { - return root.contactsModule.isBlockedContact(pubKey) - } - function hasPendingContactRequest(pubKey) { return root.contactsModule.hasPendingContactRequest(pubKey) }