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
This commit is contained in:
Jonathan Rainville 2024-11-01 10:32:20 -04:00 committed by GitHub
parent 36f2bb79a9
commit 27ececad63
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 204 additions and 187 deletions

View File

@ -2,6 +2,8 @@ const CHAT_SECTION_NAME* = "Messages"
const CHAT_SECTION_ICON* = "chat" const CHAT_SECTION_ICON* = "chat"
const LOADING_SECTION_ID* = "loadingSection" 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_ID* = "communitiesPortal"
const COMMUNITIESPORTAL_SECTION_NAME* = "Communities Portal" const COMMUNITIESPORTAL_SECTION_NAME* = "Communities Portal"

View File

@ -208,9 +208,6 @@ proc getMessageById*(self: Controller, messageId: string): GetMessageResult =
proc isUsersListAvailable*(self: Controller): bool = proc isUsersListAvailable*(self: Controller): bool =
return self.isUsersListAvailable return self.isUsersListAvailable
proc getMyMutualContacts*(self: Controller): seq[ContactsDto] =
return self.contactService.getContactsByGroup(ContactsGroup.MyMutualContacts)
proc muteChat*(self: Controller, interval: int) = proc muteChat*(self: Controller, interval: int) =
self.chatService.muteChat(self.chatId, interval) self.chatService.muteChat(self.chatId, interval)

View File

@ -89,9 +89,6 @@ method unpinMessage*(self: AccessInterface, messageId: string) {.base.} =
method getMyChatId*(self: AccessInterface): string {.base.} = method getMyChatId*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available") 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.} = method muteChat*(self: AccessInterface, interval: int) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -1,4 +1,4 @@
import NimQml, chronicles, sequtils, sugar import NimQml, chronicles, sequtils
import io_interface import io_interface
import ../io_interface as delegate_interface import ../io_interface as delegate_interface
import view, controller import view, controller
@ -273,9 +273,6 @@ method onPinMessage*(self: Module, messageId: string, actionInitiatedBy: string)
method getMyChatId*(self: Module): string = method getMyChatId*(self: Module): string =
self.controller.getMyChatId() 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) = method muteChat*(self: Module, interval: int) =
self.controller.muteChat(interval) self.controller.muteChat(interval)

View File

@ -66,9 +66,6 @@ QtObject:
proc getMyChatId*(self: View): string {.slot.} = proc getMyChatId*(self: View): string {.slot.} =
return self.delegate.getMyChatId() return self.delegate.getMyChatId()
proc isMyContact*(self: View, contactId: string): bool {.slot.} =
return self.delegate.isMyContact(contactId)
proc muteChat*(self: View, interval: int) {.slot.} = proc muteChat*(self: View, interval: int) {.slot.} =
self.delegate.muteChat(interval) self.delegate.muteChat(interval)

View File

