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:
parent
36f2bb79a9
commit
27ececad63
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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.} =
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue