From 736d665a2c8a40a4b08c5c28ed900cdb923bdde3 Mon Sep 17 00:00:00 2001
From: Damian Kaczmarek <76782439+damian-kaczmarek@users.noreply.github.com>
Date: Fri, 29 Nov 2024 15:44:54 +0100
Subject: [PATCH] feat: more errors handling for personal migration #WPB-14281
(#3674)
---
.../teammigration/TeamMigrationState.kt | 4 +-
.../teammigration/TeamMigrationViewModel.kt | 4 +-
.../TeamMigrationConfirmationStepScreen.kt | 86 +++++++++++++++++--
app/src/main/res/values/strings.xml | 6 ++
.../TeamMigrationViewModelTest.kt | 59 ++++++++++++-
kalium | 2 +-
6 files changed, 143 insertions(+), 18 deletions(-)
diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationState.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationState.kt
index 3a045cfd045..be2d3d9625e 100644
--- a/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationState.kt
+++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationState.kt
@@ -18,11 +18,11 @@
package com.wire.android.ui.userprofile.teammigration
import androidx.compose.foundation.text.input.TextFieldState
-import com.wire.kalium.logic.CoreFailure
+import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamFailure
data class TeamMigrationState(
val teamNameTextState: TextFieldState = TextFieldState(),
val shouldShowMigrationLeaveDialog: Boolean = false,
val currentStep: Int = 0,
- val migrationFailure: CoreFailure? = null
+ val migrationFailure: MigrateFromPersonalToTeamFailure? = null
)
diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationViewModel.kt
index 9b8fefd2dc9..b4080251aa6 100644
--- a/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationViewModel.kt
+++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationViewModel.kt
@@ -24,7 +24,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.wire.android.feature.analytics.AnonymousAnalyticsManager
import com.wire.android.feature.analytics.model.AnalyticsEvent
-import com.wire.kalium.logic.CoreFailure
+import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamFailure
import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamResult
import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -114,7 +114,7 @@ class TeamMigrationViewModel @Inject constructor(
teamMigrationState = teamMigrationState.copy(migrationFailure = null)
}
- private fun onMigrationFailure(failure: CoreFailure) {
+ private fun onMigrationFailure(failure: MigrateFromPersonalToTeamFailure) {
teamMigrationState = teamMigrationState.copy(migrationFailure = failure)
}
}
diff --git a/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/step3/TeamMigrationConfirmationStepScreen.kt b/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/step3/TeamMigrationConfirmationStepScreen.kt
index f3254d79370..996e6a2a4fc 100644
--- a/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/step3/TeamMigrationConfirmationStepScreen.kt
+++ b/app/src/main/kotlin/com/wire/android/ui/userprofile/teammigration/step3/TeamMigrationConfirmationStepScreen.kt
@@ -41,14 +41,18 @@ import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withLink
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
+import com.ramcosta.composedestinations.navigation.popUpTo
import com.wire.android.R
import com.wire.android.navigation.WireDestination
import com.wire.android.navigation.style.SlideNavigationAnimation
import com.wire.android.ui.common.WireCheckbox
+import com.wire.android.ui.common.WireDialog
+import com.wire.android.ui.common.WireDialogButtonProperties
+import com.wire.android.ui.common.WireDialogButtonType
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.common.dimensions
-import com.wire.android.ui.common.error.CoreFailureErrorDialog
import com.wire.android.ui.destinations.TeamMigrationDoneStepScreenDestination
+import com.wire.android.ui.destinations.TeamMigrationTeamPlanStepScreenDestination
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireTypography
import com.wire.android.ui.userprofile.teammigration.PersonalToTeamMigrationNavGraph
@@ -58,6 +62,7 @@ import com.wire.android.ui.userprofile.teammigration.common.BottomLineButtons
import com.wire.android.ui.userprofile.teammigration.common.BulletList
import com.wire.android.util.CustomTabsHelper
import com.wire.android.util.ui.PreviewMultipleThemes
+import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamFailure
const val TEAM_MIGRATION_CONFIRMATION_STEP = 3
@@ -70,7 +75,7 @@ fun TeamMigrationConfirmationStepScreen(
navigator: DestinationsNavigator,
teamMigrationViewModel: TeamMigrationViewModel
) {
- val state = remember { teamMigrationViewModel.teamMigrationState }
+ val state = teamMigrationViewModel.teamMigrationState
TeamMigrationConfirmationStepScreenContent(
onContinueButtonClicked = {
@@ -85,7 +90,20 @@ fun TeamMigrationConfirmationStepScreen(
}
)
- HandleErrors(state, teamMigrationViewModel::failureHandled)
+ HandleErrors(
+ teamMigrationState = state,
+ onFailureHandled = teamMigrationViewModel::failureHandled,
+ goBackToFirstStep = {
+ navigator.navigate(
+ direction = TeamMigrationTeamPlanStepScreenDestination,
+ builder = {
+ popUpTo(TeamMigrationTeamPlanStepScreenDestination) {
+ inclusive = false
+ }
+ }
+ )
+ }
+ )
LaunchedEffect(Unit) {
teamMigrationViewModel.sendPersonalTeamCreationFlowStartedEvent(TEAM_MIGRATION_CONFIRMATION_STEP)
@@ -96,15 +114,65 @@ fun TeamMigrationConfirmationStepScreen(
@Composable
private fun HandleErrors(
teamMigrationState: TeamMigrationState,
- onFailureHandled: () -> Unit
+ onFailureHandled: () -> Unit,
+ goBackToFirstStep: () -> Unit,
) {
val failure = teamMigrationState.migrationFailure ?: return
- // TODO handle error WPB-14281
- CoreFailureErrorDialog(
- coreFailure = failure,
- onDialogDismiss = {
- onFailureHandled()
+
+ when (failure) {
+ is MigrateFromPersonalToTeamFailure.UserAlreadyInTeam -> {
+ ErrorDialog(
+ title = stringResource(R.string.personal_to_team_migration_error_title_already_in_team),
+ message = stringResource(R.string.personal_to_team_migration_error_message_already_in_team),
+ buttonText = stringResource(id = R.string.label_ok),
+ onDismiss = {
+ onFailureHandled()
+ }
+ )
}
+
+ is MigrateFromPersonalToTeamFailure.NoNetwork -> {
+ ErrorDialog(
+ title = stringResource(R.string.personal_to_team_migration_error_title),
+ message = stringResource(R.string.personal_to_team_migration_error_message_slow_network),
+ buttonText = stringResource(id = R.string.label_try_again),
+ onDismiss = {
+ onFailureHandled()
+ goBackToFirstStep()
+ }
+ )
+ }
+
+ else -> {
+ ErrorDialog(
+ title = stringResource(R.string.personal_to_team_migration_error_title),
+ message = stringResource(R.string.personal_to_team_migration_error_message_unknown_error),
+ buttonText = stringResource(id = R.string.label_try_again),
+ onDismiss = {
+ onFailureHandled()
+ goBackToFirstStep()
+ }
+ )
+ }
+ }
+}
+
+@Composable
+private fun ErrorDialog(
+ title: String,
+ message: String,
+ buttonText: String,
+ onDismiss: () -> Unit,
+) {
+ WireDialog(
+ title = title,
+ text = message,
+ onDismiss = onDismiss,
+ dismissButtonProperties = WireDialogButtonProperties(
+ onClick = onDismiss,
+ text = buttonText,
+ type = WireDialogButtonType.Primary,
+ )
)
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 36c6d043c92..95fafc74212 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -44,6 +44,7 @@
External
Service
Deleted
+ Try Again
Message could not be sent due to connectivity issues.
The edited message could not be sent due to connectivity issues.
Message could not be sent, as the backend of %s could not be reached.
@@ -1631,5 +1632,10 @@ In group conversations, the group admin can overwrite this setting.
When you leave now, you lose your progress and need to restart the team creation.
Continue Team Creation
Leave Without Saving
+ Team not created
+ Already part of a team
+ You\'ve created or joined a team with this email address on another device.
+ Wire could not complete your team creation due to a slow internet connection.
+ Wire could not complete your team creation due to an unknown error.
diff --git a/app/src/test/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationViewModelTest.kt
index efec0349927..42a7a926e05 100644
--- a/app/src/test/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationViewModelTest.kt
+++ b/app/src/test/kotlin/com/wire/android/ui/userprofile/teammigration/TeamMigrationViewModelTest.kt
@@ -22,6 +22,7 @@ import com.wire.android.config.CoroutineTestExtension
import com.wire.android.feature.analytics.AnonymousAnalyticsManager
import com.wire.android.feature.analytics.model.AnalyticsEvent
import com.wire.kalium.logic.NetworkFailure
+import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamFailure
import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamResult
import com.wire.kalium.logic.feature.user.migration.MigrateFromPersonalToTeamUseCase
import io.mockk.MockKAnnotations
@@ -186,10 +187,48 @@ class TeamMigrationViewModelTest {
}
@Test
- fun `given team name, when migrateFromPersonalToTeamAccount return failure, then call use case and handle the failure`() =
+ fun `given team name, when migrateFromPersonalToTeamAccount return unknown failure, then call use case and handle the failure`() =
runTest {
val (arrangement, viewModel) = Arrangement()
- .withMigrateFromPersonalToTeamError()
+ .withMigrateFromPersonalToTeamErrorUnknown()
+ .arrange()
+
+ val onSuccess = {}
+
+ viewModel.migrateFromPersonalToTeamAccount(onSuccess)
+
+ coVerify(exactly = 1) {
+ arrangement.migrateFromPersonalToTeam(Arrangement.TEAM_NAME)
+ }
+ Assertions.assertNotNull(viewModel.teamMigrationState.migrationFailure)
+ viewModel.failureHandled()
+ Assertions.assertNull(viewModel.teamMigrationState.migrationFailure)
+ }
+
+ @Test
+ fun `given team name, when migrateFromPersonalToTeamAccount return user already in team failure, then call use case and handle the failure`() =
+ runTest {
+ val (arrangement, viewModel) = Arrangement()
+ .withMigrateFromPersonalToTeamErrorAlreadyInTeam()
+ .arrange()
+
+ val onSuccess = {}
+
+ viewModel.migrateFromPersonalToTeamAccount(onSuccess)
+
+ coVerify(exactly = 1) {
+ arrangement.migrateFromPersonalToTeam(Arrangement.TEAM_NAME)
+ }
+ Assertions.assertNotNull(viewModel.teamMigrationState.migrationFailure)
+ viewModel.failureHandled()
+ Assertions.assertNull(viewModel.teamMigrationState.migrationFailure)
+ }
+
+ @Test
+ fun `given team name, when migrateFromPersonalToTeamAccount return no network failure, then call use case and handle the failure`() =
+ runTest {
+ val (arrangement, viewModel) = Arrangement()
+ .withMigrateFromPersonalToTeamErrorNoNetwork()
.arrange()
val onSuccess = {}
@@ -227,9 +266,21 @@ class TeamMigrationViewModelTest {
coEvery { migrateFromPersonalToTeam(any()) } returns MigrateFromPersonalToTeamResult.Success
}
- fun withMigrateFromPersonalToTeamError() = apply {
+ fun withMigrateFromPersonalToTeamErrorUnknown() = apply {
+ coEvery { migrateFromPersonalToTeam(any()) } returns MigrateFromPersonalToTeamResult.Error(
+ MigrateFromPersonalToTeamFailure.UnknownError(NetworkFailure.ProxyError(null))
+ )
+ }
+
+ fun withMigrateFromPersonalToTeamErrorAlreadyInTeam() = apply {
+ coEvery { migrateFromPersonalToTeam(any()) } returns MigrateFromPersonalToTeamResult.Error(
+ MigrateFromPersonalToTeamFailure.UserAlreadyInTeam()
+ )
+ }
+
+ fun withMigrateFromPersonalToTeamErrorNoNetwork() = apply {
coEvery { migrateFromPersonalToTeam(any()) } returns MigrateFromPersonalToTeamResult.Error(
- NetworkFailure.NoNetworkConnection(null)
+ MigrateFromPersonalToTeamFailure.NoNetwork
)
}
diff --git a/kalium b/kalium
index bee4d00171b..4c476f7390e 160000
--- a/kalium
+++ b/kalium
@@ -1 +1 @@
-Subproject commit bee4d00171b79c0a2506c4a2b6eb2f45a250c52c
+Subproject commit 4c476f7390ed6a7ffe27bc9ad0ce649c532ac35b