@ -263,12 +263,6 @@ method createGroupChat*(self: AccessInterface, groupName: string, pubKeys: seq[s
method joinGroupChatFromInvitation*(self: AccessInterface, groupName: string, chatId: string, adminPK: string) {.base.} = method joinGroupChatFromInvitation*(self: AccessInterface, groupName: string, chatId: string, adminPK: string) {.base.} =
raise newException(ValueError, "No implementation available") 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.} = method acceptRequestToJoinCommunity*(self: AccessInterface, requestId: string, communityId: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -413,18 +413,6 @@ proc convertPubKeysToJson(self: Module, pubKeys: string): seq[string] =
proc showPermissionUpdateNotification(self: Module, community: CommunityDto, tokenPermission: CommunityTokenPermissionDto): bool = proc showPermissionUpdateNotification(self: Module, community: CommunityDto, tokenPermission: CommunityTokenPermissionDto): bool =
return tokenPermission.state == TokenPermissionState.Approved and (community.isControlNode or not tokenPermission.isPrivate) and community.isMember 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) = method load*(self: Module) =
self.controller.init() self.controller.init()
self.view.load() self.view.load()
@ -452,7 +440,7 @@ method onChatsLoaded*(
if self.membersListModule != nil: if self.membersListModule != nil:
self.membersListModule.load() 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) # we do this only in case of chat section (not in case of communities)
self.initContactRequestsModel() self.initContactRequestsModel()
else: else:

View File

@ -18,8 +18,6 @@ QtObject:
tmpChatId: string # shouldn't be used anywhere except in prepareChatContentModuleForChatId/getChatContentModule procs tmpChatId: string # shouldn't be used anywhere except in prepareChatContentModuleForChatId/getChatContentModule procs
contactRequestsModel: user_model.Model contactRequestsModel: user_model.Model
contactRequestsModelVariant: QVariant contactRequestsModelVariant: QVariant
listOfMyContacts: user_model.Model
listOfMyContactsVariant: QVariant
editCategoryChannelsModel: chats_model.Model editCategoryChannelsModel: chats_model.Model
editCategoryChannelsVariant: QVariant editCategoryChannelsVariant: QVariant
loadingHistoryMessagesInProgress: bool loadingHistoryMessagesInProgress: bool
@ -47,8 +45,6 @@ QtObject:
self.activeItemVariant.delete self.activeItemVariant.delete
self.contactRequestsModel.delete self.contactRequestsModel.delete
self.contactRequestsModelVariant.delete self.contactRequestsModelVariant.delete
self.listOfMyContacts.delete
self.listOfMyContactsVariant.delete
self.editCategoryChannelsModel.delete self.editCategoryChannelsModel.delete
self.editCategoryChannelsVariant.delete self.editCategoryChannelsVariant.delete
self.tokenPermissionsModel.delete self.tokenPermissionsModel.delete
@ -70,8 +66,6 @@ QtObject:
result.activeItemVariant = newQVariant(result.activeItem) result.activeItemVariant = newQVariant(result.activeItem)
result.contactRequestsModel = user_model.newModel() result.contactRequestsModel = user_model.newModel()
result.contactRequestsModelVariant = newQVariant(result.contactRequestsModel) result.contactRequestsModelVariant = newQVariant(result.contactRequestsModel)
result.listOfMyContacts = user_model.newModel()
result.listOfMyContactsVariant = newQVariant(result.listOfMyContacts)
result.loadingHistoryMessagesInProgress = false result.loadingHistoryMessagesInProgress = false
result.tokenPermissionsModel = newTokenPermissionsModel() result.tokenPermissionsModel = newTokenPermissionsModel()
result.tokenPermissionsVariant = newQVariant(result.tokenPermissionsModel) result.tokenPermissionsVariant = newQVariant(result.tokenPermissionsModel)
@ -132,25 +126,6 @@ QtObject:
QtProperty[QVariant] contactRequestsModel: QtProperty[QVariant] contactRequestsModel:
read = getContactRequestsModel 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 activeItemChanged*(self:View) {.signal.}
proc getActiveItem(self: View): QVariant {.slot.} = proc getActiveItem(self: View): QVariant {.slot.} =

View File

@ -143,6 +143,23 @@ proc init*(self: Controller) =
self.networksService, 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.events.on(SIGNAL_CHATS_LOADING_FAILED) do(e:Args):
self.delegate.onChatsLoadingFailed() self.delegate.onChatsLoadingFailed()
@ -533,9 +550,6 @@ proc setCurrentUserStatus*(self: Controller, status: StatusType) =
proc getContact*(self: Controller, id: string): ContactsDto = proc getContact*(self: Controller, id: string): ContactsDto =
return self.contactsService.getContactById(id) return self.contactsService.getContactById(id)
proc getContacts*(self: Controller, group: ContactsGroup): seq[ContactsDto] =
return self.contactsService.getContactsByGroup(group)
proc getContactNameAndImage*(self: Controller, contactId: string): proc getContactNameAndImage*(self: Controller, contactId: string):
tuple[name: string, image: string, largeImage: string] = tuple[name: string, image: string, largeImage: string] =
return self.contactsService.getContactNameAndImage(contactId) return self.contactsService.getContactNameAndImage(contactId)

View File

@ -117,6 +117,24 @@ method onCommunityDataLoaded*(
){.base.} = ){.base.} =
raise newException(ValueError, "No implementation available") 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.} = method onChatsLoadingFailed*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -117,6 +117,7 @@ type
moduleLoaded: bool moduleLoaded: bool
chatsLoaded: bool chatsLoaded: bool
communityDataLoaded: bool communityDataLoaded: bool
contactsLoaded: bool
pendingSpectateRequest: SpectateRequest pendingSpectateRequest: SpectateRequest
statusDeepLinkToActivate: string statusDeepLinkToActivate: string
@ -195,6 +196,7 @@ proc newModule*[T](
result.moduleLoaded = false result.moduleLoaded = false
result.chatsLoaded = false result.chatsLoaded = false
result.communityDataLoaded = false result.communityDataLoaded = false
result.contactsLoaded = false
result.events = events result.events = events
result.urlsManager = urlsManager result.urlsManager = urlsManager
@ -502,6 +504,22 @@ method load*[T](
if (activeSectionId == ""): if (activeSectionId == ""):
activeSectionId = singletonInstance.userProfile.getPubKey() 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 # Communities Portal Section
let communitiesPortalSectionItem = initItem( let communitiesPortalSectionItem = initItem(
conf.COMMUNITIESPORTAL_SECTION_ID, conf.COMMUNITIESPORTAL_SECTION_ID,
@ -518,7 +536,7 @@ method load*[T](
enabled = true, enabled = true,
) )
self.view.model().addItem(communitiesPortalSectionItem) self.view.model().addItem(communitiesPortalSectionItem)
if(activeSectionId == communitiesPortalSectionItem.id): if activeSectionId == communitiesPortalSectionItem.id:
activeSection = communitiesPortalSectionItem activeSection = communitiesPortalSectionItem
# Wallet Section # Wallet Section
@ -539,7 +557,7 @@ method load*[T](
enabled = WALLET_ENABLED, enabled = WALLET_ENABLED,
) )
self.view.model().addItem(walletSectionItem) self.view.model().addItem(walletSectionItem)
if(activeSectionId == walletSectionItem.id): if activeSectionId == walletSectionItem.id:
activeSection = walletSectionItem activeSection = walletSectionItem
# Node Management Section # Node Management Section
@ -560,7 +578,7 @@ method load*[T](
enabled = singletonInstance.localAccountSensitiveSettings.getNodeManagementEnabled(), enabled = singletonInstance.localAccountSensitiveSettings.getNodeManagementEnabled(),
) )
self.view.model().addItem(nodeManagementSectionItem) self.view.model().addItem(nodeManagementSectionItem)
if(activeSectionId == nodeManagementSectionItem.id): if activeSectionId == nodeManagementSectionItem.id:
activeSection = nodeManagementSectionItem activeSection = nodeManagementSectionItem
# Profile Section # Profile Section
@ -581,7 +599,7 @@ method load*[T](
enabled = true, enabled = true,
) )
self.view.model().addItem(profileSettingsSectionItem) self.view.model().addItem(profileSettingsSectionItem)
if(activeSectionId == profileSettingsSectionItem.id): if activeSectionId == profileSettingsSectionItem.id:
activeSection = profileSettingsSectionItem activeSection = profileSettingsSectionItem
self.profileSectionModule.load() 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 section is empty or profile then open the loading section until chats are loaded
if activeSection.isEmpty() or activeSection.sectionType == SectionType.ProfileSettings: if activeSection.isEmpty() or activeSection.sectionType == SectionType.ProfileSettings:
# Set bogus Item as active until the chat is loaded # 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) self.setActiveSection(loadingItem, skipSavingInSettings = true)
else: else:
self.setActiveSection(activeSection) self.setActiveSection(activeSection)
proc isEverythingLoaded[T](self: Module[T]): bool =
return self.communityDataLoaded and self.chatsLoaded and self.contactsLoaded
method onChatsLoaded*[T]( method onChatsLoaded*[T](
self: Module[T], self: Module[T],
events: EventEmitter, events: EventEmitter,
@ -636,11 +642,9 @@ method onChatsLoaded*[T](
networkService: network_service.Service, networkService: network_service.Service,
) = ) =
self.chatsLoaded = true self.chatsLoaded = true
if not self.communityDataLoaded: if not self.isEverythingLoaded:
return return
let myPubKey = singletonInstance.userProfile.getPubKey() let myPubKey = singletonInstance.userProfile.getPubKey()
var activeSection: SectionItem var activeSection: SectionItem
var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection() var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection()
if activeSectionId == "" or activeSectionId == conf.SETTINGS_SECTION_ID: if activeSectionId == "" or activeSectionId == conf.SETTINGS_SECTION_ID:
@ -752,7 +756,43 @@ method onCommunityDataLoaded*[T](
networkService: network_service.Service, networkService: network_service.Service,
) = ) =
self.communityDataLoaded = true 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 return
self.onChatsLoaded( self.onChatsLoaded(

View File

@ -30,6 +30,9 @@ proc delete*(self: Controller) =
discard discard
proc init*(self: Controller) = 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): self.events.on(SIGNAL_CONTACT_ADDED) do(e: Args):
var args = ContactArgs(e) var args = ContactArgs(e)
self.delegate.contactAdded(args.contactId) self.delegate.contactAdded(args.contactId)

View File

@ -27,6 +27,9 @@ method isLoaded*(self: AccessInterface): bool {.base.} =
method viewDidLoad*(self: AccessInterface) {.base.} = method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method onContactsLoaded*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method switchToOrCreateOneToOneChat*(self: AccessInterface, publicKey: string) {.base.} = method switchToOrCreateOneToOneChat*(self: AccessInterface, publicKey: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -118,6 +118,10 @@ method isLoaded*(self: Module): bool =
return self.moduleLoaded return self.moduleLoaded
method viewDidLoad*(self: Module) = 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.contactsModel(), ContactsGroup.AllKnownContacts)
self.buildModel(self.view.myMutualContactsModel(), ContactsGroup.MyMutualContacts) self.buildModel(self.view.myMutualContactsModel(), ContactsGroup.MyMutualContacts)
self.buildModel(self.view.blockedContactsModel(), ContactsGroup.BlockedContacts) 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.receivedButRejectedContactRequestsModel(), ContactsGroup.IncomingRejectedContactRequests)
# self.buildModel(self.view.sentButRejectedContactRequestsModel(), ContactsGroup.IncomingRejectedContactRequests) # self.buildModel(self.view.sentButRejectedContactRequestsModel(), ContactsGroup.IncomingRejectedContactRequests)
self.moduleLoaded = true
self.delegate.contactsModuleDidLoad()
method getModuleAsVariant*(self: Module): QVariant = method getModuleAsVariant*(self: Module): QVariant =
return self.viewVariant return self.viewVariant

