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 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"

View File

@ -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)

View File

@ -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")

View File

@ -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)

View File

@ -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)

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.} =
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")

View File

@ -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:

View File

@ -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.} =

View File

@ -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)

View File

@ -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")

View File

@ -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(

View File

@ -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)

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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)
arg.finish(response)

View File

@ -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:

View File

@ -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

View File

@ -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

View File

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

View File

@ -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 {

View File

@ -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
}