Skip to content

Commit

Permalink
perf(contacts): make initial contacts fetching async (#16560)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
jrainville authored Nov 1, 2024
1 parent 36f2bb7 commit 27ececa
Show file tree
Hide file tree
Showing 22 changed files with 206 additions and 189 deletions.
2 changes: 2 additions & 0 deletions src/app/global/app_sections_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 0 additions & 3 deletions src/app/modules/main/chat_section/chat_content/controller.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
5 changes: 1 addition & 4 deletions src/app/modules/main/chat_section/chat_content/module.nim
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)

Expand Down
3 changes: 0 additions & 3 deletions src/app/modules/main/chat_section/chat_content/view.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
6 changes: 0 additions & 6 deletions src/app/modules/main/chat_section/io_interface.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
14 changes: 1 addition & 13 deletions src/app/modules/main/chat_section/module.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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:
Expand Down
25 changes: 0 additions & 25 deletions src/app/modules/main/chat_section/view.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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.} =
Expand Down
20 changes: 17 additions & 3 deletions src/app/modules/main/controller.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions src/app/modules/main/io_interface.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
86 changes: 63 additions & 23 deletions src/app/modules/main/module.nim
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ type
moduleLoaded: bool
chatsLoaded: bool
communityDataLoaded: bool
contactsLoaded: bool
pendingSpectateRequest: SpectateRequest
statusDeepLinkToActivate: string

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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()
Expand All @@ -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,
Expand All @@ -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:
Expand Down Expand Up @@ -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(
Expand Down
3 changes: 3 additions & 0 deletions src/app/modules/main/profile_section/contacts/controller.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
Loading

0 comments on commit 27ececa

Please sign in to comment.