mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-22 11:38:57 +00:00
refactor(@desktop/chat-communities): asynchronous fetching messages
This commit is contained in:
parent
d8dea2dc58
commit
eca74532ac
@ -6,6 +6,7 @@ import ../../app_service/service/contacts/service as contacts_service
|
|||||||
import ../../app_service/service/language/service as language_service
|
import ../../app_service/service/language/service as language_service
|
||||||
import ../../app_service/service/chat/service as chat_service
|
import ../../app_service/service/chat/service as chat_service
|
||||||
import ../../app_service/service/community/service as community_service
|
import ../../app_service/service/community/service as community_service
|
||||||
|
import ../../app_service/service/message/service as message_service
|
||||||
import ../../app_service/service/token/service as token_service
|
import ../../app_service/service/token/service as token_service
|
||||||
import ../../app_service/service/transaction/service as transaction_service
|
import ../../app_service/service/transaction/service as transaction_service
|
||||||
import ../../app_service/service/collectible/service as collectible_service
|
import ../../app_service/service/collectible/service as collectible_service
|
||||||
@ -22,9 +23,11 @@ import ../core/local_account_settings
|
|||||||
import ../../app_service/service/profile/service as profile_service
|
import ../../app_service/service/profile/service as profile_service
|
||||||
import ../../app_service/service/settings/service as settings_service
|
import ../../app_service/service/settings/service as settings_service
|
||||||
import ../../app_service/service/about/service as about_service
|
import ../../app_service/service/about/service as about_service
|
||||||
|
|
||||||
import ../modules/startup/module as startup_module
|
import ../modules/startup/module as startup_module
|
||||||
import ../modules/main/module as main_module
|
import ../modules/main/module as main_module
|
||||||
|
|
||||||
|
import ../core/local_account_settings
|
||||||
import ../core/global_singleton
|
import ../core/global_singleton
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
@ -70,6 +73,7 @@ type
|
|||||||
contactsService: contacts_service.Service
|
contactsService: contacts_service.Service
|
||||||
chatService: chat_service.Service
|
chatService: chat_service.Service
|
||||||
communityService: community_service.Service
|
communityService: community_service.Service
|
||||||
|
messageService: message_service.Service
|
||||||
tokenService: token_service.Service
|
tokenService: token_service.Service
|
||||||
transactionService: transaction_service.Service
|
transactionService: transaction_service.Service
|
||||||
collectibleService: collectible_service.Service
|
collectibleService: collectible_service.Service
|
||||||
@ -136,12 +140,14 @@ proc newAppController*(appService: AppService): AppController =
|
|||||||
result.contactsService = contacts_service.newService(appService.status.events, appService.threadpool)
|
result.contactsService = contacts_service.newService(appService.status.events, appService.threadpool)
|
||||||
result.chatService = chat_service.newService()
|
result.chatService = chat_service.newService()
|
||||||
result.communityService = community_service.newService(result.chatService)
|
result.communityService = community_service.newService(result.chatService)
|
||||||
result.tokenService = token_service.newService(appService.status.events, appService.threadpool, result.settingService, result.settingsService)
|
result.messageService = message_service.newService(appService.status.events, appService.threadpool)
|
||||||
|
result.tokenService = token_service.newService(appService.status.events, appService.threadpool, result.settingService,
|
||||||
|
result.settingsService)
|
||||||
result.collectibleService = collectible_service.newService(result.settingService)
|
result.collectibleService = collectible_service.newService(result.settingService)
|
||||||
result.walletAccountService = wallet_account_service.newService(
|
result.walletAccountService = wallet_account_service.newService(appService.status.events, result.settingService,
|
||||||
appService.status.events, result.settingService, result.tokenService
|
result.tokenService)
|
||||||
)
|
result.transactionService = transaction_service.newService(appService.status.events, appService.threadpool,
|
||||||
result.transactionService = transaction_service.newService(appService.status.events, appService.threadpool, result.walletAccountService)
|
result.walletAccountService)
|
||||||
result.bookmarkService = bookmark_service.newService()
|
result.bookmarkService = bookmark_service.newService()
|
||||||
result.profileService = profile_service.newService()
|
result.profileService = profile_service.newService()
|
||||||
result.aboutService = about_service.newService()
|
result.aboutService = about_service.newService()
|
||||||
@ -173,6 +179,7 @@ proc newAppController*(appService: AppService): AppController =
|
|||||||
result.accountsService,
|
result.accountsService,
|
||||||
result.chatService,
|
result.chatService,
|
||||||
result.communityService,
|
result.communityService,
|
||||||
|
result.messageService,
|
||||||
result.tokenService,
|
result.tokenService,
|
||||||
result.transactionService,
|
result.transactionService,
|
||||||
result.collectibleService,
|
result.collectibleService,
|
||||||
@ -288,7 +295,7 @@ proc load(self: AppController) =
|
|||||||
self.buildAndRegisterUserProfile()
|
self.buildAndRegisterUserProfile()
|
||||||
|
|
||||||
# load main module
|
# load main module
|
||||||
self.mainModule.load(self.chatService, self.communityService)
|
self.mainModule.load(self.appService.status.events, self.chatService, self.communityService, self.messageService)
|
||||||
|
|
||||||
proc userLoggedIn*(self: AppController) =
|
proc userLoggedIn*(self: AppController) =
|
||||||
#################################################
|
#################################################
|
||||||
|
@ -5,6 +5,7 @@ import io_interface
|
|||||||
|
|
||||||
import ../../../../app_service/service/chat/service as chat_service
|
import ../../../../app_service/service/chat/service as chat_service
|
||||||
import ../../../../app_service/service/community/service as community_service
|
import ../../../../app_service/service/community/service as community_service
|
||||||
|
import ../../../../app_service/service/message/service as message_service
|
||||||
|
|
||||||
export controller_interface
|
export controller_interface
|
||||||
|
|
||||||
@ -17,16 +18,19 @@ type
|
|||||||
activeSubItemId: string
|
activeSubItemId: string
|
||||||
chatService: chat_service.ServiceInterface
|
chatService: chat_service.ServiceInterface
|
||||||
communityService: community_service.ServiceInterface
|
communityService: community_service.ServiceInterface
|
||||||
|
messageService: message_service.Service
|
||||||
|
|
||||||
proc newController*(delegate: io_interface.AccessInterface, id: string, isCommunity: bool,
|
proc newController*(delegate: io_interface.AccessInterface, id: string, isCommunity: bool,
|
||||||
chatService: chat_service.ServiceInterface,
|
chatService: chat_service.ServiceInterface,
|
||||||
communityService: community_service.ServiceInterface): Controller =
|
communityService: community_service.ServiceInterface,
|
||||||
|
messageService: message_service.Service): Controller =
|
||||||
result = Controller()
|
result = Controller()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
result.id = id
|
result.id = id
|
||||||
result.isCommunityModule = isCommunity
|
result.isCommunityModule = isCommunity
|
||||||
result.chatService = chatService
|
result.chatService = chatService
|
||||||
result.communityService = communityService
|
result.communityService = communityService
|
||||||
|
result.messageService = messageService
|
||||||
|
|
||||||
method delete*(self: Controller) =
|
method delete*(self: Controller) =
|
||||||
discard
|
discard
|
||||||
@ -60,6 +64,11 @@ method setActiveItemSubItem*(self: Controller, itemId: string, subItemId: string
|
|||||||
self.activeItemId = itemId
|
self.activeItemId = itemId
|
||||||
self.activeSubItemId = subItemId
|
self.activeSubItemId = subItemId
|
||||||
|
|
||||||
|
if(self.activeSubItemId.len > 0):
|
||||||
|
self.messageService.loadInitialMessagesForChat(self.activeSubItemId)
|
||||||
|
else:
|
||||||
|
self.messageService.loadInitialMessagesForChat(self.activeItemId)
|
||||||
|
|
||||||
# We need to take other actions here like notify status go that unviewed mentions count is updated and so...
|
# We need to take other actions here like notify status go that unviewed mentions count is updated and so...
|
||||||
|
|
||||||
self.delegate.activeItemSubItemSet(self.activeItemId, self.activeSubItemId)
|
self.delegate.activeItemSubItemSet(self.activeItemId, self.activeSubItemId)
|
@ -2,29 +2,39 @@ import controller_interface
|
|||||||
import io_interface
|
import io_interface
|
||||||
|
|
||||||
import ../../../../../app_service/service/community/service as community_service
|
import ../../../../../app_service/service/community/service as community_service
|
||||||
|
import ../../../../../app_service/service/message/service as message_service
|
||||||
|
|
||||||
|
import eventemitter
|
||||||
|
import status/[signals]
|
||||||
|
|
||||||
export controller_interface
|
export controller_interface
|
||||||
|
|
||||||
type
|
type
|
||||||
Controller* = ref object of controller_interface.AccessInterface
|
Controller* = ref object of controller_interface.AccessInterface
|
||||||
delegate: io_interface.AccessInterface
|
delegate: io_interface.AccessInterface
|
||||||
|
events: EventEmitter
|
||||||
id: string
|
id: string
|
||||||
isCommunityModule: bool
|
isCommunityModule: bool
|
||||||
communityService: community_service.ServiceInterface
|
communityService: community_service.ServiceInterface
|
||||||
|
messageService: message_service.Service
|
||||||
|
|
||||||
proc newController*(delegate: io_interface.AccessInterface, id: string, isCommunity: bool,
|
proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter, id: string, isCommunity: bool,
|
||||||
communityService: community_service.ServiceInterface): Controller =
|
communityService: community_service.ServiceInterface, messageService: message_service.Service): Controller =
|
||||||
result = Controller()
|
result = Controller()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
|
result.events = events
|
||||||
result.id = id
|
result.id = id
|
||||||
result.isCommunityModule = isCommunity
|
result.isCommunityModule = isCommunity
|
||||||
result.communityService = communityService
|
result.communityService = communityService
|
||||||
|
result.messageService = messageService
|
||||||
|
|
||||||
method delete*(self: Controller) =
|
method delete*(self: Controller) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
method init*(self: Controller) =
|
method init*(self: Controller) =
|
||||||
discard
|
self.events.on(SIGNAL_MESSAGES_LOADED) do(e:Args):
|
||||||
|
let args = MessagesLoadedArgs(e)
|
||||||
|
echo "RECEIVED MESSAGES ASYNC: ", repr(args)
|
||||||
|
|
||||||
method getId*(self: Controller): string =
|
method getId*(self: Controller): string =
|
||||||
return self.id
|
return self.id
|
||||||
|
@ -1,21 +1,77 @@
|
|||||||
import NimQml
|
type
|
||||||
|
ContentType* {.pure.} = enum
|
||||||
|
FetchMoreMessagesButton = -2
|
||||||
|
ChatIdentifier = -1
|
||||||
|
Unknown = 0
|
||||||
|
Message = 1
|
||||||
|
Sticker = 2
|
||||||
|
Status = 3
|
||||||
|
Emoji = 4
|
||||||
|
Transaction = 5
|
||||||
|
Group = 6
|
||||||
|
Image = 7
|
||||||
|
Audio = 8
|
||||||
|
Community = 9
|
||||||
|
Gap = 10
|
||||||
|
Edit = 11
|
||||||
|
|
||||||
QtObject:
|
type
|
||||||
type
|
Item* = object
|
||||||
Item* = ref object of QObject
|
id: string
|
||||||
|
`from`: string
|
||||||
proc setup(self: Item) =
|
alias: string
|
||||||
self.QObject.setup
|
identicon: string
|
||||||
|
seen: bool
|
||||||
|
outgoingStatus: string
|
||||||
|
text: string
|
||||||
|
stickerHash: string
|
||||||
|
stickerPack: int
|
||||||
|
image: string
|
||||||
|
gapFrom: int64
|
||||||
|
gapTo: int64
|
||||||
|
timestamp: int64
|
||||||
|
contentType: ContentType
|
||||||
|
messageType: int
|
||||||
|
|
||||||
proc delete*(self: Item) =
|
proc initItem*(id, `from`, alias, identicon, outgoingStatus, text: string, seen: bool, timestamp: int64,
|
||||||
self.QObject.delete
|
contentType: ContentType, messageType: int): Item =
|
||||||
|
result.id = id
|
||||||
|
result.`from` = `from`
|
||||||
|
result.alias = alias
|
||||||
|
result.identicon = identicon
|
||||||
|
result.seen = seen
|
||||||
|
result.outgoingStatus = outgoingStatus
|
||||||
|
result.text = text
|
||||||
|
result.timestamp = timestamp
|
||||||
|
result.contentType = contentType
|
||||||
|
result.messageType = messageType
|
||||||
|
|
||||||
proc newItem*(): Item =
|
proc id*(self: Item): string {.inline.} =
|
||||||
new(result, delete)
|
self.id
|
||||||
result.setup()
|
|
||||||
|
|
||||||
proc id*(self: Item): string {.slot.} =
|
proc `from`*(self: Item): string {.inline.} =
|
||||||
self.id
|
self.`from`
|
||||||
|
|
||||||
QtProperty[string] id:
|
proc alias*(self: Item): string {.inline.} =
|
||||||
read = id
|
self.alias
|
||||||
|
|
||||||
|
proc identicon*(self: Item): string {.inline.} =
|
||||||
|
self.identicon
|
||||||
|
|
||||||
|
proc outgoingStatus*(self: Item): string {.inline.} =
|
||||||
|
self.outgoingStatus
|
||||||
|
|
||||||
|
proc text*(self: Item): string {.inline.} =
|
||||||
|
self.text
|
||||||
|
|
||||||
|
proc seen*(self: Item): bool {.inline.} =
|
||||||
|
self.seen
|
||||||
|
|
||||||
|
proc timestamp*(self: Item): int64 {.inline.} =
|
||||||
|
self.timestamp
|
||||||
|
|
||||||
|
proc contentType*(self: Item): ContentType {.inline.} =
|
||||||
|
self.contentType
|
||||||
|
|
||||||
|
proc messageType*(self: Item): int {.inline.} =
|
||||||
|
self.messageType
|
@ -1,17 +1,101 @@
|
|||||||
import NimQml
|
import NimQml, Tables, strutils, strformat
|
||||||
|
|
||||||
import item
|
import item
|
||||||
|
|
||||||
|
type
|
||||||
|
ModelRole {.pure.} = enum
|
||||||
|
Id = UserRole + 1
|
||||||
|
From
|
||||||
|
Alias
|
||||||
|
Identicon
|
||||||
|
Seen
|
||||||
|
OutgoingStatus
|
||||||
|
Text
|
||||||
|
Timestamp
|
||||||
|
ContentType
|
||||||
|
MessageType
|
||||||
|
# StickerHash
|
||||||
|
# StickerPack
|
||||||
|
# Image
|
||||||
|
# GapFrom
|
||||||
|
# GapTo
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
Model* = ref object of QAbstractListModel
|
Model* = ref object of QAbstractListModel
|
||||||
sections: seq[Item]
|
items: seq[Item]
|
||||||
|
|
||||||
proc setup(self: Model) =
|
proc delete(self: Model) =
|
||||||
self.QAbstractListModel.setup
|
self.items = @[]
|
||||||
|
|
||||||
proc delete*(self: Model) =
|
|
||||||
self.QAbstractListModel.delete
|
self.QAbstractListModel.delete
|
||||||
|
|
||||||
|
proc setup(self: Model) =
|
||||||
|
self.QAbstractListModel.setup
|
||||||
|
|
||||||
proc newModel*(): Model =
|
proc newModel*(): Model =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.setup
|
result.setup
|
||||||
|
|
||||||
|
method rowCount(self: Model, index: QModelIndex = nil): int =
|
||||||
|
return self.items.len
|
||||||
|
|
||||||
|
method roleNames(self: Model): Table[int, string] =
|
||||||
|
{
|
||||||
|
ModelRole.Id.int:"id",
|
||||||
|
ModelRole.From.int:"from",
|
||||||
|
ModelRole.Alias.int:"alias",
|
||||||
|
ModelRole.Identicon.int:"identicon",
|
||||||
|
ModelRole.Seen.int:"seen",
|
||||||
|
ModelRole.OutgoingStatus.int:"outgoingStatus",
|
||||||
|
ModelRole.Text.int:"text",
|
||||||
|
ModelRole.Timestamp.int:"timestamp",
|
||||||
|
ModelRole.ContentType.int:"contentType",
|
||||||
|
ModelRole.MessageType.int:"messageType",
|
||||||
|
# ModelRole.StickerHash.int:"stickerHash",
|
||||||
|
# ModelRole.StickerPack.int:"stickerPack",
|
||||||
|
# ModelRole.Image.int:"image",
|
||||||
|
# ModelRole.GapFrom.int:"gapFrom",
|
||||||
|
# ModelRole.GapTo.int:"gapTo"
|
||||||
|
}.toTable
|
||||||
|
|
||||||
|
method data(self: Model, index: QModelIndex, role: int): QVariant =
|
||||||
|
if (not index.isValid):
|
||||||
|
return
|
||||||
|
|
||||||
|
if (index.row < 0 or index.row >= self.items.len):
|
||||||
|
return
|
||||||
|
|
||||||
|
let item = self.items[index.row]
|
||||||
|
let enumRole = role.ModelRole
|
||||||
|
|
||||||
|
case enumRole:
|
||||||
|
of ModelRole.Id:
|
||||||
|
result = newQVariant(item.id)
|
||||||
|
of ModelRole.From:
|
||||||
|
result = newQVariant(item.`from`)
|
||||||
|
of ModelRole.Alias:
|
||||||
|
result = newQVariant(item.alias)
|
||||||
|
of ModelRole.Identicon:
|
||||||
|
result = newQVariant(item.identicon)
|
||||||
|
of ModelRole.Seen:
|
||||||
|
result = newQVariant(item.seen)
|
||||||
|
of ModelRole.OutgoingStatus:
|
||||||
|
result = newQVariant(item.outgoingStatus)
|
||||||
|
of ModelRole.Text:
|
||||||
|
result = newQVariant(item.text)
|
||||||
|
of ModelRole.Timestamp:
|
||||||
|
result = newQVariant(item.timestamp)
|
||||||
|
of ModelRole.ContentType:
|
||||||
|
result = newQVariant(item.contentType.int)
|
||||||
|
of ModelRole.MessageType:
|
||||||
|
result = newQVariant(item.messageType)
|
||||||
|
# of ModelRole.StickerHash:
|
||||||
|
# result = newQVariant(item.stickerHash)
|
||||||
|
# of ModelRole.StickerPack:
|
||||||
|
# result = newQVariant(item.stickerPack)
|
||||||
|
# of ModelRole.Image:
|
||||||
|
# result = newQVariant(item.image)
|
||||||
|
# of ModelRole.GapFrom:
|
||||||
|
# result = newQVariant(item.gapFrom)
|
||||||
|
# of ModelRole.GapTo:
|
||||||
|
# result = newQVariant(item.gapTo)
|
@ -6,6 +6,9 @@ import ../../../../core/global_singleton
|
|||||||
|
|
||||||
import ../../../../../app_service/service/chat/service as chat_service
|
import ../../../../../app_service/service/chat/service as chat_service
|
||||||
import ../../../../../app_service/service/community/service as community_service
|
import ../../../../../app_service/service/community/service as community_service
|
||||||
|
import ../../../../../app_service/service/message/service as message_service
|
||||||
|
|
||||||
|
import eventemitter
|
||||||
|
|
||||||
export io_interface
|
export io_interface
|
||||||
|
|
||||||
@ -17,14 +20,14 @@ type
|
|||||||
controller: controller.AccessInterface
|
controller: controller.AccessInterface
|
||||||
moduleLoaded: bool
|
moduleLoaded: bool
|
||||||
|
|
||||||
proc newModule*(delegate: delegate_interface.AccessInterface, id: string, isCommunity: bool,
|
proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, id: string, isCommunity: bool,
|
||||||
chatService: chat_service.Service, communityService: community_service.Service):
|
chatService: chat_service.Service, communityService: community_service.Service, messageService: message_service.Service):
|
||||||
Module =
|
Module =
|
||||||
result = Module()
|
result = Module()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
result.view = view.newView(result)
|
result.view = view.newView(result)
|
||||||
result.viewVariant = newQVariant(result.view)
|
result.viewVariant = newQVariant(result.view)
|
||||||
result.controller = controller.newController(result, id, isCommunity, communityService)
|
result.controller = controller.newController(result, events, id, isCommunity, communityService, messageService)
|
||||||
result.moduleLoaded = false
|
result.moduleLoaded = false
|
||||||
|
|
||||||
method delete*(self: Module) =
|
method delete*(self: Module) =
|
||||||
|
@ -10,6 +10,9 @@ import users/module as users_module
|
|||||||
|
|
||||||
import ../../../../app_service/service/chat/service as chat_service
|
import ../../../../app_service/service/chat/service as chat_service
|
||||||
import ../../../../app_service/service/community/service as community_service
|
import ../../../../app_service/service/community/service as community_service
|
||||||
|
import ../../../../app_service/service/message/service as message_service
|
||||||
|
|
||||||
|
import eventemitter
|
||||||
|
|
||||||
export io_interface
|
export io_interface
|
||||||
|
|
||||||
@ -27,18 +30,20 @@ type
|
|||||||
usersModule: users_module.AccessInterface
|
usersModule: users_module.AccessInterface
|
||||||
moduleLoaded: bool
|
moduleLoaded: bool
|
||||||
|
|
||||||
proc newModule*(delegate: delegate_interface.AccessInterface, id: string, isCommunity: bool,
|
proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, id: string, isCommunity: bool,
|
||||||
chatService: chat_service.Service, communityService: community_service.Service):
|
chatService: chat_service.Service, communityService: community_service.Service,
|
||||||
|
messageService: message_service.Service):
|
||||||
Module =
|
Module =
|
||||||
result = Module()
|
result = Module()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
result.view = view.newView(result)
|
result.view = view.newView(result)
|
||||||
result.viewVariant = newQVariant(result.view)
|
result.viewVariant = newQVariant(result.view)
|
||||||
result.controller = controller.newController(result, id, isCommunity, chatService, communityService)
|
result.controller = controller.newController(result, id, isCommunity, chatService, communityService, messageService)
|
||||||
result.moduleLoaded = false
|
result.moduleLoaded = false
|
||||||
|
|
||||||
result.inputAreaModule = input_area_module.newModule(result, id, isCommunity, chatService, communityService)
|
result.inputAreaModule = input_area_module.newModule(result, id, isCommunity, chatService, communityService)
|
||||||
result.messagesModule = messages_module.newModule(result, id, isCommunity, chatService, communityService)
|
result.messagesModule = messages_module.newModule(result, events, id, isCommunity, chatService, communityService,
|
||||||
|
messageService)
|
||||||
result.usersModule = users_module.newModule(result, id, isCommunity, chatService, communityService)
|
result.usersModule = users_module.newModule(result, id, isCommunity, chatService, communityService)
|
||||||
|
|
||||||
method delete*(self: Module) =
|
method delete*(self: Module) =
|
||||||
@ -62,7 +67,7 @@ proc buildChatUI(self: Module) =
|
|||||||
if(selectedItemId.len == 0):
|
if(selectedItemId.len == 0):
|
||||||
selectedItemId = item.id
|
selectedItemId = item.id
|
||||||
|
|
||||||
self.controller.setActiveItemSubItem(selectedItemId, "")
|
self.setActiveItemSubItem(selectedItemId, "")
|
||||||
|
|
||||||
proc buildCommunityUI(self: Module) =
|
proc buildCommunityUI(self: Module) =
|
||||||
var selectedItemId = ""
|
var selectedItemId = ""
|
||||||
|
@ -44,6 +44,13 @@ method delete*(self: Controller) =
|
|||||||
discard
|
discard
|
||||||
|
|
||||||
method init*(self: Controller) =
|
method init*(self: Controller) =
|
||||||
|
self.events.on("mailserverAvailable") do(e:Args):
|
||||||
|
echo "MAILSERVER AVAILABLE: ", repr(e)
|
||||||
|
# We need to take some actions here. This is the only pace where "mailserverAvailable" signal should be handled.
|
||||||
|
# Do the following, if we really need that.
|
||||||
|
# requestAllHistoricMessagesResult
|
||||||
|
# requestMissingCommunityInfos
|
||||||
|
|
||||||
if(defined(macosx)):
|
if(defined(macosx)):
|
||||||
let account = self.accountsService.getLoggedInAccount()
|
let account = self.accountsService.getLoggedInAccount()
|
||||||
singletonInstance.localAccountSettings.setFileName(account.name)
|
singletonInstance.localAccountSettings.setFileName(account.name)
|
||||||
|
@ -11,6 +11,7 @@ import profile_section/module as profile_section_module
|
|||||||
import ../../../app_service/service/keychain/service as keychain_service
|
import ../../../app_service/service/keychain/service as keychain_service
|
||||||
import ../../../app_service/service/chat/service as chat_service
|
import ../../../app_service/service/chat/service as chat_service
|
||||||
import ../../../app_service/service/community/service as community_service
|
import ../../../app_service/service/community/service as community_service
|
||||||
|
import ../../../app_service/service/message/service as message_service
|
||||||
import ../../../app_service/service/token/service as token_service
|
import ../../../app_service/service/token/service as token_service
|
||||||
import ../../../app_service/service/transaction/service as transaction_service
|
import ../../../app_service/service/transaction/service as transaction_service
|
||||||
import ../../../app_service/service/collectible/service as collectible_service
|
import ../../../app_service/service/collectible/service as collectible_service
|
||||||
@ -20,7 +21,6 @@ import ../../../app_service/service/bookmarks/service as bookmark_service
|
|||||||
import ../../../app_service/service/dapp_permissions/service as dapp_permissions_service
|
import ../../../app_service/service/dapp_permissions/service as dapp_permissions_service
|
||||||
import ../../../app_service/service/provider/service as provider_service
|
import ../../../app_service/service/provider/service as provider_service
|
||||||
|
|
||||||
import eventemitter
|
|
||||||
import ../../../app_service/service/profile/service as profile_service
|
import ../../../app_service/service/profile/service as profile_service
|
||||||
import ../../../app_service/service/accounts/service as accounts_service
|
import ../../../app_service/service/accounts/service as accounts_service
|
||||||
import ../../../app_service/service/settings/service as settings_service
|
import ../../../app_service/service/settings/service as settings_service
|
||||||
@ -30,6 +30,8 @@ import ../../../app_service/service/language/service as language_service
|
|||||||
import ../../../app_service/service/mnemonic/service as mnemonic_service
|
import ../../../app_service/service/mnemonic/service as mnemonic_service
|
||||||
import ../../../app_service/service/privacy/service as privacy_service
|
import ../../../app_service/service/privacy/service as privacy_service
|
||||||
|
|
||||||
|
import eventemitter
|
||||||
|
|
||||||
export io_interface
|
export io_interface
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -52,6 +54,7 @@ proc newModule*[T](
|
|||||||
accountsService: accounts_service.ServiceInterface,
|
accountsService: accounts_service.ServiceInterface,
|
||||||
chatService: chat_service.Service,
|
chatService: chat_service.Service,
|
||||||
communityService: community_service.Service,
|
communityService: community_service.Service,
|
||||||
|
messageService: message_service.Service,
|
||||||
tokenService: token_service.Service,
|
tokenService: token_service.Service,
|
||||||
transactionService: transaction_service.Service,
|
transactionService: transaction_service.Service,
|
||||||
collectibleService: collectible_service.Service,
|
collectibleService: collectible_service.Service,
|
||||||
@ -77,7 +80,8 @@ proc newModule*[T](
|
|||||||
result.moduleLoaded = false
|
result.moduleLoaded = false
|
||||||
|
|
||||||
# Submodules
|
# Submodules
|
||||||
result.chatSectionModule = chat_section_module.newModule(result, "chat", false, chatService, communityService)
|
result.chatSectionModule = chat_section_module.newModule(result, events, "chat", false, chatService, communityService,
|
||||||
|
messageService)
|
||||||
result.communitySectionsModule = initOrderedTable[string, chat_section_module.AccessInterface]()
|
result.communitySectionsModule = initOrderedTable[string, chat_section_module.AccessInterface]()
|
||||||
result.walletSectionModule = wallet_section_module.newModule[Module[T]](result, events, tokenService,
|
result.walletSectionModule = wallet_section_module.newModule[Module[T]](result, events, tokenService,
|
||||||
transactionService, collectible_service, walletAccountService, settingService)
|
transactionService, collectible_service, walletAccountService, settingService)
|
||||||
@ -98,8 +102,8 @@ method delete*[T](self: Module[T]) =
|
|||||||
self.viewVariant.delete
|
self.viewVariant.delete
|
||||||
self.controller.delete
|
self.controller.delete
|
||||||
|
|
||||||
method load*[T](self: Module[T], chatService: chat_service.Service,
|
method load*[T](self: Module[T], events: EventEmitter, chatService: chat_service.Service,
|
||||||
communityService: community_service.Service) =
|
communityService: community_service.Service, messageService: message_service.Service) =
|
||||||
singletonInstance.engine.setRootContextProperty("mainModule", self.viewVariant)
|
singletonInstance.engine.setRootContextProperty("mainModule", self.viewVariant)
|
||||||
self.controller.init()
|
self.controller.init()
|
||||||
self.view.load()
|
self.view.load()
|
||||||
@ -107,7 +111,8 @@ method load*[T](self: Module[T], chatService: chat_service.Service,
|
|||||||
# Create community modules here, since we don't know earlier how many communities we have.
|
# Create community modules here, since we don't know earlier how many communities we have.
|
||||||
let communities = self.controller.getCommunities()
|
let communities = self.controller.getCommunities()
|
||||||
for c in communities:
|
for c in communities:
|
||||||
self.communitySectionsModule[c.id] = chat_section_module.newModule(self, c.id, true, chatService, communityService)
|
self.communitySectionsModule[c.id] = chat_section_module.newModule(self, events, c.id, true, chatService,
|
||||||
|
communityService, messageService)
|
||||||
|
|
||||||
var activeSection: Item
|
var activeSection: Item
|
||||||
var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection()
|
var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection()
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import ../../../../app_service/service/chat/service as chat_service
|
import ../../../../app_service/service/chat/service as chat_service
|
||||||
import ../../../../app_service/service/community/service as community_service
|
import ../../../../app_service/service/community/service as community_service
|
||||||
|
import ../../../../app_service/service/message/service as message_service
|
||||||
|
|
||||||
|
import eventemitter
|
||||||
|
|
||||||
method delete*(self: AccessInterface) {.base.} =
|
method delete*(self: AccessInterface) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method load*(self: AccessInterface, chatService: chat_service.Service, communityService: community_service.Service,)
|
method load*(self: AccessInterface, events: EventEmitter, chatService: chat_service.Service, communityService: community_service.Service,
|
||||||
|
messageService: message_service.Service)
|
||||||
{.base.} =
|
{.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
46
src/app_service/service/message/async_tasks.nim
Normal file
46
src/app_service/service/message/async_tasks.nim
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
include ../../common/json_utils
|
||||||
|
include ../../tasks/common
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Async load messages
|
||||||
|
#################################################
|
||||||
|
type
|
||||||
|
AsyncFetchChatMessagesTaskArg = ref object of QObjectTaskArg
|
||||||
|
chatId: string
|
||||||
|
msgCursor: string
|
||||||
|
pinnedMsgCursor: string
|
||||||
|
limit: int
|
||||||
|
|
||||||
|
const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[AsyncFetchChatMessagesTaskArg](argEncoded)
|
||||||
|
|
||||||
|
# handle messages
|
||||||
|
var messagesArr: JsonNode
|
||||||
|
var messagesCursor: string
|
||||||
|
let msgsResponse = status_go.fetchMessages(arg.chatId, arg.msgCursor, arg.limit)
|
||||||
|
discard msgsResponse.result.getProp("cursor", messagesCursor)
|
||||||
|
discard msgsResponse.result.getProp("messages", messagesArr)
|
||||||
|
|
||||||
|
# handle pinned messages
|
||||||
|
var pinnedMsgArr: JsonNode
|
||||||
|
var pinnedMsgCursor: string
|
||||||
|
let pinnedMsgsResponse = status_go.fetchPinnedMessages(arg.chatId, arg.pinnedMsgCursor, arg.limit)
|
||||||
|
discard pinnedMsgsResponse.result.getProp("cursor", pinnedMsgCursor)
|
||||||
|
discard pinnedMsgsResponse.result.getProp("pinnedMessages", pinnedMsgArr)
|
||||||
|
|
||||||
|
# handle reactions
|
||||||
|
var reactionsArr: JsonNode
|
||||||
|
# messages and reactions are using the same cursor
|
||||||
|
let rResponse = status_go.fetchReactions(arg.chatId, arg.msgCursor, arg.limit)
|
||||||
|
reactionsArr = rResponse.result
|
||||||
|
|
||||||
|
let responseJson = %*{
|
||||||
|
"chatId": arg.chatId,
|
||||||
|
"messages": messagesArr,
|
||||||
|
"messagesCursor": messagesCursor,
|
||||||
|
"pinnedMessages": pinnedMsgArr,
|
||||||
|
"pinnedMessagesCursor": pinnedMsgCursor,
|
||||||
|
"reactions": reactionsArr
|
||||||
|
}
|
||||||
|
|
||||||
|
arg.finish(responseJson)
|
100
src/app_service/service/message/dto/message.nim
Normal file
100
src/app_service/service/message/dto/message.nim
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
{.used.}
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
include ../../../common/json_utils
|
||||||
|
|
||||||
|
type QuotedMessage* = object
|
||||||
|
`from`*: string
|
||||||
|
text*: string
|
||||||
|
#parsedText*: Not sure if we use it
|
||||||
|
|
||||||
|
type Sticker* = object
|
||||||
|
hash*: string
|
||||||
|
pack*: int
|
||||||
|
|
||||||
|
type GapParameters* = object
|
||||||
|
`from`*: int64
|
||||||
|
to*: int64
|
||||||
|
|
||||||
|
type MessageDto* = object
|
||||||
|
id*: string
|
||||||
|
whisperTimestamp*: int64
|
||||||
|
`from`*: string
|
||||||
|
alias*: string
|
||||||
|
identicon*: string
|
||||||
|
seen*: bool
|
||||||
|
outgoingStatus*: string
|
||||||
|
quotedMessage*: QuotedMessage
|
||||||
|
rtl*: bool
|
||||||
|
#parsedText*: Not sure if we use it
|
||||||
|
lineCount*: int
|
||||||
|
text*: string
|
||||||
|
chatId*: string
|
||||||
|
localChatId*: string
|
||||||
|
clock*: int64
|
||||||
|
replace*: string
|
||||||
|
responseTo*: string
|
||||||
|
ensName*: string
|
||||||
|
sticker*: Sticker
|
||||||
|
image*: string
|
||||||
|
gapParameters*: GapParameters
|
||||||
|
timestamp*: int64
|
||||||
|
contentType*: int
|
||||||
|
messageType*: int
|
||||||
|
links*: seq[string]
|
||||||
|
|
||||||
|
proc toQuotedMessage*(jsonObj: JsonNode): QuotedMessage =
|
||||||
|
result = QuotedMessage()
|
||||||
|
discard jsonObj.getProp("from", result.from)
|
||||||
|
discard jsonObj.getProp("text", result.text)
|
||||||
|
|
||||||
|
proc toSticker*(jsonObj: JsonNode): Sticker =
|
||||||
|
result = Sticker()
|
||||||
|
discard jsonObj.getProp("hash", result.hash)
|
||||||
|
discard jsonObj.getProp("pack", result.pack)
|
||||||
|
|
||||||
|
proc toGapParameters*(jsonObj: JsonNode): GapParameters =
|
||||||
|
result = GapParameters()
|
||||||
|
discard jsonObj.getProp("from", result.from)
|
||||||
|
discard jsonObj.getProp("to", result.to)
|
||||||
|
|
||||||
|
proc toMessageDto*(jsonObj: JsonNode): MessageDto =
|
||||||
|
result = MessageDto()
|
||||||
|
discard jsonObj.getProp("id", result.id)
|
||||||
|
discard jsonObj.getProp("whisperTimestamp", result.whisperTimestamp)
|
||||||
|
discard jsonObj.getProp("from", result.from)
|
||||||
|
discard jsonObj.getProp("alias", result.alias)
|
||||||
|
discard jsonObj.getProp("identicon", result.identicon)
|
||||||
|
discard jsonObj.getProp("seen", result.seen)
|
||||||
|
discard jsonObj.getProp("outgoingStatus", result.outgoingStatus)
|
||||||
|
discard jsonObj.getProp("rtl", result.rtl)
|
||||||
|
discard jsonObj.getProp("lineCount", result.lineCount)
|
||||||
|
discard jsonObj.getProp("text", result.text)
|
||||||
|
discard jsonObj.getProp("chatId", result.chatId)
|
||||||
|
discard jsonObj.getProp("localChatId", result.localChatId)
|
||||||
|
discard jsonObj.getProp("clock", result.clock)
|
||||||
|
discard jsonObj.getProp("replace", result.replace)
|
||||||
|
discard jsonObj.getProp("responseTo", result.responseTo)
|
||||||
|
discard jsonObj.getProp("ensName", result.ensName)
|
||||||
|
discard jsonObj.getProp("timestamp", result.timestamp)
|
||||||
|
discard jsonObj.getProp("contentType", result.contentType)
|
||||||
|
discard jsonObj.getProp("messageType", result.messageType)
|
||||||
|
discard jsonObj.getProp("image", result.image)
|
||||||
|
|
||||||
|
var quotedMessageObj: JsonNode
|
||||||
|
if(jsonObj.getProp("quotedMessage", quotedMessageObj)):
|
||||||
|
result.quotedMessage = toQuotedMessage(quotedMessageObj)
|
||||||
|
|
||||||
|
var stickerObj: JsonNode
|
||||||
|
if(jsonObj.getProp("sticker", stickerObj)):
|
||||||
|
result.sticker = toSticker(stickerObj)
|
||||||
|
|
||||||
|
var gapParametersObj: JsonNode
|
||||||
|
if(jsonObj.getProp("gapParameters", gapParametersObj)):
|
||||||
|
result.gapParameters = toGapParameters(gapParametersObj)
|
||||||
|
|
||||||
|
var linksArr: JsonNode
|
||||||
|
if(jsonObj.getProp("links", linksArr)):
|
||||||
|
for link in linksArr:
|
||||||
|
result.links.add(link.getStr)
|
21
src/app_service/service/message/dto/pinnedMessage.nim
Normal file
21
src/app_service/service/message/dto/pinnedMessage.nim
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{.used.}
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import message
|
||||||
|
|
||||||
|
include ../../../common/json_utils
|
||||||
|
|
||||||
|
type PinnedMessageDto* = object
|
||||||
|
pinnedAt*: int64
|
||||||
|
pinnedBy*: string
|
||||||
|
message*: MessageDto
|
||||||
|
|
||||||
|
proc toPinnedMessageDto*(jsonObj: JsonNode): PinnedMessageDto =
|
||||||
|
result = PinnedMessageDto()
|
||||||
|
discard jsonObj.getProp("pinnedAt", result.pinnedAt)
|
||||||
|
discard jsonObj.getProp("pinnedBy", result.pinnedBy)
|
||||||
|
|
||||||
|
var messageObj: JsonNode
|
||||||
|
if(jsonObj.getProp("message", messageObj)):
|
||||||
|
result.message = toMessageDto(messageObj)
|
24
src/app_service/service/message/dto/reaction.nim
Normal file
24
src/app_service/service/message/dto/reaction.nim
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{.used.}
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
include ../../../common/json_utils
|
||||||
|
|
||||||
|
type ReactionDto* = object
|
||||||
|
id*: string
|
||||||
|
clock*: int64
|
||||||
|
chatId*: string
|
||||||
|
localChatId*: string
|
||||||
|
`from`*: string
|
||||||
|
messageId*: string
|
||||||
|
emojiId*: int
|
||||||
|
|
||||||
|
proc toReactionDto*(jsonObj: JsonNode): ReactionDto =
|
||||||
|
result = ReactionDto()
|
||||||
|
discard jsonObj.getProp("id", result.id)
|
||||||
|
discard jsonObj.getProp("clock", result.clock)
|
||||||
|
discard jsonObj.getProp("chatId", result.chatId)
|
||||||
|
discard jsonObj.getProp("localChatId", result.localChatId)
|
||||||
|
discard jsonObj.getProp("from", result.from)
|
||||||
|
discard jsonObj.getProp("messageId", result.messageId)
|
||||||
|
discard jsonObj.getProp("emojiId", result.emojiId)
|
133
src/app_service/service/message/service.nim
Normal file
133
src/app_service/service/message/service.nim
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import NimQml, tables, json, sequtils, chronicles
|
||||||
|
|
||||||
|
import eventemitter
|
||||||
|
import ../../tasks/[qt, threadpool]
|
||||||
|
|
||||||
|
import status/statusgo_backend_new/messages as status_go
|
||||||
|
|
||||||
|
import ./dto/message as message_dto
|
||||||
|
import ./dto/pinnedMessage as pinned_msg_dto
|
||||||
|
import ./dto/reaction as reaction_dto
|
||||||
|
|
||||||
|
export message_dto
|
||||||
|
export pinned_msg_dto
|
||||||
|
export reaction_dto
|
||||||
|
|
||||||
|
include async_tasks
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "messages-service"
|
||||||
|
|
||||||
|
const MESSAGES_PER_PAGE = 20
|
||||||
|
|
||||||
|
# Signals which may be emitted by this service:
|
||||||
|
const SIGNAL_MESSAGES_LOADED* = "new-messagesLoaded" #Once we are done with refactoring we should remove "new-" from this signal name
|
||||||
|
|
||||||
|
type
|
||||||
|
MessagesLoadedArgs* = ref object of Args
|
||||||
|
chatId*: string
|
||||||
|
messages*: seq[MessageDto]
|
||||||
|
pinnedMessages*: seq[PinnedMessageDto]
|
||||||
|
reactions*: seq[ReactionDto]
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type Service* = ref object of QObject
|
||||||
|
events: EventEmitter
|
||||||
|
threadpool: ThreadPool
|
||||||
|
msgCursor: Table[string, string]
|
||||||
|
pinnedMsgCursor: Table[string, string]
|
||||||
|
|
||||||
|
proc delete*(self: Service) =
|
||||||
|
self.QObject.delete
|
||||||
|
|
||||||
|
proc newService*(events: EventEmitter, threadpool: ThreadPool): Service =
|
||||||
|
new(result, delete)
|
||||||
|
result.QObject.setup
|
||||||
|
result.events = events
|
||||||
|
result.threadpool = threadpool
|
||||||
|
result.msgCursor = initTable[string, string]()
|
||||||
|
result.pinnedMsgCursor = initTable[string, string]()
|
||||||
|
|
||||||
|
proc getCurrentMessageCursor(self: Service, chatId: string): string =
|
||||||
|
if(not self.msgCursor.hasKey(chatId)):
|
||||||
|
self.msgCursor[chatId] = ""
|
||||||
|
|
||||||
|
return self.msgCursor[chatId]
|
||||||
|
|
||||||
|
proc getCurrentPinnedMessageCursor(self: Service, chatId: string): string =
|
||||||
|
if(not self.pinnedMsgCursor.hasKey(chatId)):
|
||||||
|
self.pinnedMsgCursor[chatId] = ""
|
||||||
|
|
||||||
|
return self.pinnedMsgCursor[chatId]
|
||||||
|
|
||||||
|
proc onLoadMoreMessagesForChat*(self: Service, response: string) {.slot.} =
|
||||||
|
let responseObj = response.parseJson
|
||||||
|
if (responseObj.kind != JObject):
|
||||||
|
info "load more messages response is not a json object"
|
||||||
|
|
||||||
|
# notify view, this is important
|
||||||
|
self.events.emit(SIGNAL_MESSAGES_LOADED, MessagesLoadedArgs())
|
||||||
|
return
|
||||||
|
|
||||||
|
var chatId: string
|
||||||
|
discard responseObj.getProp("chatId", chatId)
|
||||||
|
|
||||||
|
# handling messages
|
||||||
|
var msgCursor: string
|
||||||
|
if(responseObj.getProp("messagesCursor", msgCursor)):
|
||||||
|
self.msgCursor[chatId] = msgCursor
|
||||||
|
|
||||||
|
var messagesArr: JsonNode
|
||||||
|
var messages: seq[MessageDto]
|
||||||
|
if(responseObj.getProp("messages", messagesArr)):
|
||||||
|
messages = map(messagesArr.getElems(), proc(x: JsonNode): MessageDto = x.toMessageDto())
|
||||||
|
|
||||||
|
# handling pinned messages
|
||||||
|
var pinnedMsgCursor: string
|
||||||
|
if(responseObj.getProp("pinnedMessagesCursor", pinnedMsgCursor)):
|
||||||
|
self.pinnedMsgCursor[chatId] = pinnedMsgCursor
|
||||||
|
|
||||||
|
var pinnedMsgArr: JsonNode
|
||||||
|
var pinnedMessages: seq[PinnedMessageDto]
|
||||||
|
if(responseObj.getProp("pinnedMessages", pinnedMsgArr)):
|
||||||
|
pinnedMessages = map(pinnedMsgArr.getElems(), proc(x: JsonNode): PinnedMessageDto = x.toPinnedMessageDto())
|
||||||
|
|
||||||
|
# handling reactions
|
||||||
|
var reactionsArr: JsonNode
|
||||||
|
var reactions: seq[ReactionDto]
|
||||||
|
if(responseObj.getProp("reactions", reactionsArr)):
|
||||||
|
reactions = map(reactionsArr.getElems(), proc(x: JsonNode): ReactionDto = x.toReactionDto())
|
||||||
|
|
||||||
|
let data = MessagesLoadedArgs(chatId: chatId,
|
||||||
|
messages: messages,
|
||||||
|
pinnedMessages: pinnedMessages,
|
||||||
|
reactions: reactions)
|
||||||
|
|
||||||
|
self.events.emit(SIGNAL_MESSAGES_LOADED, data)
|
||||||
|
|
||||||
|
|
||||||
|
proc loadMoreMessagesForChat*(self: Service, chatId: string) =
|
||||||
|
if (chatId.len == 0):
|
||||||
|
error "empty chat id", methodName="loadMoreMessagesForChat"
|
||||||
|
return
|
||||||
|
|
||||||
|
let arg = AsyncFetchChatMessagesTaskArg(
|
||||||
|
tptr: cast[ByteAddress](asyncFetchChatMessagesTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: "onLoadMoreMessagesForChat",
|
||||||
|
chatId: chatId,
|
||||||
|
msgCursor: self.getCurrentMessageCursor(chatId),
|
||||||
|
pinnedMsgCursor: self.getCurrentPinnedMessageCursor(chatId),
|
||||||
|
limit: MESSAGES_PER_PAGE
|
||||||
|
)
|
||||||
|
|
||||||
|
self.threadpool.start(arg)
|
||||||
|
|
||||||
|
proc loadInitialMessagesForChat*(self: Service, chatId: string) =
|
||||||
|
if(self.getCurrentMessageCursor(chatId).len > 0):
|
||||||
|
return
|
||||||
|
|
||||||
|
# we're here if initial messages are not loaded yet
|
||||||
|
self.loadMoreMessagesForChat(chatId)
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user