diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepository.kt index 1e86404efe9..3fd0a5e8423 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepository.kt @@ -70,15 +70,20 @@ import com.wire.kalium.network.api.base.authenticated.conversation.ConversationA import com.wire.kalium.persistence.dao.QualifiedIDEntity import com.wire.kalium.persistence.dao.client.ClientDAO import com.wire.kalium.persistence.dao.conversation.ConversationDAO +import com.wire.kalium.persistence.dao.conversation.ConversationDetailsWithEventsEntity import com.wire.kalium.persistence.dao.conversation.ConversationEntity import com.wire.kalium.persistence.dao.conversation.ConversationMetaDataDAO import com.wire.kalium.persistence.dao.member.MemberDAO import com.wire.kalium.persistence.dao.message.MessageDAO +import com.wire.kalium.persistence.dao.message.draft.MessageDraftDAO +import com.wire.kalium.persistence.dao.unread.ConversationUnreadEventEntity import com.wire.kalium.util.DelicateKaliumApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.datetime.Instant @@ -127,11 +132,7 @@ interface ConversationRepository { suspend fun getConversationList(): Either>> suspend fun observeConversationList(): Flow> suspend fun observeConversationListDetails(fromArchive: Boolean): Flow> - suspend fun observeConversationListDetailsWithEvents( - fromArchive: Boolean = false, - onlyInteractionsEnabled: Boolean = false, - newActivitiesOnTop: Boolean = false, - ): Flow> + suspend fun observeConversationListDetailsWithEvents(fromArchive: Boolean = false): Flow> suspend fun getConversationIds( type: Conversation.Type, protocol: Conversation.Protocol, @@ -317,6 +318,7 @@ internal class ConversationDataSource internal constructor( private val memberDAO: MemberDAO, private val conversationApi: ConversationApi, private val messageDAO: MessageDAO, + private val messageDraftDAO: MessageDraftDAO, private val clientDAO: ClientDAO, private val clientApi: ClientApi, private val conversationMetaDataDAO: ConversationMetaDataDAO, @@ -520,17 +522,28 @@ internal class ConversationDataSource internal constructor( conversationViewEntityList.map { conversationViewEntity -> conversationMapper.fromDaoModelToDetails(conversationViewEntity) } } - override suspend fun observeConversationListDetailsWithEvents( - fromArchive: Boolean, - onlyInteractionsEnabled: Boolean, - newActivitiesOnTop: Boolean, - ): Flow> = - conversationDAO.getAllConversationDetailsWithEvents(fromArchive, onlyInteractionsEnabled, newActivitiesOnTop) - .map { conversationDetailsWithEventsViewEntityList -> - conversationDetailsWithEventsViewEntityList.map { conversationDetailsWithEventsViewEntity -> - conversationMapper.fromDaoModelToDetailsWithEvents(conversationDetailsWithEventsViewEntity) - } + override suspend fun observeConversationListDetailsWithEvents(fromArchive: Boolean): Flow> = + combine( + conversationDAO.getAllConversationDetails(fromArchive), + if (fromArchive) flowOf(listOf()) else messageDAO.observeLastMessages(), + messageDAO.observeConversationsUnreadEvents(), + messageDraftDAO.observeMessageDrafts() + ) { conversationList, lastMessageList, unreadEvents, drafts -> + val lastMessageMap = lastMessageList.associateBy { it.conversationId } + val messageDraftMap = drafts.filter { it.text.isNotBlank() }.associateBy { it.conversationId } + val unreadEventsMap = unreadEvents.associateBy { it.conversationId } + + conversationList.map { conversation -> + conversationMapper.fromDaoModelToDetailsWithEvents( + ConversationDetailsWithEventsEntity( + conversationViewEntity = conversation, + lastMessage = lastMessageMap[conversation.id], + messageDraft = messageDraftMap[conversation.id], + unreadEvents = unreadEventsMap[conversation.id] ?: ConversationUnreadEventEntity(conversation.id, mapOf()), + ) + ) } + } override suspend fun fetchMlsOneToOneConversation(userId: UserId): Either = wrapApiRequest { diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 859269f102c..7351839496c 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -707,6 +707,7 @@ class UserSessionScope internal constructor( userStorage.database.memberDAO, authenticatedNetworkContainer.conversationApi, userStorage.database.messageDAO, + userStorage.database.messageDraftDAO, userStorage.database.clientDAO, authenticatedNetworkContainer.clientApi, userStorage.database.conversationMetaDataDAO, diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ConversationScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ConversationScope.kt index b471f6c742c..7ee88554ded 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ConversationScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ConversationScope.kt @@ -118,6 +118,9 @@ class ConversationScope internal constructor( val observeConversationListDetails: ObserveConversationListDetailsUseCase get() = ObserveConversationListDetailsUseCaseImpl(conversationRepository) + val observeConversationListDetailsWithEvents: ObserveConversationListDetailsWithEventsUseCase + get() = ObserveConversationListDetailsWithEventsUseCaseImpl(conversationRepository) + val observeConversationMembers: ObserveConversationMembersUseCase get() = ObserveConversationMembersUseCaseImpl(conversationRepository, userRepository) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ObserveConversationListDetailsWithEventsUseCaseImpl.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ObserveConversationListDetailsWithEventsUseCaseImpl.kt new file mode 100644 index 00000000000..543ca5d213c --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/conversation/ObserveConversationListDetailsWithEventsUseCaseImpl.kt @@ -0,0 +1,41 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +package com.wire.kalium.logic.feature.conversation + +import com.wire.kalium.logic.data.conversation.ConversationDetails +import com.wire.kalium.logic.data.conversation.ConversationDetailsWithEvents +import com.wire.kalium.logic.data.conversation.ConversationRepository +import kotlinx.coroutines.flow.Flow + +/** + * This use case will observe and return the list of conversation details for the current user. + * @see ConversationDetails + */ +fun interface ObserveConversationListDetailsWithEventsUseCase { + suspend operator fun invoke(fromArchive: Boolean): Flow> +} + +internal class ObserveConversationListDetailsWithEventsUseCaseImpl( + private val conversationRepository: ConversationRepository, +) : ObserveConversationListDetailsWithEventsUseCase { + + override suspend operator fun invoke(fromArchive: Boolean): Flow> { + return conversationRepository.observeConversationListDetailsWithEvents(fromArchive) + } +} diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationMapperTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationMapperTest.kt index b086f0f4bfc..8001981da4c 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationMapperTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationMapperTest.kt @@ -19,7 +19,6 @@ package com.wire.kalium.logic.data.conversation import com.wire.kalium.logic.data.connection.ConnectionStatusMapper -import com.wire.kalium.logic.data.conversation.ConversationRepositoryTest.Companion.MESSAGE_DRAFT_ENTITY import com.wire.kalium.logic.data.conversation.ConversationRepositoryTest.Companion.MESSAGE_PREVIEW_ENTITY import com.wire.kalium.logic.data.id.IdMapper import com.wire.kalium.logic.data.id.TeamId @@ -427,6 +426,8 @@ class ConversationMapperTest { val OTHER_MEMBERS = listOf(ConversationMemberDTO.Other(service = null, id = UserId("other1", "domain1"), conversationRole = "wire_admin")) val MEMBERS_RESPONSE = ConversationMembersResponse(SELF_MEMBER_RESPONSE, OTHER_MEMBERS) + val MESSAGE_DRAFT_ENTITY = MessageDraftEntity(TestConversation.VIEW_ENTITY.id, "text", null, null, listOf()) + val CONVERSATION_RESPONSE = ConversationResponse( "creator", MEMBERS_RESPONSE, diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepositoryTest.kt index b1d9918a4af..70f0807d7d6 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ConversationRepositoryTest.kt @@ -33,7 +33,6 @@ import com.wire.kalium.logic.data.id.toApi import com.wire.kalium.logic.data.id.toCrypto import com.wire.kalium.logic.data.id.toDao import com.wire.kalium.logic.data.id.toModel -import com.wire.kalium.logic.data.message.MessagePreviewContent import com.wire.kalium.logic.data.message.UnreadEventType import com.wire.kalium.logic.data.user.OtherUser import com.wire.kalium.logic.data.user.SelfUser @@ -44,6 +43,7 @@ import com.wire.kalium.logic.framework.TestConversation import com.wire.kalium.logic.framework.TestTeam import com.wire.kalium.logic.framework.TestUser import com.wire.kalium.logic.functional.Either +import com.wire.kalium.logic.sync.receiver.conversation.RenamedConversationEventHandler import com.wire.kalium.logic.util.arrangement.dao.MemberDAOArrangement import com.wire.kalium.logic.util.arrangement.dao.MemberDAOArrangementImpl import com.wire.kalium.logic.util.shouldFail @@ -88,6 +88,7 @@ import com.wire.kalium.persistence.dao.message.MessageDAO import com.wire.kalium.persistence.dao.message.MessageEntity import com.wire.kalium.persistence.dao.message.MessagePreviewEntity import com.wire.kalium.persistence.dao.message.MessagePreviewEntityContent +import com.wire.kalium.persistence.dao.message.draft.MessageDraftDAO import com.wire.kalium.persistence.dao.message.draft.MessageDraftEntity import com.wire.kalium.persistence.dao.unread.ConversationUnreadEventEntity import com.wire.kalium.persistence.dao.unread.UnreadEventTypeEntity @@ -99,6 +100,7 @@ import io.mockative.any import io.mockative.coEvery import io.mockative.coVerify import io.mockative.eq +import io.mockative.every import io.mockative.fake.valueOf import io.mockative.matchers.AnyMatcher import io.mockative.matchers.EqualsMatcher @@ -112,6 +114,7 @@ import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import kotlinx.datetime.Clock import kotlinx.datetime.Instant +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertContains import kotlin.test.assertEquals @@ -698,14 +701,12 @@ class ConversationRepositoryTest { conversationIdEntity, mapOf(UnreadEventTypeEntity.MESSAGE to unreadMessagesCount) ) - val conversationDetailsWithEventsEntity = ConversationDetailsWithEventsEntity( - conversationViewEntity = conversationEntity, - lastMessage = messagePreviewEntity, - unreadEvents = conversationUnreadEventEntity, - ) val (_, conversationRepository) = Arrangement() - .withConversationDetailsWithEvents(listOf(conversationDetailsWithEventsEntity)) + .withConversations(listOf(conversationEntity)) + .withLastMessages(listOf(messagePreviewEntity)) + .withConversationUnreadEvents(listOf(conversationUnreadEventEntity)) + .withMessageDrafts(listOf()) .arrange() // when @@ -715,7 +716,6 @@ class ConversationRepositoryTest { assertContains(result.map { it.conversationDetails.conversation.id }, conversationId) val conversation = result.first { it.conversationDetails.conversation.id == conversationId } - assertIs(conversation.conversationDetails) assertEquals(conversation.unreadEventCount[UnreadEventType.MESSAGE], unreadMessagesCount) assertEquals( MapperProvider.messageMapper(TestUser.SELF.id).fromEntityToMessagePreview(messagePreviewEntity), @@ -733,12 +733,10 @@ class ConversationRepositoryTest { val conversationIdEntity = ConversationIDEntity("some_value", "some_domain") val conversationId = QualifiedID("some_value", "some_domain") val shouldFetchFromArchivedConversations = true - val messagePreviewEntity = MESSAGE_PREVIEW_ENTITY.copy(conversationId = conversationIdEntity) val conversationEntity = TestConversation.VIEW_ENTITY.copy( id = conversationIdEntity, type = ConversationEntity.Type.GROUP, - archived = true, ) val unreadMessagesCount = 5 @@ -746,14 +744,12 @@ class ConversationRepositoryTest { conversationIdEntity, mapOf(UnreadEventTypeEntity.MESSAGE to unreadMessagesCount) ) - val conversationDetailsWithEventsEntity = ConversationDetailsWithEventsEntity( - conversationViewEntity = conversationEntity, - lastMessage = messagePreviewEntity, - unreadEvents = conversationUnreadEventEntity, - ) val (_, conversationRepository) = Arrangement() - .withConversationDetailsWithEvents(listOf(conversationDetailsWithEventsEntity)) + .withConversations(listOf(conversationEntity)) + .withLastMessages(listOf(MESSAGE_PREVIEW_ENTITY.copy(conversationId = conversationIdEntity))) + .withMessageDrafts(listOf()) + .withConversationUnreadEvents(listOf(conversationUnreadEventEntity)) .arrange() // when @@ -763,7 +759,6 @@ class ConversationRepositoryTest { assertContains(result.map { it.conversationDetails.conversation.id }, conversationId) val conversation = result.first { it.conversationDetails.conversation.id == conversationId } - assertIs(conversation.conversationDetails) assertEquals(conversation.unreadEventCount[UnreadEventType.MESSAGE], unreadMessagesCount) assertEquals(null, conversation.lastMessage) @@ -771,65 +766,63 @@ class ConversationRepositoryTest { } } + // TODO: bring back once pagination is implemented + @Ignore @Test fun givenAGroupConversationHasNotNewMessages_whenGettingConversationDetails_ThenReturnZeroUnreadMessageCount() = runTest { // given - val conversationIdEntity = ConversationIDEntity("some_value", "some_domain") - val conversationId = QualifiedID("some_value", "some_domain") - val shouldFetchFromArchivedConversations = false val conversationEntity = TestConversation.VIEW_ENTITY.copy( - id = conversationIdEntity, type = ConversationEntity.Type.GROUP, ) - val conversationDetailsWithEventsEntity = ConversationDetailsWithEventsEntity(conversationViewEntity = conversationEntity) val (_, conversationRepository) = Arrangement() - .withConversationDetailsWithEvents(listOf(conversationDetailsWithEventsEntity)) + .withExpectedObservableConversationDetails(conversationEntity) .arrange() // when - conversationRepository.observeConversationListDetailsWithEvents(shouldFetchFromArchivedConversations).test { + conversationRepository.observeConversationDetailsById(conversationEntity.id.toModel()).test { // then - val conversation = awaitItem().first { it.conversationDetails.conversation.id == conversationId } + val conversationDetail = awaitItem() - assertIs(conversation.conversationDetails) - assertTrue { conversation.lastMessage == null } + assertIs(conversationDetail) +// assertTrue { conversationDetail.lastMessage == null } awaitComplete() } } - @Test - fun givenAOneToOneConversationHasNotNewMessages_whenGettingConversationDetails_ThenReturnZeroUnreadMessageCount() = - runTest { - // given - val conversationIdEntity = ConversationIDEntity("some_value", "some_domain") - val conversationId = QualifiedID("some_value", "some_domain") - val shouldFetchFromArchivedConversations = false - val conversationEntity = TestConversation.VIEW_ENTITY.copy( - id = conversationIdEntity, - type = ConversationEntity.Type.ONE_ON_ONE, - otherUserId = QualifiedIDEntity("otherUser", "domain"), - ) - val conversationDetailsWithEventsEntity = ConversationDetailsWithEventsEntity(conversationViewEntity = conversationEntity) - - val (_, conversationRepository) = Arrangement() - .withConversationDetailsWithEvents(listOf(conversationDetailsWithEventsEntity)) - .arrange() - - // when - conversationRepository.observeConversationListDetailsWithEvents(shouldFetchFromArchivedConversations).test { - // then - val conversation = awaitItem().first { it.conversationDetails.conversation.id == conversationId } - - assertIs(conversation.conversationDetails) - assertTrue { conversation.lastMessage == null } - - awaitComplete() - } - } + // TODO: bring back once pagination is implemented +// @Test +// fun givenAOneToOneConversationHasNotNewMessages_whenGettingConversationDetails_ThenReturnZeroUnreadMessageCount() = +// runTest { +// // given +// val conversationIdEntity = ConversationIDEntity("some_value", "some_domain") +// val conversationId = QualifiedID("some_value", "some_domain") +// val shouldFetchFromArchivedConversations = false +// val conversationEntity = TestConversation.VIEW_ENTITY.copy( +// id = conversationIdEntity, +// type = ConversationEntity.Type.ONE_ON_ONE, +// otherUserId = QualifiedIDEntity("otherUser", "domain"), +// ) +// val conversationDetailsWithEventsEntity = ConversationDetailsWithEventsEntity(conversationViewEntity = conversationEntity) +// +// val (_, conversationRepository) = Arrangement() +// .withConversationDetailsWithEvents(listOf(conversationDetailsWithEventsEntity)) +// .arrange() +// +// // when +// conversationRepository.observeConversationListDetailsWithEvents(shouldFetchFromArchivedConversations).test { +// // then +// val conversation = awaitItem().first { it.conversationDetails.conversation.id == conversationId } +// +// assertIs(conversation.conversationDetails) +// assertTrue { conversation.lastMessage == null } +// +// awaitComplete() +// } +// } @Test - fun givenAOneToOneConversationHasNewMessages_whenObservingConversationListDetails_ThenCorrectlyGetUnreadMessageCount() = runTest { + fun givenAGroupConversationHasNewMessages_whenObservingConversationListDetails_ThenCorrectlyGetUnreadMessageCount() = runTest { // given val conversationIdEntity = ConversationIDEntity("some_value", "some_domain") val conversationId = QualifiedID("some_value", "some_domain") @@ -845,13 +838,12 @@ class ConversationRepositoryTest { conversationIdEntity, mapOf(UnreadEventTypeEntity.MESSAGE to unreadMessagesCount) ) - val conversationDetailsWithEventsEntity = ConversationDetailsWithEventsEntity( - conversationViewEntity = conversationEntity, - unreadEvents = conversationUnreadEventEntity, - ) val (_, conversationRepository) = Arrangement() - .withConversationDetailsWithEvents(listOf(conversationDetailsWithEventsEntity)) + .withConversations(listOf(conversationEntity)) + .withLastMessages(listOf()) + .withMessageDrafts(listOf()) + .withConversationUnreadEvents(listOf(conversationUnreadEventEntity)) .arrange() // when @@ -861,37 +853,12 @@ class ConversationRepositoryTest { assertContains(result.map { it.conversationDetails.conversation.id }, conversationId) val conversation = result.first { it.conversationDetails.conversation.id == conversationId } - assertIs(conversation.conversationDetails) assertEquals(conversation.unreadEventCount[UnreadEventType.MESSAGE], unreadMessagesCount) awaitComplete() } } - @Test - fun givenAConversationHasLastMessageAndDraft_whenObservingConversationListDetails_ThenCorrectlyGetLastMessage() = runTest { - // given - val conversationIdEntity = ConversationIDEntity("some_value", "some_domain") - val conversationId = QualifiedID("some_value", "some_domain") - val conversationEntity = TestConversation.VIEW_ENTITY.copy(id = conversationIdEntity, type = ConversationEntity.Type.GROUP) - val conversationDetailsWithEventsEntity = ConversationDetailsWithEventsEntity( - conversationViewEntity = conversationEntity, - lastMessage = MESSAGE_PREVIEW_ENTITY.copy(conversationId = conversationIdEntity), - messageDraft = MESSAGE_DRAFT_ENTITY.copy(conversationId = conversationIdEntity), - unreadEvents = ConversationUnreadEventEntity(conversationIdEntity, mapOf()), - ) - val (_, conversationRepository) = Arrangement() - .withConversationDetailsWithEvents(listOf(conversationDetailsWithEventsEntity)) - .arrange() - // when - conversationRepository.observeConversationListDetailsWithEvents(false).test { - val result = awaitItem() - val conversation = result.first { it.conversationDetails.conversation.id == conversationId } - assertIs(conversation.lastMessage?.content) - awaitComplete() - } - } - @Test fun givenAConversationDaoFailed_whenUpdatingTheConversationReadDate_thenShouldNotSucceed() = runTest { // given @@ -1446,9 +1413,16 @@ class ConversationRepositoryTest { @Mock private val messageDAO = mock(MessageDAO::class) + @Mock + private val messageDraftDAO = mock(MessageDraftDAO::class) + @Mock val conversationMetaDataDAO: ConversationMetaDataDAO = mock(ConversationMetaDataDAO::class) + @Mock + val renamedConversationEventHandler = + mock(RenamedConversationEventHandler::class) + val conversationRepository = ConversationDataSource( TestUser.USER_ID, @@ -1458,9 +1432,10 @@ class ConversationRepositoryTest { memberDAO, conversationApi, messageDAO, + messageDraftDAO, clientDao, clientApi, - conversationMetaDataDAO, + conversationMetaDataDAO ) @@ -1521,22 +1496,40 @@ class ConversationRepositoryTest { }.returns(response) } + suspend fun withConversationUnreadEvents(unreadEvents: List) = apply { + coEvery { + messageDAO.observeConversationsUnreadEvents() + }.returns(flowOf(unreadEvents)) + } + suspend fun withUnreadArchivedConversationsCount(unreadCount: Long) = apply { coEvery { conversationDAO.observeUnreadArchivedConversationsCount() }.returns(flowOf(unreadCount)) } + suspend fun withUnreadMessageCounter(unreadCounter: Map) = apply { + coEvery { + messageDAO.observeUnreadMessageCounter() + }.returns(flowOf(unreadCounter)) + } + suspend fun withConversations(conversations: List) = apply { coEvery { conversationDAO.getAllConversationDetails(any()) }.returns(flowOf(conversations)) } - suspend fun withConversationDetailsWithEvents(conversations: List) = apply { + suspend fun withLastMessages(messages: List) = apply { coEvery { - conversationDAO.getAllConversationDetailsWithEvents(any(), any(), any()) - }.returns(flowOf(conversations)) + messageDAO.observeLastMessages() + }.returns(flowOf(messages)) + } + + suspend fun withMessageDrafts(messageDrafts: List) = apply { + coEvery { + messageDraftDAO.observeMessageDrafts() + }.returns(flowOf(messageDrafts)) } suspend fun withUpdateConversationReadDateException(exception: Throwable) = apply { @@ -1814,7 +1807,6 @@ class ConversationRepositoryTest { isSelfMessage = false, senderUserId = USER_ENTITY_ID ) - val MESSAGE_DRAFT_ENTITY = MessageDraftEntity(TestConversation.VIEW_ENTITY.id, "text", null, null, listOf()) private val TEST_QUALIFIED_ID_ENTITY = PersistenceQualifiedId("value", "domain") val OTHER_USER_ID = UserId("otherValue", "domain")