From 27ececad637e3f9c1399e0ea7b2bfdc3b41e6bd2 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 1 Nov 2024 10:32:20 -0400 Subject: [PATCH] perf(contacts): make initial contacts fetching async (#16560) * perf(contacts): make initial contacts fetching async Fixes #16509 * fix: don't fetch contact if we don't have it in cache Fixes #16509 * feat: add a visible loading indicator when the chats are not ready yet --- src/app/global/app_sections_config.nim | 2 + .../chat_section/chat_content/controller.nim | 3 - .../chat_content/io_interface.nim | 3 - .../main/chat_section/chat_content/module.nim | 5 +- .../main/chat_section/chat_content/view.nim | 3 - .../main/chat_section/io_interface.nim | 6 - src/app/modules/main/chat_section/module.nim | 14 +- src/app/modules/main/chat_section/view.nim | 25 --- src/app/modules/main/controller.nim | 20 ++- src/app/modules/main/io_interface.nim | 18 +++ src/app/modules/main/module.nim | 86 +++++++--- .../profile_section/contacts/controller.nim | 3 + .../profile_section/contacts/io_interface.nim | 3 + .../main/profile_section/contacts/module.nim | 7 +- .../modules/shared_models/section_item.nim | 4 +- .../service/contacts/async_tasks.nim | 21 ++- src/app_service/service/contacts/service.nim | 152 ++++++++---------- src/backend/contacts.nim | 8 - .../StatusQ/Controls/StatusIconTabButton.qml | 3 +- ui/app/mainui/AppMain.qml | 2 +- ui/imports/utils/Constants.qml | 1 + ui/imports/utils/Utils.qml | 2 + 22 files changed, 204 insertions(+), 187 deletions(-) diff --git a/src/app/global/app_sections_config.nim b/src/app/global/app_sections_config.nim index d811aea244..8d8208ded6 100644 --- a/src/app/global/app_sections_config.nim +++ b/src/app/global/app_sections_config.nim @@ -2,6 +2,8 @@ const CHAT_SECTION_NAME* = "Messages" const CHAT_SECTION_ICON* = "chat" const LOADING_SECTION_ID* = "loadingSection" +const LOADING_SECTION_NAME* = "Chat section loading..." +const LOADING_SECTION_ICON* = "loading" const COMMUNITIESPORTAL_SECTION_ID* = "communitiesPortal" const COMMUNITIESPORTAL_SECTION_NAME* = "Communities Portal" diff --git a/src/app/modules/main/chat_section/chat_content/controller.nim b/src/app/modules/main/chat_section/chat_content/controller.nim index f8d08aae9e..b6e1953261 100644 --- a/src/app/modules/main/chat_section/chat_content/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/controller.nim @@ -208,9 +208,6 @@ proc getMessageById*(self: Controller, messageId: string): GetMessageResult = proc isUsersListAvailable*(self: Controller): bool = return self.isUsersListAvailable -proc getMyMutualContacts*(self: Controller): seq[ContactsDto] = - return self.contactService.getContactsByGroup(ContactsGroup.MyMutualContacts) - proc muteChat*(self: Controller, interval: int) = self.chatService.muteChat(self.chatId, interval) diff --git a/src/app/modules/main/chat_section/chat_content/io_interface.nim b/src/app/modules/main/chat_section/chat_content/io_interface.nim index 7f8e31994a..527bd27bb6 100644 --- a/src/app/modules/main/chat_section/chat_content/io_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/io_interface.nim @@ -89,9 +89,6 @@ method unpinMessage*(self: AccessInterface, messageId: string) {.base.} = method getMyChatId*(self: AccessInterface): string {.base.} = raise newException(ValueError, "No implementation available") -method isMyContact*(self: AccessInterface, contactId: string): bool {.base.} = - raise newException(ValueError, "No implementation available") - method muteChat*(self: AccessInterface, interval: int) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/chat_section/chat_content/module.nim b/src/app/modules/main/chat_section/chat_content/module.nim index 19edaae6f2..39e6002eee 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -1,4 +1,4 @@ -import NimQml, chronicles, sequtils, sugar +import NimQml, chronicles, sequtils import io_interface import ../io_interface as delegate_interface import view, controller @@ -273,9 +273,6 @@ method onPinMessage*(self: Module, messageId: string, actionInitiatedBy: string) method getMyChatId*(self: Module): string = self.controller.getMyChatId() -method isMyContact*(self: Module, contactId: string): bool = - self.controller.getMyMutualContacts().filter(x => x.id == contactId).len > 0 - method muteChat*(self: Module, interval: int) = self.controller.muteChat(interval) diff --git a/src/app/modules/main/chat_section/chat_content/view.nim b/src/app/modules/main/chat_section/chat_content/view.nim index dfbf7fb787..d31225511c 100644 --- a/src/app/modules/main/chat_section/chat_content/view.nim +++ b/src/app/modules/main/chat_section/chat_content/view.nim @@ -66,9 +66,6 @@ QtObject: proc getMyChatId*(self: View): string {.slot.} = return self.delegate.getMyChatId() - proc isMyContact*(self: View, contactId: string): bool {.slot.} = - return self.delegate.isMyContact(contactId) - proc muteChat*(self: View, interval: int) {.slot.} = self.delegate.muteChat(interval) diff --git a/src/app/modules/main/chat_section/io_interface.nim b/src/app/modules/main/chat_section/io_interface.nim index e1174a0d98..c1f5d94bd7 100644 --- a/src/app/modules/main/chat_section/io_interface.nim +++ b/src/app/modules/main/chat_section/io_interface.nim @@ -263,12 +263,6 @@ method createGroupChat*(self: AccessInterface, groupName: string, pubKeys: seq[s method joinGroupChatFromInvitation*(self: AccessInterface, groupName: string, chatId: string, adminPK: string) {.base.} = raise newException(ValueError, "No implementation available") -method initListOfMyContacts*(self: AccessInterface, pubKeys: string) {.base.} = - raise newException(ValueError, "No implementation available") - -method clearListOfMyContacts*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") - method acceptRequestToJoinCommunity*(self: AccessInterface, requestId: string, communityId: string) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index 48f9741df3..b0cb1f49c1 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -413,18 +413,6 @@ proc convertPubKeysToJson(self: Module, pubKeys: string): seq[string] = proc showPermissionUpdateNotification(self: Module, community: CommunityDto, tokenPermission: CommunityTokenPermissionDto): bool = return tokenPermission.state == TokenPermissionState.Approved and (community.isControlNode or not tokenPermission.isPrivate) and community.isMember -method initListOfMyContacts*(self: Module, pubKeys: string) = - var myContacts: seq[UserItem] - let contacts = self.controller.getContacts(ContactsGroup.MyMutualContacts) - for c in contacts: - let item = self.createItemFromPublicKey(c.id) - myContacts.add(item) - - self.view.listOfMyContacts().addItems(myContacts) - -method clearListOfMyContacts*(self: Module) = - self.view.listOfMyContacts().clear() - method load*(self: Module) = self.controller.init() self.view.load() @@ -452,7 +440,7 @@ method onChatsLoaded*( if self.membersListModule != nil: self.membersListModule.load() - if(not self.controller.isCommunity()): + if not self.controller.isCommunity(): # we do this only in case of chat section (not in case of communities) self.initContactRequestsModel() else: diff --git a/src/app/modules/main/chat_section/view.nim b/src/app/modules/main/chat_section/view.nim index 85da4e93fe..556d4d01f2 100644 --- a/src/app/modules/main/chat_section/view.nim +++ b/src/app/modules/main/chat_section/view.nim @@ -18,8 +18,6 @@ QtObject: tmpChatId: string # shouldn't be used anywhere except in prepareChatContentModuleForChatId/getChatContentModule procs contactRequestsModel: user_model.Model contactRequestsModelVariant: QVariant - listOfMyContacts: user_model.Model - listOfMyContactsVariant: QVariant editCategoryChannelsModel: chats_model.Model editCategoryChannelsVariant: QVariant loadingHistoryMessagesInProgress: bool @@ -47,8 +45,6 @@ QtObject: self.activeItemVariant.delete self.contactRequestsModel.delete self.contactRequestsModelVariant.delete - self.listOfMyContacts.delete - self.listOfMyContactsVariant.delete self.editCategoryChannelsModel.delete self.editCategoryChannelsVariant.delete self.tokenPermissionsModel.delete @@ -70,8 +66,6 @@ QtObject: result.activeItemVariant = newQVariant(result.activeItem) result.contactRequestsModel = user_model.newModel() result.contactRequestsModelVariant = newQVariant(result.contactRequestsModel) - result.listOfMyContacts = user_model.newModel() - result.listOfMyContactsVariant = newQVariant(result.listOfMyContacts) result.loadingHistoryMessagesInProgress = false result.tokenPermissionsModel = newTokenPermissionsModel() result.tokenPermissionsVariant = newQVariant(result.tokenPermissionsModel) @@ -132,25 +126,6 @@ QtObject: QtProperty[QVariant] contactRequestsModel: read = getContactRequestsModel - proc listOfMyContactsChanged*(self: View) {.signal.} - - proc populateMyContacts*(self: View, pubKeys: string) {.slot.} = - self.delegate.initListOfMyContacts(pubKeys) - self.listOfMyContactsChanged() - - proc clearMyContacts*(self: View) {.slot.} = - self.delegate.clearListOfMyContacts() - self.listOfMyContactsChanged() - - proc listOfMyContacts*(self: View): user_model.Model = - return self.listOfMyContacts - - proc getListOfMyContacts(self: View): QVariant {.slot.} = - return self.listOfMyContactsVariant - QtProperty[QVariant] listOfMyContacts: - read = getListOfMyContacts - notify = listOfMyContactsChanged - proc activeItemChanged*(self:View) {.signal.} proc getActiveItem(self: View): QVariant {.slot.} = diff --git a/src/app/modules/main/controller.nim b/src/app/modules/main/controller.nim index bf4da9a8a8..fb3fc9febd 100644 --- a/src/app/modules/main/controller.nim +++ b/src/app/modules/main/controller.nim @@ -143,6 +143,23 @@ proc init*(self: Controller) = self.networksService, ) + self.events.on(SIGNAL_CONTACTS_LOADED) do(e:Args): + self.delegate.onContactsLoaded( + self.events, + self.settingsService, + self.nodeConfigurationService, + self.contactsService, + self.chatService, + self.communityService, + self.messageService, + self.mailserversService, + self.walletAccountService, + self.tokenService, + self.communityTokensService, + self.sharedUrlsService, + self.networksService, + ) + self.events.on(SIGNAL_CHATS_LOADING_FAILED) do(e:Args): self.delegate.onChatsLoadingFailed() @@ -533,9 +550,6 @@ proc setCurrentUserStatus*(self: Controller, status: StatusType) = proc getContact*(self: Controller, id: string): ContactsDto = return self.contactsService.getContactById(id) -proc getContacts*(self: Controller, group: ContactsGroup): seq[ContactsDto] = - return self.contactsService.getContactsByGroup(group) - proc getContactNameAndImage*(self: Controller, contactId: string): tuple[name: string, image: string, largeImage: string] = return self.contactsService.getContactNameAndImage(contactId) diff --git a/src/app/modules/main/io_interface.nim b/src/app/modules/main/io_interface.nim index e9bea0abcb..f8808ac8f9 100644 --- a/src/app/modules/main/io_interface.nim +++ b/src/app/modules/main/io_interface.nim @@ -117,6 +117,24 @@ method onCommunityDataLoaded*( ){.base.} = raise newException(ValueError, "No implementation available") +method onContactsLoaded*( + self: AccessInterface, + events: EventEmitter, + settingsService: settings_service.Service, + nodeConfigurationService: node_configuration_service.Service, + contactsService: contacts_service.Service, + chatService: chat_service.Service, + communityService: community_service.Service, + messageService: message_service.Service, + mailserversService: mailservers_service.Service, + walletAccountService: wallet_account_service.Service, + tokenService: token_service.Service, + communityTokensService: community_tokens_service.Service, + sharedUrlsService: urls_service.Service, + networkService: network_service.Service, + ){.base.} = + raise newException(ValueError, "No implementation available") + method onChatsLoadingFailed*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index e681ee1608..62258553ec 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -117,6 +117,7 @@ type moduleLoaded: bool chatsLoaded: bool communityDataLoaded: bool + contactsLoaded: bool pendingSpectateRequest: SpectateRequest statusDeepLinkToActivate: string @@ -195,6 +196,7 @@ proc newModule*[T]( result.moduleLoaded = false result.chatsLoaded = false result.communityDataLoaded = false + result.contactsLoaded = false result.events = events result.urlsManager = urlsManager @@ -502,6 +504,22 @@ method load*[T]( if (activeSectionId == ""): activeSectionId = singletonInstance.userProfile.getPubKey() + let loadingItem = initItem( + LOADING_SECTION_ID, + SectionType.LoadingSection, + conf.LOADING_SECTION_NAME, + memberRole = MemberRole.Owner, + description = "", + image = "", + icon = conf.LOADING_SECTION_ICON, + color = "", + hasNotification = false, + notificationsCount = 0, + active = false, + enabled = true, + ) + self.view.model().addItem(loadingItem) + # Communities Portal Section let communitiesPortalSectionItem = initItem( conf.COMMUNITIESPORTAL_SECTION_ID, @@ -518,7 +536,7 @@ method load*[T]( enabled = true, ) self.view.model().addItem(communitiesPortalSectionItem) - if(activeSectionId == communitiesPortalSectionItem.id): + if activeSectionId == communitiesPortalSectionItem.id: activeSection = communitiesPortalSectionItem # Wallet Section @@ -539,7 +557,7 @@ method load*[T]( enabled = WALLET_ENABLED, ) self.view.model().addItem(walletSectionItem) - if(activeSectionId == walletSectionItem.id): + if activeSectionId == walletSectionItem.id: activeSection = walletSectionItem # Node Management Section @@ -560,7 +578,7 @@ method load*[T]( enabled = singletonInstance.localAccountSensitiveSettings.getNodeManagementEnabled(), ) self.view.model().addItem(nodeManagementSectionItem) - if(activeSectionId == nodeManagementSectionItem.id): + if activeSectionId == nodeManagementSectionItem.id: activeSection = nodeManagementSectionItem # Profile Section @@ -581,7 +599,7 @@ method load*[T]( enabled = true, ) self.view.model().addItem(profileSettingsSectionItem) - if(activeSectionId == profileSettingsSectionItem.id): + if activeSectionId == profileSettingsSectionItem.id: activeSection = profileSettingsSectionItem self.profileSectionModule.load() @@ -600,25 +618,13 @@ method load*[T]( # If section is empty or profile then open the loading section until chats are loaded if activeSection.isEmpty() or activeSection.sectionType == SectionType.ProfileSettings: # Set bogus Item as active until the chat is loaded - let loadingItem = initItem( - LOADING_SECTION_ID, - SectionType.LoadingSection, - name = "", - memberRole = MemberRole.Owner, - description = "", - image = "", - icon = "", - color = "", - hasNotification = false, - notificationsCount = 0, - active = false, - enabled = true, - ) - self.view.model().addItem(loadingItem) self.setActiveSection(loadingItem, skipSavingInSettings = true) else: self.setActiveSection(activeSection) +proc isEverythingLoaded[T](self: Module[T]): bool = + return self.communityDataLoaded and self.chatsLoaded and self.contactsLoaded + method onChatsLoaded*[T]( self: Module[T], events: EventEmitter, @@ -636,11 +642,9 @@ method onChatsLoaded*[T]( networkService: network_service.Service, ) = self.chatsLoaded = true - if not self.communityDataLoaded: + if not self.isEverythingLoaded: return - let myPubKey = singletonInstance.userProfile.getPubKey() - var activeSection: SectionItem var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection() if activeSectionId == "" or activeSectionId == conf.SETTINGS_SECTION_ID: @@ -752,7 +756,43 @@ method onCommunityDataLoaded*[T]( networkService: network_service.Service, ) = self.communityDataLoaded = true - if not self.chatsLoaded: + if not self.isEverythingLoaded: + return + + self.onChatsLoaded( + events, + settingsService, + nodeConfigurationService, + contactsService, + chatService, + communityService, + messageService, + mailserversService, + walletAccountService, + tokenService, + communityTokensService, + sharedUrlsService, + networkService, + ) + +method onContactsLoaded*[T]( + self: Module[T], + events: EventEmitter, + settingsService: settings_service.Service, + nodeConfigurationService: node_configuration_service.Service, + contactsService: contacts_service.Service, + chatService: chat_service.Service, + communityService: community_service.Service, + messageService: message_service.Service, + mailserversService: mailservers_service.Service, + walletAccountService: wallet_account_service.Service, + tokenService: token_service.Service, + communityTokensService: community_tokens_service.Service, + sharedUrlsService: urls_service.Service, + networkService: network_service.Service, +) = + self.contactsLoaded = true + if not self.isEverythingLoaded: return self.onChatsLoaded( diff --git a/src/app/modules/main/profile_section/contacts/controller.nim b/src/app/modules/main/profile_section/contacts/controller.nim index 2cdd39ed5e..e19d92c197 100644 --- a/src/app/modules/main/profile_section/contacts/controller.nim +++ b/src/app/modules/main/profile_section/contacts/controller.nim @@ -30,6 +30,9 @@ proc delete*(self: Controller) = discard proc init*(self: Controller) = + self.events.on(SIGNAL_CONTACTS_LOADED) do(e:Args): + self.delegate.onContactsLoaded() + self.events.on(SIGNAL_CONTACT_ADDED) do(e: Args): var args = ContactArgs(e) self.delegate.contactAdded(args.contactId) diff --git a/src/app/modules/main/profile_section/contacts/io_interface.nim b/src/app/modules/main/profile_section/contacts/io_interface.nim index d641382723..5c20778007 100644 --- a/src/app/modules/main/profile_section/contacts/io_interface.nim +++ b/src/app/modules/main/profile_section/contacts/io_interface.nim @@ -27,6 +27,9 @@ method isLoaded*(self: AccessInterface): bool {.base.} = method viewDidLoad*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") +method onContactsLoaded*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + method switchToOrCreateOneToOneChat*(self: AccessInterface, publicKey: string) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/profile_section/contacts/module.nim b/src/app/modules/main/profile_section/contacts/module.nim index e973760e61..b3c477d52f 100644 --- a/src/app/modules/main/profile_section/contacts/module.nim +++ b/src/app/modules/main/profile_section/contacts/module.nim @@ -118,6 +118,10 @@ method isLoaded*(self: Module): bool = return self.moduleLoaded method viewDidLoad*(self: Module) = + self.moduleLoaded = true + self.delegate.contactsModuleDidLoad() + +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) @@ -127,9 +131,6 @@ method viewDidLoad*(self: Module) = # self.buildModel(self.view.receivedButRejectedContactRequestsModel(), ContactsGroup.IncomingRejectedContactRequests) # self.buildModel(self.view.sentButRejectedContactRequestsModel(), ContactsGroup.IncomingRejectedContactRequests) - self.moduleLoaded = true - self.delegate.contactsModuleDidLoad() - method getModuleAsVariant*(self: Module): QVariant = return self.viewVariant diff --git a/src/app/modules/shared_models/section_item.nim b/src/app/modules/shared_models/section_item.nim index 605f0bc418..8c0dabb76a 100644 --- a/src/app/modules/shared_models/section_item.nim +++ b/src/app/modules/shared_models/section_item.nim @@ -10,13 +10,13 @@ import ../../../app_service/service/community_tokens/community_collectible_owner type SectionType* {.pure.} = enum - LoadingSection = -1 Chat = 0 Community, Wallet, ProfileSettings, NodeManagement, - CommunitiesPortal + CommunitiesPortal, + LoadingSection, type SectionItem* = object diff --git a/src/app_service/service/contacts/async_tasks.nim b/src/app_service/service/contacts/async_tasks.nim index 99166a7815..781cb9bc88 100644 --- a/src/app_service/service/contacts/async_tasks.nim +++ b/src/app_service/service/contacts/async_tasks.nim @@ -53,9 +53,22 @@ proc lookupContactTask(argEncoded: string) {.gcsafe, nimcall.} = error "error lookupContactTask: ", message = e.msg arg.finish(output) -################################################# -# Async request contact info -################################################# +type + AsyncFetchContactsTaskArg = ref object of QObjectTaskArg + pubkey: string + +proc asyncFetchContactsTask(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncFetchContactsTaskArg](argEncoded) + try: + let response = status_contacts.getContacts() + arg.finish(%* { + "response": response, + "error": "", + }) + except Exception as e: + arg.finish(%* { + "error": e.msg, + }) type AsyncRequestContactInfoTaskArg = ref object of QObjectTaskArg @@ -115,4 +128,4 @@ proc fetchProfileShowcaseAccountsTask(argEncoded: string) {.gcsafe, nimcall.} = response["response"] = rpcResponse.result except Exception as e: response["error"] = %* e.msg - arg.finish(response) \ No newline at end of file + arg.finish(response) diff --git a/src/app_service/service/contacts/service.nim b/src/app_service/service/contacts/service.nim index e8a92b8597..37b5b00cdf 100644 --- a/src/app_service/service/contacts/service.nim +++ b/src/app_service/service/contacts/service.nim @@ -68,6 +68,7 @@ type # Signals which may be emitted by this service: const SIGNAL_ENS_RESOLVED* = "ensResolved" +const SIGNAL_CONTACTS_LOADED* = "contactsLoaded" const SIGNAL_CONTACT_ADDED* = "contactAdded" const SIGNAL_CONTACT_BLOCKED* = "contactBlocked" const SIGNAL_CONTACT_UNBLOCKED* = "contactUnblocked" @@ -142,18 +143,22 @@ QtObject: self.contactsStatus[contact.dto.id] = StatusUpdateDto(publicKey: contact.dto.id, statusType: StatusType.Unknown) proc fetchContacts*(self: Service) = + let arg = AsyncFetchContactsTaskArg( + tptr: asyncFetchContactsTask, + vptr: cast[ByteAddress](self.vptr), + slot: "fetchContactsDone", + ) + self.threadpool.start(arg) + + proc fetchContactsDone*(self: Service, response: string) {.slot.} = try: - let response = status_contacts.getContacts() - - let contacts = map(response.result.getElems(), proc(x: JsonNode): ContactsDto = x.toContactsDto()) - - for contact in contacts: - self.addContact(self.constructContactDetails(contact)) - + let rpcResponseObj = response.parseJson + for elem in rpcResponseObj["response"]["result"].getElems(): + let contactDto = elem.toContactsDto() + self.addContact(self.constructContactDetails(contactDto)) + self.events.emit(SIGNAL_CONTACTS_LOADED, Args()) except Exception as e: - let errDesription = e.msg - error "error fetching contacts: ", errDesription - return + error "error fetching contacts", msg = e.msg proc updateAndEmitStatuses(self: Service, statusUpdates: seq[StatusUpdateDto]) = for s in statusUpdates: @@ -271,37 +276,12 @@ QtObject: return contacts - proc fetchContact(self: Service, id: string): ContactDetails = - try: - let response = status_contacts.getContactByID(id) - - let contactDto = response.result.toContactsDto() - if contactDto.id.len == 0: - return - - result = self.constructContactDetails(contactDto) - self.addContact(result) - - except Exception as e: - let errDesription = e.msg - error "error: ", errDesription - return - proc generateAlias*(self: Service, publicKey: string): string = if(publicKey.len == 0): error "cannot generate an alias from the empty public key" return return status_accounts.generateAlias(publicKey).result.getStr - proc getTrustStatus*(self: Service, publicKey: string): TrustStatus = - try: - let t = status_contacts.getTrustStatus(publicKey).result.getInt - return t.toTrustStatus() - except Exception as e: - let errDesription = e.msg - error "error: ", errDesription - return TrustStatus.Unknown - proc getContactNameAndImageInternal(self: Service, contactDto: ContactsDto): tuple[name: string, optionalName: string, image: string, largeImage: string] = ## This proc should be used accross the app in order to have for the same contact @@ -334,7 +314,7 @@ QtObject: if len(pubkey) == 0: return - if(pubkey == singletonInstance.userProfile.getPubKey()): + if pubkey == singletonInstance.userProfile.getPubKey(): # If we try to get the contact details of ourselves, just return our own info return self.constructContactDetails( ContactsDto( @@ -355,36 +335,32 @@ QtObject: ## Returns contact details based on passed id (public key) ## If we don't have stored contact localy or in the db then we create it based on public key. - if(self.contacts.hasKey(pubkey)): + if self.contacts.hasKey(pubkey): return self.contacts[pubkey] - result = self.fetchContact(pubkey) - if result.dto.id.len == 0: - if(not pubkey.startsWith("0x")): - debug "id is not in a hex format" - return + if not pubkey.startsWith("0x"): + debug "id is not in a hex format" + return - var num64: int64 - let parsedChars = parseHex(pubkey, num64) - if(parsedChars != PK_LENGTH_0X_INCLUDED): - debug "id doesn't have expected length" - return + var num64: int64 + let parsedChars = parseHex(pubkey, num64) + if parsedChars != PK_LENGTH_0X_INCLUDED: + debug "id doesn't have expected length" + return - let alias = self.generateAlias(pubkey) - let trustStatus = self.getTrustStatus(pubkey) - let contact = self.constructContactDetails( - ContactsDto( - id: pubkey, - alias: alias, - ensVerified: result.dto.ensVerified, - added: result.dto.added, - blocked: result.dto.blocked, - hasAddedUs: result.dto.hasAddedUs, - trustStatus: trustStatus - ) + let contact = self.constructContactDetails( + ContactsDto( + id: pubkey, + alias: self.generateAlias(pubkey), + ensVerified: false, + added: false, + blocked: false, + hasAddedUs: false, + trustStatus: TrustStatus.Unknown, ) - self.addContact(contact) - return contact + ) + self.addContact(contact) + return contact proc getContactById*(self: Service, id: string): ContactsDto = return self.getContactDetails(id).dto @@ -562,13 +538,16 @@ QtObject: checkAndEmitACNotificationsFromResponse(self.events, response.result{"activityCenterNotifications"}) proc ensResolved*(self: Service, jsonObj: string) {.slot.} = - let jsonObj = jsonObj.parseJson() - let data = ResolvedContactArgs( - pubkey: jsonObj["id"].getStr, - address: jsonObj["address"].getStr, - uuid: jsonObj["uuid"].getStr, - reason: jsonObj["reason"].getStr) - self.events.emit(SIGNAL_ENS_RESOLVED, data) + try: + let jsonObj = jsonObj.parseJson() + let data = ResolvedContactArgs( + pubkey: jsonObj["id"].getStr, + address: jsonObj["address"].getStr, + uuid: jsonObj["uuid"].getStr, + reason: jsonObj["reason"].getStr) + self.events.emit(SIGNAL_ENS_RESOLVED, data) + except Exception as e: + error "error resolving ENS ", msg=e.msg proc resolveENS*(self: Service, value: string, uuid: string = "", reason = "") = if(self.closingApp): @@ -635,26 +614,29 @@ QtObject: error "error in removeTrustStatus request", msg = e.msg proc asyncContactInfoLoaded*(self: Service, pubkeyAndRpcResponse: string) {.slot.} = - let rpcResponseObj = pubkeyAndRpcResponse.parseJson - let publicKey = rpcResponseObj{"publicKey"}.getStr - let requestError = rpcResponseObj{"error"} - var error : string + try: + let rpcResponseObj = pubkeyAndRpcResponse.parseJson + let publicKey = rpcResponseObj{"publicKey"}.getStr + let requestError = rpcResponseObj{"error"} + var error : string - if requestError.kind != JNull: - error = requestError.getStr - else: - let responseError = rpcResponseObj{"response"}{"error"} - if responseError.kind != JNull: - error = Json.decode($responseError, RpcError).message + if requestError.kind != JNull: + error = requestError.getStr + else: + let responseError = rpcResponseObj{"response"}{"error"} + if responseError.kind != JNull: + error = Json.decode($responseError, RpcError).message - if len(error) != 0: - error "error requesting contact info", msg = error, publicKey - self.events.emit(SIGNAL_CONTACT_INFO_REQUEST_FINISHED, ContactInfoRequestArgs(publicKey: publicKey, ok: false)) - return + if len(error) != 0: + error "error requesting contact info", msg = error, publicKey + self.events.emit(SIGNAL_CONTACT_INFO_REQUEST_FINISHED, ContactInfoRequestArgs(publicKey: publicKey, ok: false)) + return - let contact = rpcResponseObj{"response"}{"result"}.toContactsDto() - self.saveContact(contact) - self.events.emit(SIGNAL_CONTACT_INFO_REQUEST_FINISHED, ContactInfoRequestArgs(publicKey: publicKey, ok: true)) + let contact = rpcResponseObj{"response"}{"result"}.toContactsDto() + self.saveContact(contact) + self.events.emit(SIGNAL_CONTACT_INFO_REQUEST_FINISHED, ContactInfoRequestArgs(publicKey: publicKey, ok: true)) + except Exception as e: + error "error in contact info loaded", msg = e.msg proc requestContactInfo*(self: Service, pubkey: string) = try: diff --git a/src/backend/contacts.nim b/src/backend/contacts.nim index 3b2509ceeb..74abaf4eaf 100644 --- a/src/backend/contacts.nim +++ b/src/backend/contacts.nim @@ -8,10 +8,6 @@ proc getContacts*(): RpcResponse[JsonNode] = let payload = %* [] result = callPrivateRPC("contacts".prefix, payload) -proc getContactById*(id: string): RpcResponse[JsonNode] = - let payload = %* [id] - result = callPrivateRPC("getContactByID".prefix, payload) - proc blockContact*(id: string): RpcResponse[JsonNode] = result = callPrivateRPC("blockContactDesktop".prefix, %* [id]) @@ -83,10 +79,6 @@ proc removeTrustStatus*(pubkey: string): RpcResponse[JsonNode] = let payload = %* [pubkey] result = callPrivateRPC("removeTrustStatus".prefix, payload) -proc getTrustStatus*(pubkey: string): RpcResponse[JsonNode] = - let payload = %* [pubkey] - result = callPrivateRPC("getTrustStatus".prefix, payload) - proc retractContactRequest*(pubkey: string): RpcResponse[JsonNode] = let payload = %*[{ "id": pubkey diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusIconTabButton.qml b/ui/StatusQ/src/StatusQ/Controls/StatusIconTabButton.qml index d9db4ff03d..9ed670305b 100644 --- a/ui/StatusQ/src/StatusQ/Controls/StatusIconTabButton.qml +++ b/ui/StatusQ/src/StatusQ/Controls/StatusIconTabButton.qml @@ -25,7 +25,8 @@ TabButton { StatusSmartIdenticon { id: identicon anchors.centerIn: parent - asset.isImage: (statusIconTabButton.icon.source.toString() !== "") + loading: statusIconTabButton.icon.name === "loading" + asset.isImage: loading || statusIconTabButton.icon.source.toString() !== "" asset.name: asset.isImage ? statusIconTabButton.icon.source : statusIconTabButton.icon.name asset.width: asset.isImage ? 28 : statusIconTabButton.icon.width diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index b5ae48aaee..ff0be0d876 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -815,7 +815,7 @@ Item { RangeFilter { roleName: "sectionType" minimumValue: Constants.appSection.wallet - maximumValue: Constants.appSection.communitiesPortal + maximumValue: Constants.appSection.loadingSection }, ValueFilter { roleName: "enabled" diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index a9c739f742..42e360da59 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -326,6 +326,7 @@ QtObject { readonly property int profile: 3 readonly property int node: 4 readonly property int communitiesPortal: 5 + readonly property int loadingSection: 6 } readonly property QtObject appViewStackIndex: QtObject { diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml index 2be271d88f..7b281b438c 100644 --- a/ui/imports/utils/Utils.qml +++ b/ui/imports/utils/Utils.qml @@ -417,6 +417,8 @@ QtObject { return qsTr("Node Management") case Constants.appSection.communitiesPortal: return qsTr("Discover Communities") + case Constants.appSection.loadingSection: + return qsTr("Chat section loading...") default: return fallback }