Repository: thunderbird/thunderbird-android (language: kotlin)

Issue:
[Account setup] Don't allow navigating back to transient special folders screen
When special folders are automatically configured by the server, the user only sees transient screens ("Fetching list of folders…" and "All special folders have been configured automatically by the server"). Currently we allow the user to change the special folder assignment anyway. That's also why we allow the user to navigate back to this screen. 

![image](https://github.com/thunderbird/thunderbird-android/assets/218061/104f8059-0f0c-4f0b-bb53-89190cb4de9b)

We've now decided that we want to keep things simple and don't allow users to change the special folders assignment (during account setup) when the server provided a complete mapping. In that case, the success screen is completely transient and we don't need the "Edit special folders" or "Next" buttons. When navigating back from the following screen, the special folders screen should be skipped.

However, if the server didn't provide a complete mapping, we prompt the user to configure special folders. In that case, navigating back from the screen that follows, should display that special folders screen again.


Discussion hints:
nan

Pull request: Change special folder success to loading and change navigation
Don't allow navigating back to transient special folders screen

Fixes #7553


Test command: ./gradlew :feature:account:setup:testDebugUnitTest --tests "app.k9mail.feature.account.setup.ui.specialfolders.SpecialFoldersScreenKtTest" --tests "app.k9mail.feature.account.setup.ui.specialfolders.SpecialFoldersViewModelTest" --tests "app.k9mail.feature.account.setup.ui.specialfolders.SpecialFoldersStateTest"

Fix patch:
diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/navigation/AccountSetupNavHost.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/navigation/AccountSetupNavHost.kt
index dc1a996e48e..f493cb07806 100644
--- a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/navigation/AccountSetupNavHost.kt
+++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/navigation/AccountSetupNavHost.kt
@@ -129,8 +129,18 @@ fun AccountSetupNavHost(
 
         composable(route = NESTED_NAVIGATION_SPECIAL_FOLDERS) {
             SpecialFoldersScreen(
-                onNext = {
-                    navController.navigate(NESTED_NAVIGATION_DISPLAY_OPTIONS)
+                onNext = { isManualSetup ->
+                    navController.navigate(NESTED_NAVIGATION_DISPLAY_OPTIONS) {
+                        if (isManualSetup) {
+                            popUpTo(NESTED_NAVIGATION_SPECIAL_FOLDERS)
+                        } else {
+                            if (isAutomaticConfig) {
+                                popUpTo(NESTED_NAVIGATION_AUTO_CONFIG)
+                            } else {
+                                popUpTo(NESTED_NAVIGATION_OUTGOING_SERVER_CONFIG)
+                            }
+                        }
+                    }
                 },
                 onBack = { navController.popBackStack() },
                 viewModel = koinViewModel<SpecialFoldersViewModel>(),
diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersContent.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersContent.kt
index cfe0a802f32..5937a219171 100644
--- a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersContent.kt
+++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersContent.kt
@@ -1,29 +1,19 @@
 package app.k9mail.feature.account.setup.ui.specialfolders
 
-import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.tooling.preview.Preview
-import app.k9mail.core.ui.compose.designsystem.atom.Icon
-import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonText
-import app.k9mail.core.ui.compose.designsystem.atom.text.TextSubtitle1
 import app.k9mail.core.ui.compose.designsystem.molecule.ContentLoadingErrorView
 import app.k9mail.core.ui.compose.designsystem.molecule.ErrorView
 import app.k9mail.core.ui.compose.designsystem.molecule.LoadingView
 import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer
-import app.k9mail.core.ui.compose.theme.Icons
 import app.k9mail.core.ui.compose.theme.MainTheme
 import app.k9mail.core.ui.compose.theme.PreviewWithThemes
 import app.k9mail.feature.account.common.ui.AppTitleTopHeader
@@ -66,9 +56,9 @@ fun SpecialFoldersContent(
                 modifier = Modifier.fillMaxSize(),
             ) {
                 if (state.isSuccess) {
-                    SuccessView(
+                    LoadingView(
                         message = stringResource(id = R.string.account_setup_special_folders_success_message),
-                        onEditClick = { onEvent(Event.OnEditClicked) },
+                        modifier = Modifier.padding(horizontal = MainTheme.spacings.double),
                     )
                 } else {
                     SpecialFoldersFormContent(
@@ -82,46 +72,6 @@ fun SpecialFoldersContent(
     }
 }
 
-@Composable
-fun SuccessView(
-    message: String,
-    onEditClick: () -> Unit,
-    modifier: Modifier = Modifier,
-) {
-    Column(
-        modifier = Modifier
-            .fillMaxWidth()
-            .padding(MainTheme.spacings.double)
-            .then(modifier),
-        horizontalAlignment = Alignment.CenterHorizontally,
-        verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default),
-    ) {
-        TextSubtitle1(
-            text = message,
-            textAlign = TextAlign.Center,
-        )
-
-        Row(
-            modifier = Modifier.height(MainTheme.sizes.larger),
-            verticalAlignment = Alignment.CenterVertically,
-        ) {
-            Icon(
-                imageVector = Icons.Outlined.celebration,
-                tint = MainTheme.colors.secondary,
-                modifier = Modifier.requiredSize(MainTheme.sizes.large),
-            )
-        }
-        Row(
-            verticalAlignment = Alignment.CenterVertically,
-        ) {
-            ButtonText(
-                text = stringResource(id = R.string.account_setup_special_folders_edit_folders_button_label),
-                onClick = onEditClick,
-            )
-        }
-    }
-}
-
 @Composable
 private fun SpecialFoldersErrorView(
     failure: SpecialFoldersContract.Failure,
diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersContract.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersContract.kt
index 60116c289b7..2126f445925 100644
--- a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersContract.kt
+++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersContract.kt
@@ -15,6 +15,7 @@ interface SpecialFoldersContract {
     data class State(
         val formState: FormState = FormState(),
 
+        val isManualSetup: Boolean = false,
         val isSuccess: Boolean = false,
         override val error: Failure? = null,
         override val isLoading: Boolean = true,
@@ -36,7 +37,6 @@ interface SpecialFoldersContract {
 
     sealed interface Event {
         data object LoadSpecialFolderOptions : Event
-        data object OnEditClicked : Event
         data object OnRetryClicked : Event
         data object OnNextClicked : Event
         data object OnBackClicked : Event
@@ -51,7 +51,10 @@ interface SpecialFoldersContract {
     }
 
     sealed interface Effect {
-        data object NavigateNext : Effect
+        data class NavigateNext(
+            val isManualSetup: Boolean,
+        ) : Effect
+
         data object NavigateBack : Effect
     }
 
diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersScreen.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersScreen.kt
index ac224cf5f5f..158d81ed0fa 100644
--- a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersScreen.kt
+++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersScreen.kt
@@ -17,14 +17,14 @@ import app.k9mail.feature.account.setup.ui.specialfolders.fake.FakeSpecialFolder
 
 @Composable
 fun SpecialFoldersScreen(
-    onNext: () -> Unit,
+    onNext: (isManualSetup: Boolean) -> Unit,
     onBack: () -> Unit,
     viewModel: ViewModel,
     modifier: Modifier = Modifier,
 ) {
     val (state, dispatch) = viewModel.observe { effect ->
         when (effect) {
-            Effect.NavigateNext -> onNext()
+            is Effect.NavigateNext -> onNext(effect.isManualSetup)
             Effect.NavigateBack -> onBack()
         }
     }
@@ -43,7 +43,7 @@ fun SpecialFoldersScreen(
                 onNextClick = { dispatch(Event.OnNextClicked) },
                 onBackClick = { dispatch(Event.OnBackClicked) },
                 state = WizardNavigationBarState(
-                    isNextEnabled = state.value.isLoading.not(),
+                    showNext = state.value.isManualSetup && state.value.isLoading.not(),
                 ),
             )
         },
diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersViewModel.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersViewModel.kt
index 78d17ff29a0..6ed7b13956e 100644
--- a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersViewModel.kt
+++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersViewModel.kt
@@ -37,7 +37,6 @@ class SpecialFoldersViewModel(
 
             Event.OnNextClicked -> onNextClicked()
             Event.OnBackClicked -> onBackClicked()
-            Event.OnEditClicked -> onEditClicked()
             Event.OnRetryClicked -> onRetryClicked()
         }
     }
@@ -65,6 +64,7 @@ class SpecialFoldersViewModel(
                 is ValidationResult.Failure -> {
                     updateState {
                         it.copy(
+                            isManualSetup = true,
                             isSuccess = false,
                             isLoading = false,
                         )
@@ -129,7 +129,7 @@ class SpecialFoldersViewModel(
 
     private fun navigateNext() {
         viewModelScope.coroutineContext.cancelChildren()
-        emitEffect(Effect.NavigateNext)
+        emitEffect(Effect.NavigateNext(isManualSetup = state.value.isManualSetup))
     }
 
     private fun onBackClicked() {
@@ -137,15 +137,6 @@ class SpecialFoldersViewModel(
         emitEffect(Effect.NavigateBack)
     }
 
-    private fun onEditClicked() {
-        viewModelScope.coroutineContext.cancelChildren()
-        updateState { state ->
-            state.copy(
-                isSuccess = false,
-            )
-        }
-    }
-
     private fun onRetryClicked() {
         viewModelScope.coroutineContext.cancelChildren()
         updateState {
diff --git a/feature/account/setup/src/main/res/values/strings.xml b/feature/account/setup/src/main/res/values/strings.xml
index 3471acf983a..326b671b239 100644
--- a/feature/account/setup/src/main/res/values/strings.xml
+++ b/feature/account/setup/src/main/res/values/strings.xml
@@ -39,7 +39,6 @@
     <string name="account_setup_special_folders_trash_folder_label">Trash folder</string>
     <string name="account_setup_special_folders_folder_none">None</string>
     <string name="account_setup_special_folders_folder_automatic">Automatic (%s)</string>
-    <string name="account_setup_special_folders_edit_folders_button_label">Edit special folders</string>
 
     <string name="account_setup_options_top_bar_title">Account options</string>
     <string name="account_setup_options_section_display_options">Display options</string>


Test patch:
diff --git a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersScreenKtTest.kt b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersScreenKtTest.kt
index d7ddd0cae0f..8d88bde8833 100644
--- a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersScreenKtTest.kt
+++ b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersScreenKtTest.kt
@@ -33,7 +33,7 @@ class SpecialFoldersScreenKtTest : ComposeTest() {
         assertThat(onNextCounter).isEqualTo(0)
         assertThat(onBackCounter).isEqualTo(0)
 
-        viewModel.effect(Effect.NavigateNext)
+        viewModel.effect(Effect.NavigateNext(true))
 
         assertThat(onNextCounter).isEqualTo(1)
         assertThat(onBackCounter).isEqualTo(0)
diff --git a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersStateTest.kt b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersStateTest.kt
index 4e821fdcaad..968a109faf6 100644
--- a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersStateTest.kt
+++ b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersStateTest.kt
@@ -16,6 +16,7 @@ class SpecialFoldersStateTest {
         assertThat(state).isEqualTo(
             State(
                 formState = FormState(),
+                isManualSetup = false,
                 isSuccess = false,
                 error = null,
                 isLoading = true,
diff --git a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersViewModelTest.kt b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersViewModelTest.kt
index c12ef6cf414..21119e8d405 100644
--- a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersViewModelTest.kt
+++ b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/specialfolders/SpecialFoldersViewModelTest.kt
@@ -75,7 +75,7 @@ class SpecialFoldersViewModelTest {
             }
 
             turbines.assertThatAndEffectTurbineConsumed {
-                isEqualTo(Effect.NavigateNext)
+                isEqualTo(Effect.NavigateNext(false))
             }
 
             assertThat(accountStateRepository.getState()).isEqualTo(
@@ -108,6 +108,7 @@ class SpecialFoldersViewModelTest {
         testSubject.event(Event.LoadSpecialFolderOptions)
 
         val unvalidatedState = initialState.copy(
+            isManualSetup = true,
             isLoading = false,
             isSuccess = false,
             formState = FormState(
@@ -187,7 +188,7 @@ class SpecialFoldersViewModelTest {
 
     @Test
     fun `should save form data and emit NavigateNext effect when OnNextClicked event received`() = runTest {
-        val initialState = State(isSuccess = true)
+        val initialState = State(isManualSetup = true)
         val accountStateRepository = InMemoryAccountStateRepository()
         val testSubject = createTestSubject(
             initialState = initialState,
@@ -200,7 +201,7 @@ class SpecialFoldersViewModelTest {
         assertThat(turbines.awaitStateItem()).isEqualTo(initialState.copy(isLoading = false))
 
         turbines.assertThatAndEffectTurbineConsumed {
-            isEqualTo(Effect.NavigateNext)
+            isEqualTo(Effect.NavigateNext(true))
         }
 
         assertThat(accountStateRepository.getState()).isEqualTo(
@@ -228,19 +229,6 @@ class SpecialFoldersViewModelTest {
         }
     }
 
-    @Test
-    fun `should show form when OnEditClicked event received`() = runTest {
-        val initialState = State(isSuccess = true)
-        val testSubject = createTestSubject(initialState = initialState)
-        val turbines = turbinesWithInitialStateCheck(testSubject, initialState)
-
-        testSubject.event(Event.OnEditClicked)
-
-        turbines.assertThatAndStateTurbineConsumed {
-            isEqualTo(initialState.copy(isSuccess = false))
-        }
-    }
-
     @Test
     fun `should show form when OnRetryClicked event received`() = runTest {
         val initialState = State(error = SpecialFoldersContract.Failure.LoadFoldersFailed("irrelevant"))
@@ -281,7 +269,7 @@ class SpecialFoldersViewModelTest {
         )
 
         turbines.assertThatAndEffectTurbineConsumed {
-            isEqualTo(Effect.NavigateNext)
+            isEqualTo(Effect.NavigateNext(false))
         }
     }