diff --git a/sphinx/application/data/concepts/repositories/concept-repository-dashboard/src/main/java/chat/sphinx/concept_repository_dashboard/RepositoryDashboard.kt b/sphinx/application/data/concepts/repositories/concept-repository-dashboard/src/main/java/chat/sphinx/concept_repository_dashboard/RepositoryDashboard.kt index cba331ab8a..efa5063cc9 100644 --- a/sphinx/application/data/concepts/repositories/concept-repository-dashboard/src/main/java/chat/sphinx/concept_repository_dashboard/RepositoryDashboard.kt +++ b/sphinx/application/data/concepts/repositories/concept-repository-dashboard/src/main/java/chat/sphinx/concept_repository_dashboard/RepositoryDashboard.kt @@ -40,9 +40,11 @@ interface RepositoryDashboard { val getAllNotBlockedContacts: Flow> val getAllInvites: Flow> fun getContactById(contactId: ContactId): Flow + suspend fun getAllContactsByIds(contactIds: List): List var updatedContactIds: MutableList fun getMessageById(messageId: MessageId): Flow + fun getMessagesByIds(messageIds: List): Flow> fun getInviteById(inviteId: InviteId): Flow suspend fun payForInvite(invite: Invite) diff --git a/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/ChatViewModel.kt b/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/ChatViewModel.kt index a3843943d4..bbd5d5381c 100644 --- a/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/ChatViewModel.kt +++ b/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/ChatViewModel.kt @@ -1001,8 +1001,6 @@ abstract class ChatViewModel( messagesLoadJob = viewModelScope.launch(mainImmediate) { if (isThreadChat()) { messageRepository.getAllMessagesToShowByChatId(getChat().id, 0, getThreadUUID()).distinctUntilChanged().collect { messages -> - delay(200) - val originalMessage = messageRepository.getMessageByUUID(MessageUUID(getThreadUUID()?.value!!)).firstOrNull() val completeThread = listOf(originalMessage) + messages.reversed() val list = getMessageHolderViewStateList(completeThread.filterNotNull()).toList() @@ -1015,14 +1013,10 @@ abstract class ChatViewModel( } } else { messageRepository.getAllMessagesToShowByChatId(getChat().id, 100).firstOrNull()?.let { messages -> - delay(200) - messageHolderViewStateFlow.value = getMessageHolderViewStateList(messages).toList() shimmerViewState.updateViewState(ShimmerViewState.Off) } - delay(1000L) - messageRepository.getAllMessagesToShowByChatId(getChat().id, 1000).distinctUntilChanged().collect { messages -> messageHolderViewStateFlow.value = getMessageHolderViewStateList(messages).toList() shimmerViewState.updateViewState(ShimmerViewState.Off) @@ -2461,4 +2455,3 @@ inline fun Bitmap.toInputStream(): InputStream? { return ByteArrayInputStream(imageInByte) } - diff --git a/sphinx/screens/dashboard/dashboard/src/main/java/chat/sphinx/dashboard/ui/ChatListViewModel.kt b/sphinx/screens/dashboard/dashboard/src/main/java/chat/sphinx/dashboard/ui/ChatListViewModel.kt index 07c131b6e3..70230fbc8f 100644 --- a/sphinx/screens/dashboard/dashboard/src/main/java/chat/sphinx/dashboard/ui/ChatListViewModel.kt +++ b/sphinx/screens/dashboard/dashboard/src/main/java/chat/sphinx/dashboard/ui/ChatListViewModel.kt @@ -20,6 +20,8 @@ import chat.sphinx.wrapper_chat.ChatType import chat.sphinx.wrapper_chat.isConversation import chat.sphinx.wrapper_common.chat.ChatUUID import chat.sphinx.wrapper_common.dashboard.ContactId +import chat.sphinx.wrapper_common.dashboard.InviteId +import chat.sphinx.wrapper_common.message.MessageId import chat.sphinx.wrapper_common.tribe.TribeJoinLink import chat.sphinx.wrapper_common.tribe.toTribeJoinLink import chat.sphinx.wrapper_contact.* @@ -116,7 +118,7 @@ internal class ChatListViewModel @Inject constructor( viewModelScope.launch(mainImmediate) { delay(25L) - var allChats = when (args.argChatListType) { + val allChats = when (args.argChatListType) { ChatType.CONVERSATION -> { repositoryDashboard.getAllContactChats.distinctUntilChanged() } @@ -132,19 +134,31 @@ internal class ChatListViewModel @Inject constructor( collectionLock.withLock { chatsCollectionInitialized = true val newList = ArrayList(chats.size) - val contactsAdded = mutableListOf() + val contactsAdded = mutableSetOf() + val latestMessagesById = getLatestMessagesById(chats) + val contactsById = getContactsById( + chats.mapNotNull { chat -> + if (chat.type.isConversation()) { + chat.contactIds.lastOrNull() + } else { + null + } + } + ) + val invitesById = if (contactsCollectionInitialized) { + getInvitesById() + } else { + emptyMap() + } withContext(default) { for (chat in chats) { - val message: Message? = chat.latestMessageId?.let { - repositoryDashboard.getMessageById(it).firstOrNull() - } + val message: Message? = chat.latestMessageId?.let(latestMessagesById::get) if (chat.type.isConversation()) { val contactId: ContactId = chat.contactIds.lastOrNull() ?: continue - val contact: Contact = repositoryDashboard.getContactById(contactId) - .firstOrNull() ?: continue + val contact: Contact = contactsById[contactId] ?: continue if (!contact.isBlocked()) { contactsAdded.add(contactId) @@ -178,13 +192,7 @@ internal class ChatListViewModel @Inject constructor( if (!contactsAdded.contains(contact.id)) { if (contact.isInviteContact()) { - var contactInvite: Invite? = null - - contact.inviteId?.let { inviteId -> - contactInvite = withContext(io) { - repositoryDashboard.getInviteById(inviteId).firstOrNull() - } - } + val contactInvite = contact.inviteId?.let(invitesById::get) if (contactInvite != null) { newList.add( DashboardChat.Inactive.Invite(contact, contactInvite) @@ -259,7 +267,7 @@ internal class ChatListViewModel @Inject constructor( } val newList = ArrayList(contacts.size) - val contactIds = ArrayList(contacts.size) + val contactIds = mutableSetOf() withContext(default) { for (contact in contacts) { @@ -280,9 +288,20 @@ internal class ChatListViewModel @Inject constructor( return@withLock } + val invitesById = getInvitesById() + val conversations = withContext(io) { + repositoryDashboard.getAllContactChats.firstOrNull().orEmpty() + } + val conversationsByContactId = conversations.mapNotNull { chat -> + chat.contactIds.lastOrNull()?.let { contactId -> + contactId to chat + } + }.toMap() + val latestMessagesById = getLatestMessagesById(conversations) + withContext(default) { val currentChats = currentChatViewState.originalList.toMutableList() - val chatContactIds = mutableListOf() + val chatContactIds = mutableSetOf() var updateChatViewState = false for (chat in currentChatViewState.originalList) { @@ -330,13 +349,7 @@ internal class ChatListViewModel @Inject constructor( updateChatViewState = true if (contact.isInviteContact()) { - var contactInvite: Invite? = null - - contact.inviteId?.let { inviteId -> - contactInvite = withContext(io) { - repositoryDashboard.getInviteById(inviteId).firstOrNull() - } - } + val contactInvite = contact.inviteId?.let(invitesById::get) if (contactInvite != null) { currentChats.add( DashboardChat.Inactive.Invite(contact, contactInvite) @@ -362,10 +375,8 @@ internal class ChatListViewModel @Inject constructor( if (updatedContactChat is DashboardChat.Inactive.Conversation) { //Contact unblocked - repositoryDashboard.getConversationByContactId(contact.id).firstOrNull()?.let { contactChat -> - val message: Message? = contactChat.latestMessageId?.let { - repositoryDashboard.getMessageById(it).firstOrNull() - } + conversationsByContactId[contact.id]?.let { contactChat -> + val message: Message? = contactChat.latestMessageId?.let(latestMessagesById::get) updatedContactChat = DashboardChat.Active.Conversation( contactChat, @@ -388,6 +399,41 @@ internal class ChatListViewModel @Inject constructor( } } + private suspend fun getLatestMessagesById(chats: Collection): Map { + val messageIds = chats.mapNotNull { it.latestMessageId }.distinct() + if (messageIds.isEmpty()) { + return emptyMap() + } + + return withContext(io) { + repositoryDashboard.getMessagesByIds(messageIds) + .firstOrNull() + .orEmpty() + .filterNotNull() + .associateBy { it.id } + } + } + + private suspend fun getContactsById(contactIds: Collection): Map { + val uniqueContactIds = contactIds.distinct() + if (uniqueContactIds.isEmpty()) { + return emptyMap() + } + + return withContext(io) { + repositoryDashboard.getAllContactsByIds(uniqueContactIds) + .associateBy { it.id } + } + } + + private suspend fun getInvitesById(): Map = + withContext(io) { + repositoryDashboard.getAllInvites + .firstOrNull() + .orEmpty() + .associateBy { it.id } + } + suspend fun payForInvite(invite: Invite) { getAccountBalance().firstOrNull()?.let { balance -> if (balance.balance.value < (invite.price?.value ?: 0)) {