From d1f8de89dcf3d081e7251a1d44bd8cf0f71c17da Mon Sep 17 00:00:00 2001 From: Sergei Bakhtiarov Date: Tue, 18 Aug 2026 18:43:02 +0200 Subject: [PATCH] fix: starting conversation with user without clients (WPB-18997) --- .../di/accountScoped/ConversationModule.kt | 6 ++++ .../other/OtherUserProfileScreenViewModel.kt | 13 +++++--- .../OtherUserProfileScreenViewModelTest.kt | 31 +++++++++++++++++++ .../OtherUserProfileViewModelArrangement.kt | 14 ++++++--- kalium | 2 +- 5 files changed, 57 insertions(+), 9 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/di/accountScoped/ConversationModule.kt b/app/src/main/kotlin/com/wire/android/di/accountScoped/ConversationModule.kt index 5b9373f7be8..f5beceda32b 100644 --- a/app/src/main/kotlin/com/wire/android/di/accountScoped/ConversationModule.kt +++ b/app/src/main/kotlin/com/wire/android/di/accountScoped/ConversationModule.kt @@ -25,6 +25,7 @@ import com.wire.kalium.logic.data.conversation.ResetMLSConversationUseCase import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.feature.conversation.AddMemberToConversationUseCase import com.wire.kalium.logic.feature.conversation.AddServiceToConversationUseCase +import com.wire.kalium.logic.feature.conversation.CheckOneToOneConversationIsReadyUseCase import com.wire.kalium.logic.feature.conversation.ClearConversationContentUseCase import com.wire.kalium.logic.feature.conversation.ClearUsersTypingEventsUseCase import com.wire.kalium.logic.feature.conversation.ConversationScope @@ -310,6 +311,11 @@ class ConversationModule { fun provideIsOneToOneConversationCreatedUseCase(conversationScope: ConversationScope): IsOneToOneConversationCreatedUseCase = conversationScope.isOneToOneConversationCreatedUseCase + @Provides + fun provideCheckOneToOneConversationIsReadyUseCase( + conversationScope: ConversationScope + ): CheckOneToOneConversationIsReadyUseCase = conversationScope.checkOneToOneConversationIsReadyUseCase + @Provides fun provideGetConversationProtocolInfoUseCase(conversationScope: ConversationScope): GetConversationProtocolInfoUseCase = conversationScope.getConversationProtocolInfo diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt index fd3052a43a3..93a5a04039f 100644 --- a/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModel.kt @@ -41,7 +41,7 @@ import com.wire.kalium.logic.data.conversation.Conversation import com.wire.kalium.logic.data.id.QualifiedID import com.wire.kalium.logic.feature.client.FetchUsersClientsFromRemoteUseCase import com.wire.kalium.logic.feature.client.ObserveClientsByUserIdUseCase -import com.wire.kalium.logic.feature.conversation.IsOneToOneConversationCreatedUseCase +import com.wire.kalium.logic.feature.conversation.CheckOneToOneConversationIsReadyUseCase import com.wire.kalium.logic.feature.conversation.RemoveMemberFromConversationUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMemberRoleResult import com.wire.kalium.logic.feature.conversation.UpdateConversationMemberRoleUseCase @@ -74,7 +74,7 @@ class OtherUserProfileScreenViewModel @AssistedInject constructor( private val observeClientList: ObserveClientsByUserIdUseCase, private val fetchUsersClients: FetchUsersClientsFromRemoteUseCase, private val getUserE2eiCertificateStatus: IsOtherUserE2EIVerifiedUseCase, - private val isOneToOneConversationCreated: IsOneToOneConversationCreatedUseCase, + private val checkOneToOneConversationIsReady: CheckOneToOneConversationIsReadyUseCase, private val mlsClientIdentity: GetMLSClientIdentityUseCase, private val isE2EIEnabled: IsE2EIEnabledUseCase, @Assisted savedStateHandle: SavedStateHandle @@ -104,8 +104,13 @@ class OtherUserProfileScreenViewModel @AssistedInject constructor( } private fun getIfConversationExist() { viewModelScope.launch { - val isOneToOneConversationCreated = isOneToOneConversationCreated(userId) - state = state.copy(isConversationStarted = isOneToOneConversationCreated) + val readiness = checkOneToOneConversationIsReady(userId) + if (readiness is CheckOneToOneConversationIsReadyUseCase.Result.Failure) { + appLogger.w("Failed to check one-to-one conversation readiness: ${readiness.coreFailure}") + } + state = state.copy( + isConversationStarted = readiness is CheckOneToOneConversationIsReadyUseCase.Result.Ready + ) } } private fun getMLSVerificationStatus() { diff --git a/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModelTest.kt index 88fa67d13d5..1ac3f5cb88c 100644 --- a/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileScreenViewModelTest.kt @@ -23,6 +23,7 @@ import com.wire.android.assertIs import com.wire.android.config.CoroutineTestExtension import com.wire.android.config.NavigationTestExtension import com.wire.android.ui.home.conversations.details.participants.usecase.ConversationRoleData +import com.wire.kalium.common.error.CoreFailure import com.wire.kalium.logic.data.conversation.Conversation import com.wire.kalium.logic.data.conversation.Conversation.Member import com.wire.kalium.logic.data.conversation.ConversationDetails @@ -37,6 +38,7 @@ import com.wire.kalium.logic.data.user.UserAvailabilityStatus import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.data.user.type.UserType import com.wire.kalium.logic.data.user.type.UserTypeInfo +import com.wire.kalium.logic.feature.conversation.CheckOneToOneConversationIsReadyUseCase import com.wire.kalium.logic.feature.conversation.GetOneToOneConversationDetailsUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMemberRoleResult import com.wire.kalium.logic.feature.user.GetUserInfoResult @@ -91,6 +93,35 @@ class OtherUserProfileScreenViewModelTest { assertEquals(groupState, null) } + @Test + fun `given one-to-one conversation is ready, when loading profile, then conversation is started`() = runTest { + val (_, viewModel) = OtherUserProfileViewModelArrangement() + .withConversationReadiness(CheckOneToOneConversationIsReadyUseCase.Result.Ready(CONVERSATION)) + .arrange() + + assertEquals(true, viewModel.state.isConversationStarted) + } + + @Test + fun `given one-to-one conversation is not ready, when loading profile, then conversation is not started`() = runTest { + val (_, viewModel) = OtherUserProfileViewModelArrangement() + .withConversationReadiness(CheckOneToOneConversationIsReadyUseCase.Result.NotReady) + .arrange() + + assertEquals(false, viewModel.state.isConversationStarted) + } + + @Test + fun `given one-to-one readiness check fails, when loading profile, then conversation is not started`() = runTest { + val (_, viewModel) = OtherUserProfileViewModelArrangement() + .withConversationReadiness( + CheckOneToOneConversationIsReadyUseCase.Result.Failure(CoreFailure.Unknown(null)) + ) + .arrange() + + assertEquals(false, viewModel.state.isConversationStarted) + } + @Test fun `given a group conversationId, when changing the role, then the request should be configured correctly`() = runTest { diff --git a/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileViewModelArrangement.kt b/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileViewModelArrangement.kt index 900703f9ed3..74958e1f8cd 100644 --- a/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileViewModelArrangement.kt +++ b/app/src/test/kotlin/com/wire/android/ui/userprofile/other/OtherUserProfileViewModelArrangement.kt @@ -31,8 +31,8 @@ import com.wire.android.ui.userprofile.other.OtherUserProfileScreenViewModelTest import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.feature.client.FetchUsersClientsFromRemoteUseCase import com.wire.kalium.logic.feature.client.ObserveClientsByUserIdUseCase +import com.wire.kalium.logic.feature.conversation.CheckOneToOneConversationIsReadyUseCase import com.wire.kalium.logic.feature.conversation.GetOneToOneConversationDetailsUseCase -import com.wire.kalium.logic.feature.conversation.IsOneToOneConversationCreatedUseCase import com.wire.kalium.logic.feature.conversation.RemoveMemberFromConversationUseCase import com.wire.kalium.logic.feature.conversation.UpdateConversationMemberRoleResult import com.wire.kalium.logic.feature.conversation.UpdateConversationMemberRoleUseCase @@ -86,7 +86,7 @@ internal class OtherUserProfileViewModelArrangement { lateinit var getUserE2eiCertificateStatus: IsOtherUserE2EIVerifiedUseCase @MockK - lateinit var isOneToOneConversationCreated: IsOneToOneConversationCreatedUseCase + lateinit var checkOneToOneConversationIsReady: CheckOneToOneConversationIsReadyUseCase @MockK lateinit var mlsClientIdentity: GetMLSClientIdentityUseCase @@ -108,7 +108,7 @@ internal class OtherUserProfileViewModelArrangement { observeClientList, fetchUsersClientsFromRemote, getUserE2eiCertificateStatus, - isOneToOneConversationCreated, + checkOneToOneConversationIsReady, mlsClientIdentity, isE2EIEnabled, savedStateHandle, @@ -140,7 +140,9 @@ internal class OtherUserProfileViewModelArrangement { ) coEvery { getUserE2eiCertificateStatus.invoke(any()) } returns true coEvery { mlsClientIdentity.invoke(any()) } returns GetMLSClientIdentityResult.Success(mlsIdentity) - coEvery { isOneToOneConversationCreated.invoke(any()) } returns true + coEvery { checkOneToOneConversationIsReady.invoke(any()) } returns CheckOneToOneConversationIsReadyUseCase.Result.Ready( + OtherUserProfileScreenViewModelTest.CONVERSATION + ) coEvery { isE2EIEnabled.invoke() } returns true } @@ -163,5 +165,9 @@ internal class OtherUserProfileViewModelArrangement { coEvery { observeUserInfo(any()) } returns flowOf(result) } + fun withConversationReadiness(result: CheckOneToOneConversationIsReadyUseCase.Result) = apply { + coEvery { checkOneToOneConversationIsReady(any()) } returns result + } + fun arrange() = this to viewModel } diff --git a/kalium b/kalium index b46950f005c..fe7c1cbeb02 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit b46950f005cde4196e750b5df6ee12816ce2966d +Subproject commit fe7c1cbeb023fff827f446e7d75b9a67964a69cc