View File

@ -10,13 +10,13 @@ import ../../../app_service/service/community_tokens/community_collectible_owner
type type
SectionType* {.pure.} = enum SectionType* {.pure.} = enum
LoadingSection = -1
Chat = 0 Chat = 0
Community, Community,
Wallet, Wallet,
ProfileSettings, ProfileSettings,
NodeManagement, NodeManagement,
CommunitiesPortal CommunitiesPortal,
LoadingSection,
type type
SectionItem* = object SectionItem* = object

View File

@ -53,9 +53,22 @@ proc lookupContactTask(argEncoded: string) {.gcsafe, nimcall.} =
error "error lookupContactTask: ", message = e.msg error "error lookupContactTask: ", message = e.msg
arg.finish(output) arg.finish(output)
################################################# type
# Async request contact info 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 type
AsyncRequestContactInfoTaskArg = ref object of QObjectTaskArg AsyncRequestContactInfoTaskArg = ref object of QObjectTaskArg

View File

@ -68,6 +68,7 @@ type
# Signals which may be emitted by this service: # Signals which may be emitted by this service:
const SIGNAL_ENS_RESOLVED* = "ensResolved" const SIGNAL_ENS_RESOLVED* = "ensResolved"
const SIGNAL_CONTACTS_LOADED* = "contactsLoaded"
const SIGNAL_CONTACT_ADDED* = "contactAdded" const SIGNAL_CONTACT_ADDED* = "contactAdded"
const SIGNAL_CONTACT_BLOCKED* = "contactBlocked" const SIGNAL_CONTACT_BLOCKED* = "contactBlocked"
const SIGNAL_CONTACT_UNBLOCKED* = "contactUnblocked" const SIGNAL_CONTACT_UNBLOCKED* = "contactUnblocked"
@ -142,18 +143,22 @@ QtObject:
self.contactsStatus[contact.dto.id] = StatusUpdateDto(publicKey: contact.dto.id, statusType: StatusType.Unknown) self.contactsStatus[contact.dto.id] = StatusUpdateDto(publicKey: contact.dto.id, statusType: StatusType.Unknown)
proc fetchContacts*(self: Service) = 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: try:
let response = status_contacts.getContacts() let rpcResponseObj = response.parseJson
for elem in rpcResponseObj["response"]["result"].getElems():
let contacts = map(response.result.getElems(), proc(x: JsonNode): ContactsDto = x.toContactsDto()) let contactDto = elem.toContactsDto()
self.addContact(self.constructContactDetails(contactDto))
for contact in contacts: self.events.emit(SIGNAL_CONTACTS_LOADED, Args())
self.addContact(self.constructContactDetails(contact))
except Exception as e: except Exception as e:
let errDesription = e.msg error "error fetching contacts", msg = e.msg
error "error fetching contacts: ", errDesription
return
proc updateAndEmitStatuses(self: Service, statusUpdates: seq[StatusUpdateDto]) = proc updateAndEmitStatuses(self: Service, statusUpdates: seq[StatusUpdateDto]) =
for s in statusUpdates: for s in statusUpdates:
@ -271,37 +276,12 @@ QtObject:
return contacts 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 = proc generateAlias*(self: Service, publicKey: string): string =
if(publicKey.len == 0): if(publicKey.len == 0):
error "cannot generate an alias from the empty public key" error "cannot generate an alias from the empty public key"
return return
return status_accounts.generateAlias(publicKey).result.getStr 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): proc getContactNameAndImageInternal(self: Service, contactDto: ContactsDto):
tuple[name: string, optionalName: string, image: string, largeImage: string] = 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 ## 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: if len(pubkey) == 0:
return 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 # If we try to get the contact details of ourselves, just return our own info
return self.constructContactDetails( return self.constructContactDetails(
ContactsDto( ContactsDto(
@ -355,32 +335,28 @@ QtObject:
## Returns contact details based on passed id (public key) ## 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 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] return self.contacts[pubkey]
result = self.fetchContact(pubkey) if not pubkey.startsWith("0x"):
if result.dto.id.len == 0:
if(not pubkey.startsWith("0x")):
debug "id is not in a hex format" debug "id is not in a hex format"
return return
var num64: int64 var num64: int64
let parsedChars = parseHex(pubkey, num64) let parsedChars = parseHex(pubkey, num64)
if(parsedChars != PK_LENGTH_0X_INCLUDED): if parsedChars != PK_LENGTH_0X_INCLUDED:
debug "id doesn't have expected length" debug "id doesn't have expected length"
return return
let alias = self.generateAlias(pubkey)
let trustStatus = self.getTrustStatus(pubkey)
let contact = self.constructContactDetails( let contact = self.constructContactDetails(
ContactsDto( ContactsDto(
id: pubkey, id: pubkey,
alias: alias, alias: self.generateAlias(pubkey),
ensVerified: result.dto.ensVerified, ensVerified: false,
added: result.dto.added, added: false,
blocked: result.dto.blocked, blocked: false,
hasAddedUs: result.dto.hasAddedUs, hasAddedUs: false,
trustStatus: trustStatus trustStatus: TrustStatus.Unknown,
) )
) )
self.addContact(contact) self.addContact(contact)
@ -562,6 +538,7 @@ QtObject:
checkAndEmitACNotificationsFromResponse(self.events, response.result{"activityCenterNotifications"}) checkAndEmitACNotificationsFromResponse(self.events, response.result{"activityCenterNotifications"})
proc ensResolved*(self: Service, jsonObj: string) {.slot.} = proc ensResolved*(self: Service, jsonObj: string) {.slot.} =
try:
let jsonObj = jsonObj.parseJson() let jsonObj = jsonObj.parseJson()
let data = ResolvedContactArgs( let data = ResolvedContactArgs(
pubkey: jsonObj["id"].getStr, pubkey: jsonObj["id"].getStr,
@ -569,6 +546,8 @@ QtObject:
uuid: jsonObj["uuid"].getStr, uuid: jsonObj["uuid"].getStr,
reason: jsonObj["reason"].getStr) reason: jsonObj["reason"].getStr)
self.events.emit(SIGNAL_ENS_RESOLVED, data) 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 = "") = proc resolveENS*(self: Service, value: string, uuid: string = "", reason = "") =
if(self.closingApp): if(self.closingApp):
@ -635,6 +614,7 @@ QtObject:
error "error in removeTrustStatus request", msg = e.msg error "error in removeTrustStatus request", msg = e.msg
proc asyncContactInfoLoaded*(self: Service, pubkeyAndRpcResponse: string) {.slot.} = proc asyncContactInfoLoaded*(self: Service, pubkeyAndRpcResponse: string) {.slot.} =
try:
let rpcResponseObj = pubkeyAndRpcResponse.parseJson let rpcResponseObj = pubkeyAndRpcResponse.parseJson
let publicKey = rpcResponseObj{"publicKey"}.getStr let publicKey = rpcResponseObj{"publicKey"}.getStr
let requestError = rpcResponseObj{"error"} let requestError = rpcResponseObj{"error"}
@ -655,6 +635,8 @@ QtObject:
let contact = rpcResponseObj{"response"}{"result"}.toContactsDto() let contact = rpcResponseObj{"response"}{"result"}.toContactsDto()
self.saveContact(contact) self.saveContact(contact)
self.events.emit(SIGNAL_CONTACT_INFO_REQUEST_FINISHED, ContactInfoRequestArgs(publicKey: publicKey, ok: true)) 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) = proc requestContactInfo*(self: Service, pubkey: string) =
try: try:

View File

@ -8,10 +8,6 @@ proc getContacts*(): RpcResponse[JsonNode] =
let payload = %* [] let payload = %* []
result = callPrivateRPC("contacts".prefix, 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] = proc blockContact*(id: string): RpcResponse[JsonNode] =
result = callPrivateRPC("blockContactDesktop".prefix, %* [id]) result = callPrivateRPC("blockContactDesktop".prefix, %* [id])
@ -83,10 +79,6 @@ proc removeTrustStatus*(pubkey: string): RpcResponse[JsonNode] =
let payload = %* [pubkey] let payload = %* [pubkey]
result = callPrivateRPC("removeTrustStatus".prefix, payload) 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] = proc retractContactRequest*(pubkey: string): RpcResponse[JsonNode] =
let payload = %*[{ let payload = %*[{
"id": pubkey "id": pubkey

View File

@ -25,7 +25,8 @@ TabButton {
StatusSmartIdenticon { StatusSmartIdenticon {
id: identicon id: identicon
anchors.centerIn: parent 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 ? asset.name: asset.isImage ?
statusIconTabButton.icon.source : statusIconTabButton.icon.name statusIconTabButton.icon.source : statusIconTabButton.icon.name
asset.width: asset.isImage ? 28 : statusIconTabButton.icon.width asset.width: asset.isImage ? 28 : statusIconTabButton.icon.width

View File

@ -815,7 +815,7 @@ Item {
RangeFilter { RangeFilter {
roleName: "sectionType" roleName: "sectionType"
minimumValue: Constants.appSection.wallet minimumValue: Constants.appSection.wallet
maximumValue: Constants.appSection.communitiesPortal maximumValue: Constants.appSection.loadingSection
}, },
ValueFilter { ValueFilter {
roleName: "enabled" roleName: "enabled"

View File

@ -326,6 +326,7 @@ QtObject {
readonly property int profile: 3 readonly property int profile: 3
readonly property int node: 4 readonly property int node: 4
readonly property int communitiesPortal: 5 readonly property int communitiesPortal: 5
readonly property int loadingSection: 6
} }
readonly property QtObject appViewStackIndex: QtObject { readonly property QtObject appViewStackIndex: QtObject {

View File

@ -417,6 +417,8 @@ QtObject {
return qsTr("Node Management") return qsTr("Node Management")
case Constants.appSection.communitiesPortal: case Constants.appSection.communitiesPortal:
return qsTr("Discover Communities") return qsTr("Discover Communities")
case Constants.appSection.loadingSection:
return qsTr("Chat section loading...")
default: default:
return fallback return fallback
} }