Loading feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/AccountSetupModule.kt +12 −6 Original line number Diff line number Diff line Loading @@ -82,20 +82,26 @@ val featureAccountSetupModule: Module = module { viewModel { AccountSetupViewModel( createAccount = get(), autoDiscoveryViewModel = get(), incomingViewModel = get(), incomingValidationViewModel = get(named(NAME_INCOMING_VALIDATION)), outgoingViewModel = get(), outgoingValidationViewModel = get(named(NAME_OUTGOING_VALIDATION)), optionsViewModel = get(), ) } viewModel { factory<AccountAutoDiscoveryContract.ViewModel> { AccountAutoDiscoveryViewModel( validator = get(), getAutoDiscovery = get(), ) } viewModel { factory<AccountIncomingConfigContract.ViewModel> { AccountIncomingConfigViewModel( validator = get(), ) } viewModel(named(NAME_INCOMING_VALIDATION)) { factory<AccountValidationContract.ViewModel>(named(NAME_INCOMING_VALIDATION)) { AccountValidationViewModel( validateServerSettings = get(), initialState = AccountValidationContract.State( Loading @@ -103,12 +109,12 @@ val featureAccountSetupModule: Module = module { ), ) } viewModel { factory<AccountOutgoingConfigContract.ViewModel> { AccountOutgoingConfigViewModel( validator = get(), ) } viewModel(named(NAME_OUTGOING_VALIDATION)) { factory<AccountValidationContract.ViewModel>(named(NAME_OUTGOING_VALIDATION)) { AccountValidationViewModel( validateServerSettings = get(), initialState = AccountValidationContract.State( Loading @@ -116,7 +122,7 @@ val featureAccountSetupModule: Module = module { ), ) } viewModel { factory<AccountOptionsContract.ViewModel> { AccountOptionsViewModel( validator = get(), ) Loading feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/AccountSetupContract.kt +9 −26 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryCon import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigContract import app.k9mail.feature.account.setup.ui.options.AccountOptionsContract import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigContract import app.k9mail.feature.account.setup.ui.validation.AccountValidationContract interface AccountSetupContract { Loading @@ -17,7 +18,14 @@ interface AccountSetupContract { OPTIONS, } interface ViewModel : UnidirectionalViewModel<State, Event, Effect> interface ViewModel : UnidirectionalViewModel<State, Event, Effect> { val autoDiscoveryViewModel: AccountAutoDiscoveryContract.ViewModel val incomingViewModel: AccountIncomingConfigContract.ViewModel val incomingValidationViewModel: AccountValidationContract.ViewModel val outgoingViewModel: AccountOutgoingConfigContract.ViewModel val outgoingValidationViewModel: AccountValidationContract.ViewModel val optionsViewModel: AccountOptionsContract.ViewModel } data class State( val setupStep: SetupStep = SetupStep.AUTO_CONFIG, Loading @@ -32,36 +40,11 @@ interface AccountSetupContract { val isAutomaticConfig: Boolean, ) : Event data class OnStateCollected( val autoDiscoveryState: AccountAutoDiscoveryContract.State, val incomingState: AccountIncomingConfigContract.State, val outgoingState: AccountOutgoingConfigContract.State, val optionsState: AccountOptionsContract.State, ) : Event object OnBack : Event } sealed interface Effect { data class UpdateIncomingConfig( val state: AccountIncomingConfigContract.State, ) : Effect object UpdateIncomingConfigValidation : Effect data class UpdateOutgoingConfig( val state: AccountOutgoingConfigContract.State, ) : Effect object UpdateOutgoingConfigValidation : Effect data class UpdateOptions( val state: AccountOptionsContract.State, ) : Effect object CollectExternalStates : Effect data class NavigateNext( val accountUuid: String, ) : Effect Loading feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/AccountSetupScreen.kt +7 −56 Original line number Diff line number Diff line Loading @@ -3,75 +3,26 @@ package app.k9mail.feature.account.setup.ui import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import app.k9mail.core.ui.compose.common.mvi.observe import app.k9mail.feature.account.setup.NAME_INCOMING_VALIDATION import app.k9mail.feature.account.setup.NAME_OUTGOING_VALIDATION import app.k9mail.feature.account.setup.ui.AccountSetupContract.Effect import app.k9mail.feature.account.setup.ui.AccountSetupContract.Event import app.k9mail.feature.account.setup.ui.AccountSetupContract.SetupStep import app.k9mail.feature.account.setup.ui.AccountSetupContract.ViewModel import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryContract import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryScreen import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryViewModel import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigContract import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigScreen import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigViewModel import app.k9mail.feature.account.setup.ui.incoming.toValidationState import app.k9mail.feature.account.setup.ui.options.AccountOptionsContract import app.k9mail.feature.account.setup.ui.options.AccountOptionsScreen import app.k9mail.feature.account.setup.ui.options.AccountOptionsViewModel import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigContract import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigScreen import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigViewModel import app.k9mail.feature.account.setup.ui.outgoing.toValidationState import app.k9mail.feature.account.setup.ui.validation.AccountValidationContract import app.k9mail.feature.account.setup.ui.validation.AccountValidationScreen import app.k9mail.feature.account.setup.ui.validation.AccountValidationViewModel import org.koin.androidx.compose.koinViewModel import org.koin.core.qualifier.named @Suppress("LongMethod", "CyclomaticComplexMethod") @Suppress("LongMethod") @Composable fun AccountSetupScreen( onFinish: (String) -> Unit, onBack: () -> Unit, viewModel: ViewModel = koinViewModel<AccountSetupViewModel>(), autoDiscoveryViewModel: AccountAutoDiscoveryContract.ViewModel = koinViewModel<AccountAutoDiscoveryViewModel>(), incomingViewModel: AccountIncomingConfigContract.ViewModel = koinViewModel<AccountIncomingConfigViewModel>(), incomingValidationViewModel: AccountValidationContract.ViewModel = koinViewModel<AccountValidationViewModel>( named( NAME_INCOMING_VALIDATION, ), ), outgoingViewModel: AccountOutgoingConfigContract.ViewModel = koinViewModel<AccountOutgoingConfigViewModel>(), outgoingValidationViewModel: AccountValidationContract.ViewModel = koinViewModel<AccountValidationViewModel>( named( NAME_OUTGOING_VALIDATION, ), ), optionsViewModel: AccountOptionsContract.ViewModel = koinViewModel<AccountOptionsViewModel>(), ) { val (state, dispatch) = viewModel.observe { effect -> when (effect) { is Effect.UpdateIncomingConfig -> incomingViewModel.initState(effect.state) is Effect.UpdateIncomingConfigValidation -> { incomingValidationViewModel.initState(incomingViewModel.state.value.toValidationState()) } is Effect.UpdateOutgoingConfig -> outgoingViewModel.initState(effect.state) is Effect.UpdateOutgoingConfigValidation -> { outgoingValidationViewModel.initState(outgoingViewModel.state.value.toValidationState()) } is Effect.UpdateOptions -> optionsViewModel.initState(effect.state) is Effect.CollectExternalStates -> viewModel.event( Event.OnStateCollected( autoDiscoveryState = autoDiscoveryViewModel.state.value, incomingState = incomingViewModel.state.value, outgoingState = outgoingViewModel.state.value, optionsState = optionsViewModel.state.value, ), ) is Effect.NavigateNext -> onFinish(effect.accountUuid) Effect.NavigateBack -> onBack() } Loading @@ -89,7 +40,7 @@ fun AccountSetupScreen( ) }, onBack = { dispatch(Event.OnBack) }, viewModel = autoDiscoveryViewModel, viewModel = viewModel.autoDiscoveryViewModel, ) } Loading @@ -97,7 +48,7 @@ fun AccountSetupScreen( AccountIncomingConfigScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = incomingViewModel, viewModel = viewModel.incomingViewModel, ) } Loading @@ -105,7 +56,7 @@ fun AccountSetupScreen( AccountValidationScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = incomingValidationViewModel, viewModel = viewModel.incomingValidationViewModel, ) } Loading @@ -113,7 +64,7 @@ fun AccountSetupScreen( AccountOutgoingConfigScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = outgoingViewModel, viewModel = viewModel.outgoingViewModel, ) } Loading @@ -121,7 +72,7 @@ fun AccountSetupScreen( AccountValidationScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = outgoingValidationViewModel, viewModel = viewModel.outgoingValidationViewModel, ) } Loading @@ -129,7 +80,7 @@ fun AccountSetupScreen( AccountOptionsScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = optionsViewModel, viewModel = viewModel.optionsViewModel, ) } } Loading feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/AccountSetupViewModel.kt +21 −24 Original line number Diff line number Diff line Loading @@ -7,23 +7,31 @@ import app.k9mail.feature.account.setup.ui.AccountSetupContract.Effect import app.k9mail.feature.account.setup.ui.AccountSetupContract.Event import app.k9mail.feature.account.setup.ui.AccountSetupContract.SetupStep import app.k9mail.feature.account.setup.ui.AccountSetupContract.State import app.k9mail.feature.account.setup.ui.AccountSetupContract.ViewModel import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryContract import app.k9mail.feature.account.setup.ui.common.mapper.toIncomingConfigState import app.k9mail.feature.account.setup.ui.common.mapper.toOptionsState import app.k9mail.feature.account.setup.ui.common.mapper.toOutgoingConfigState import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigContract import app.k9mail.feature.account.setup.ui.incoming.toServerSettings import app.k9mail.feature.account.setup.ui.incoming.toValidationState import app.k9mail.feature.account.setup.ui.options.AccountOptionsContract import app.k9mail.feature.account.setup.ui.options.toAccountOptions import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigContract import app.k9mail.feature.account.setup.ui.outgoing.toServerSettings import app.k9mail.feature.account.setup.ui.outgoing.toValidationState import app.k9mail.feature.account.setup.ui.validation.AccountValidationContract import kotlinx.coroutines.launch class AccountSetupViewModel( private val createAccount: UseCase.CreateAccount, override val autoDiscoveryViewModel: AccountAutoDiscoveryContract.ViewModel, override val incomingViewModel: AccountIncomingConfigContract.ViewModel, override val incomingValidationViewModel: AccountValidationContract.ViewModel, override val outgoingViewModel: AccountOutgoingConfigContract.ViewModel, override val outgoingValidationViewModel: AccountValidationContract.ViewModel, override val optionsViewModel: AccountOptionsContract.ViewModel, initialState: State = State(), ) : BaseViewModel<State, Event, Effect>(initialState), ViewModel { ) : BaseViewModel<State, Event, Effect>(initialState), AccountSetupContract.ViewModel { override fun event(event: Event) { when (event) { Loading @@ -36,13 +44,6 @@ class AccountSetupViewModel( onAutoDiscoveryFinished(event.state) } is Event.OnStateCollected -> onStateCollected( autoDiscoveryState = event.autoDiscoveryState, incomingState = event.incomingState, outgoingState = event.outgoingState, optionsState = event.optionsState, ) Event.OnBack -> onBack() Event.OnNext -> onNext() } Loading @@ -51,9 +52,9 @@ class AccountSetupViewModel( private fun onAutoDiscoveryFinished( autoDiscoveryState: AccountAutoDiscoveryContract.State, ) { emitEffect(Effect.UpdateIncomingConfig(autoDiscoveryState.toIncomingConfigState())) emitEffect(Effect.UpdateOutgoingConfig(autoDiscoveryState.toOutgoingConfigState())) emitEffect(Effect.UpdateOptions(autoDiscoveryState.toOptionsState())) incomingViewModel.initState(autoDiscoveryState.toIncomingConfigState()) outgoingViewModel.initState(autoDiscoveryState.toOutgoingConfigState()) optionsViewModel.initState(autoDiscoveryState.toOptionsState()) onNext() } Loading Loading @@ -86,8 +87,8 @@ class AccountSetupViewModel( when (state.value.setupStep) { SetupStep.AUTO_CONFIG -> { if (state.value.isAutomaticConfig) { emitEffect(Effect.UpdateIncomingConfigValidation) emitEffect(Effect.UpdateOutgoingConfigValidation) incomingValidationViewModel.initState(incomingViewModel.state.value.toValidationState()) outgoingValidationViewModel.initState(outgoingViewModel.state.value.toValidationState()) changeToSetupStep(SetupStep.INCOMING_VALIDATION) } else { changeToSetupStep(SetupStep.INCOMING_CONFIG) Loading @@ -95,7 +96,7 @@ class AccountSetupViewModel( } SetupStep.INCOMING_CONFIG -> { emitEffect(Effect.UpdateIncomingConfigValidation) incomingValidationViewModel.initState(incomingViewModel.state.value.toValidationState()) changeToSetupStep(SetupStep.INCOMING_VALIDATION) } Loading @@ -108,7 +109,7 @@ class AccountSetupViewModel( } SetupStep.OUTGOING_CONFIG -> { emitEffect(Effect.UpdateOutgoingConfigValidation) outgoingValidationViewModel.initState(outgoingViewModel.state.value.toValidationState()) changeToSetupStep(SetupStep.OUTGOING_VALIDATION) } Loading @@ -129,15 +130,11 @@ class AccountSetupViewModel( } private fun onFinish() { emitEffect(Effect.CollectExternalStates) } val autoDiscoveryState = autoDiscoveryViewModel.state.value val incomingState = incomingViewModel.state.value val outgoingState = outgoingViewModel.state.value val optionsState = optionsViewModel.state.value private fun onStateCollected( autoDiscoveryState: AccountAutoDiscoveryContract.State, incomingState: AccountIncomingConfigContract.State, outgoingState: AccountOutgoingConfigContract.State, optionsState: AccountOptionsContract.State, ) { viewModelScope.launch { val result = createAccount.execute( emailAddress = autoDiscoveryState.emailAddress.value, Loading feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/AccountSetupScreenKtTest.kt +1 −30 Original line number Diff line number Diff line Loading @@ -7,11 +7,6 @@ import app.k9mail.core.ui.compose.theme.ThunderbirdTheme import app.k9mail.feature.account.setup.ui.AccountSetupContract.Effect import app.k9mail.feature.account.setup.ui.AccountSetupContract.SetupStep import app.k9mail.feature.account.setup.ui.AccountSetupContract.State import app.k9mail.feature.account.setup.ui.autodiscovery.FakeAccountAutoDiscoveryViewModel import app.k9mail.feature.account.setup.ui.incoming.FakeAccountIncomingConfigViewModel import app.k9mail.feature.account.setup.ui.options.FakeAccountOptionsViewModel import app.k9mail.feature.account.setup.ui.outgoing.FakeAccountOutgoingConfigViewModel import app.k9mail.feature.account.setup.ui.validation.FakeAccountValidationViewModel import assertk.assertThat import assertk.assertions.isEqualTo import kotlinx.coroutines.test.runTest Loading @@ -22,12 +17,6 @@ class AccountSetupScreenKtTest : ComposeTest() { @Test fun `should display correct screen for every setup step`() = runTest { val viewModel = FakeAccountSetupViewModel() val autoDiscoveryViewModel = FakeAccountAutoDiscoveryViewModel() val incomingViewModel = FakeAccountIncomingConfigViewModel() val incomingValidationViewModel = FakeAccountValidationViewModel() val outgoingViewModel = FakeAccountOutgoingConfigViewModel() val outgoingValidationViewModel = FakeAccountValidationViewModel() val optionsViewModel = FakeAccountOptionsViewModel() setContent { ThunderbirdTheme { Loading @@ -35,12 +24,6 @@ class AccountSetupScreenKtTest : ComposeTest() { onFinish = { }, onBack = { }, viewModel = viewModel, autoDiscoveryViewModel = autoDiscoveryViewModel, incomingViewModel = incomingViewModel, incomingValidationViewModel = incomingValidationViewModel, outgoingViewModel = outgoingViewModel, outgoingValidationViewModel = outgoingValidationViewModel, optionsViewModel = optionsViewModel, ) } } Loading @@ -54,13 +37,7 @@ class AccountSetupScreenKtTest : ComposeTest() { @Test fun `should delegate navigation effects`() = runTest { val initialState = State() val viewModel = FakeAccountSetupViewModel(initialState) val autoDiscoveryViewModel = FakeAccountAutoDiscoveryViewModel() val incomingViewModel = FakeAccountIncomingConfigViewModel() val incomingValidationViewModel = FakeAccountValidationViewModel() val outgoingViewModel = FakeAccountOutgoingConfigViewModel() val outgoingValidationViewModel = FakeAccountValidationViewModel() val optionsViewModel = FakeAccountOptionsViewModel() val viewModel = FakeAccountSetupViewModel(initialState = initialState) var onFinishCounter = 0 var onBackCounter = 0 Loading @@ -70,12 +47,6 @@ class AccountSetupScreenKtTest : ComposeTest() { onFinish = { onFinishCounter++ }, onBack = { onBackCounter++ }, viewModel = viewModel, autoDiscoveryViewModel = autoDiscoveryViewModel, incomingViewModel = incomingViewModel, incomingValidationViewModel = incomingValidationViewModel, outgoingViewModel = outgoingViewModel, outgoingValidationViewModel = outgoingValidationViewModel, optionsViewModel = optionsViewModel, ) } } Loading Loading
feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/AccountSetupModule.kt +12 −6 Original line number Diff line number Diff line Loading @@ -82,20 +82,26 @@ val featureAccountSetupModule: Module = module { viewModel { AccountSetupViewModel( createAccount = get(), autoDiscoveryViewModel = get(), incomingViewModel = get(), incomingValidationViewModel = get(named(NAME_INCOMING_VALIDATION)), outgoingViewModel = get(), outgoingValidationViewModel = get(named(NAME_OUTGOING_VALIDATION)), optionsViewModel = get(), ) } viewModel { factory<AccountAutoDiscoveryContract.ViewModel> { AccountAutoDiscoveryViewModel( validator = get(), getAutoDiscovery = get(), ) } viewModel { factory<AccountIncomingConfigContract.ViewModel> { AccountIncomingConfigViewModel( validator = get(), ) } viewModel(named(NAME_INCOMING_VALIDATION)) { factory<AccountValidationContract.ViewModel>(named(NAME_INCOMING_VALIDATION)) { AccountValidationViewModel( validateServerSettings = get(), initialState = AccountValidationContract.State( Loading @@ -103,12 +109,12 @@ val featureAccountSetupModule: Module = module { ), ) } viewModel { factory<AccountOutgoingConfigContract.ViewModel> { AccountOutgoingConfigViewModel( validator = get(), ) } viewModel(named(NAME_OUTGOING_VALIDATION)) { factory<AccountValidationContract.ViewModel>(named(NAME_OUTGOING_VALIDATION)) { AccountValidationViewModel( validateServerSettings = get(), initialState = AccountValidationContract.State( Loading @@ -116,7 +122,7 @@ val featureAccountSetupModule: Module = module { ), ) } viewModel { factory<AccountOptionsContract.ViewModel> { AccountOptionsViewModel( validator = get(), ) Loading
feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/AccountSetupContract.kt +9 −26 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryCon import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigContract import app.k9mail.feature.account.setup.ui.options.AccountOptionsContract import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigContract import app.k9mail.feature.account.setup.ui.validation.AccountValidationContract interface AccountSetupContract { Loading @@ -17,7 +18,14 @@ interface AccountSetupContract { OPTIONS, } interface ViewModel : UnidirectionalViewModel<State, Event, Effect> interface ViewModel : UnidirectionalViewModel<State, Event, Effect> { val autoDiscoveryViewModel: AccountAutoDiscoveryContract.ViewModel val incomingViewModel: AccountIncomingConfigContract.ViewModel val incomingValidationViewModel: AccountValidationContract.ViewModel val outgoingViewModel: AccountOutgoingConfigContract.ViewModel val outgoingValidationViewModel: AccountValidationContract.ViewModel val optionsViewModel: AccountOptionsContract.ViewModel } data class State( val setupStep: SetupStep = SetupStep.AUTO_CONFIG, Loading @@ -32,36 +40,11 @@ interface AccountSetupContract { val isAutomaticConfig: Boolean, ) : Event data class OnStateCollected( val autoDiscoveryState: AccountAutoDiscoveryContract.State, val incomingState: AccountIncomingConfigContract.State, val outgoingState: AccountOutgoingConfigContract.State, val optionsState: AccountOptionsContract.State, ) : Event object OnBack : Event } sealed interface Effect { data class UpdateIncomingConfig( val state: AccountIncomingConfigContract.State, ) : Effect object UpdateIncomingConfigValidation : Effect data class UpdateOutgoingConfig( val state: AccountOutgoingConfigContract.State, ) : Effect object UpdateOutgoingConfigValidation : Effect data class UpdateOptions( val state: AccountOptionsContract.State, ) : Effect object CollectExternalStates : Effect data class NavigateNext( val accountUuid: String, ) : Effect Loading
feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/AccountSetupScreen.kt +7 −56 Original line number Diff line number Diff line Loading @@ -3,75 +3,26 @@ package app.k9mail.feature.account.setup.ui import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import app.k9mail.core.ui.compose.common.mvi.observe import app.k9mail.feature.account.setup.NAME_INCOMING_VALIDATION import app.k9mail.feature.account.setup.NAME_OUTGOING_VALIDATION import app.k9mail.feature.account.setup.ui.AccountSetupContract.Effect import app.k9mail.feature.account.setup.ui.AccountSetupContract.Event import app.k9mail.feature.account.setup.ui.AccountSetupContract.SetupStep import app.k9mail.feature.account.setup.ui.AccountSetupContract.ViewModel import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryContract import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryScreen import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryViewModel import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigContract import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigScreen import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigViewModel import app.k9mail.feature.account.setup.ui.incoming.toValidationState import app.k9mail.feature.account.setup.ui.options.AccountOptionsContract import app.k9mail.feature.account.setup.ui.options.AccountOptionsScreen import app.k9mail.feature.account.setup.ui.options.AccountOptionsViewModel import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigContract import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigScreen import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigViewModel import app.k9mail.feature.account.setup.ui.outgoing.toValidationState import app.k9mail.feature.account.setup.ui.validation.AccountValidationContract import app.k9mail.feature.account.setup.ui.validation.AccountValidationScreen import app.k9mail.feature.account.setup.ui.validation.AccountValidationViewModel import org.koin.androidx.compose.koinViewModel import org.koin.core.qualifier.named @Suppress("LongMethod", "CyclomaticComplexMethod") @Suppress("LongMethod") @Composable fun AccountSetupScreen( onFinish: (String) -> Unit, onBack: () -> Unit, viewModel: ViewModel = koinViewModel<AccountSetupViewModel>(), autoDiscoveryViewModel: AccountAutoDiscoveryContract.ViewModel = koinViewModel<AccountAutoDiscoveryViewModel>(), incomingViewModel: AccountIncomingConfigContract.ViewModel = koinViewModel<AccountIncomingConfigViewModel>(), incomingValidationViewModel: AccountValidationContract.ViewModel = koinViewModel<AccountValidationViewModel>( named( NAME_INCOMING_VALIDATION, ), ), outgoingViewModel: AccountOutgoingConfigContract.ViewModel = koinViewModel<AccountOutgoingConfigViewModel>(), outgoingValidationViewModel: AccountValidationContract.ViewModel = koinViewModel<AccountValidationViewModel>( named( NAME_OUTGOING_VALIDATION, ), ), optionsViewModel: AccountOptionsContract.ViewModel = koinViewModel<AccountOptionsViewModel>(), ) { val (state, dispatch) = viewModel.observe { effect -> when (effect) { is Effect.UpdateIncomingConfig -> incomingViewModel.initState(effect.state) is Effect.UpdateIncomingConfigValidation -> { incomingValidationViewModel.initState(incomingViewModel.state.value.toValidationState()) } is Effect.UpdateOutgoingConfig -> outgoingViewModel.initState(effect.state) is Effect.UpdateOutgoingConfigValidation -> { outgoingValidationViewModel.initState(outgoingViewModel.state.value.toValidationState()) } is Effect.UpdateOptions -> optionsViewModel.initState(effect.state) is Effect.CollectExternalStates -> viewModel.event( Event.OnStateCollected( autoDiscoveryState = autoDiscoveryViewModel.state.value, incomingState = incomingViewModel.state.value, outgoingState = outgoingViewModel.state.value, optionsState = optionsViewModel.state.value, ), ) is Effect.NavigateNext -> onFinish(effect.accountUuid) Effect.NavigateBack -> onBack() } Loading @@ -89,7 +40,7 @@ fun AccountSetupScreen( ) }, onBack = { dispatch(Event.OnBack) }, viewModel = autoDiscoveryViewModel, viewModel = viewModel.autoDiscoveryViewModel, ) } Loading @@ -97,7 +48,7 @@ fun AccountSetupScreen( AccountIncomingConfigScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = incomingViewModel, viewModel = viewModel.incomingViewModel, ) } Loading @@ -105,7 +56,7 @@ fun AccountSetupScreen( AccountValidationScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = incomingValidationViewModel, viewModel = viewModel.incomingValidationViewModel, ) } Loading @@ -113,7 +64,7 @@ fun AccountSetupScreen( AccountOutgoingConfigScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = outgoingViewModel, viewModel = viewModel.outgoingViewModel, ) } Loading @@ -121,7 +72,7 @@ fun AccountSetupScreen( AccountValidationScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = outgoingValidationViewModel, viewModel = viewModel.outgoingValidationViewModel, ) } Loading @@ -129,7 +80,7 @@ fun AccountSetupScreen( AccountOptionsScreen( onNext = { dispatch(Event.OnNext) }, onBack = { dispatch(Event.OnBack) }, viewModel = optionsViewModel, viewModel = viewModel.optionsViewModel, ) } } Loading
feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/AccountSetupViewModel.kt +21 −24 Original line number Diff line number Diff line Loading @@ -7,23 +7,31 @@ import app.k9mail.feature.account.setup.ui.AccountSetupContract.Effect import app.k9mail.feature.account.setup.ui.AccountSetupContract.Event import app.k9mail.feature.account.setup.ui.AccountSetupContract.SetupStep import app.k9mail.feature.account.setup.ui.AccountSetupContract.State import app.k9mail.feature.account.setup.ui.AccountSetupContract.ViewModel import app.k9mail.feature.account.setup.ui.autodiscovery.AccountAutoDiscoveryContract import app.k9mail.feature.account.setup.ui.common.mapper.toIncomingConfigState import app.k9mail.feature.account.setup.ui.common.mapper.toOptionsState import app.k9mail.feature.account.setup.ui.common.mapper.toOutgoingConfigState import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigContract import app.k9mail.feature.account.setup.ui.incoming.toServerSettings import app.k9mail.feature.account.setup.ui.incoming.toValidationState import app.k9mail.feature.account.setup.ui.options.AccountOptionsContract import app.k9mail.feature.account.setup.ui.options.toAccountOptions import app.k9mail.feature.account.setup.ui.outgoing.AccountOutgoingConfigContract import app.k9mail.feature.account.setup.ui.outgoing.toServerSettings import app.k9mail.feature.account.setup.ui.outgoing.toValidationState import app.k9mail.feature.account.setup.ui.validation.AccountValidationContract import kotlinx.coroutines.launch class AccountSetupViewModel( private val createAccount: UseCase.CreateAccount, override val autoDiscoveryViewModel: AccountAutoDiscoveryContract.ViewModel, override val incomingViewModel: AccountIncomingConfigContract.ViewModel, override val incomingValidationViewModel: AccountValidationContract.ViewModel, override val outgoingViewModel: AccountOutgoingConfigContract.ViewModel, override val outgoingValidationViewModel: AccountValidationContract.ViewModel, override val optionsViewModel: AccountOptionsContract.ViewModel, initialState: State = State(), ) : BaseViewModel<State, Event, Effect>(initialState), ViewModel { ) : BaseViewModel<State, Event, Effect>(initialState), AccountSetupContract.ViewModel { override fun event(event: Event) { when (event) { Loading @@ -36,13 +44,6 @@ class AccountSetupViewModel( onAutoDiscoveryFinished(event.state) } is Event.OnStateCollected -> onStateCollected( autoDiscoveryState = event.autoDiscoveryState, incomingState = event.incomingState, outgoingState = event.outgoingState, optionsState = event.optionsState, ) Event.OnBack -> onBack() Event.OnNext -> onNext() } Loading @@ -51,9 +52,9 @@ class AccountSetupViewModel( private fun onAutoDiscoveryFinished( autoDiscoveryState: AccountAutoDiscoveryContract.State, ) { emitEffect(Effect.UpdateIncomingConfig(autoDiscoveryState.toIncomingConfigState())) emitEffect(Effect.UpdateOutgoingConfig(autoDiscoveryState.toOutgoingConfigState())) emitEffect(Effect.UpdateOptions(autoDiscoveryState.toOptionsState())) incomingViewModel.initState(autoDiscoveryState.toIncomingConfigState()) outgoingViewModel.initState(autoDiscoveryState.toOutgoingConfigState()) optionsViewModel.initState(autoDiscoveryState.toOptionsState()) onNext() } Loading Loading @@ -86,8 +87,8 @@ class AccountSetupViewModel( when (state.value.setupStep) { SetupStep.AUTO_CONFIG -> { if (state.value.isAutomaticConfig) { emitEffect(Effect.UpdateIncomingConfigValidation) emitEffect(Effect.UpdateOutgoingConfigValidation) incomingValidationViewModel.initState(incomingViewModel.state.value.toValidationState()) outgoingValidationViewModel.initState(outgoingViewModel.state.value.toValidationState()) changeToSetupStep(SetupStep.INCOMING_VALIDATION) } else { changeToSetupStep(SetupStep.INCOMING_CONFIG) Loading @@ -95,7 +96,7 @@ class AccountSetupViewModel( } SetupStep.INCOMING_CONFIG -> { emitEffect(Effect.UpdateIncomingConfigValidation) incomingValidationViewModel.initState(incomingViewModel.state.value.toValidationState()) changeToSetupStep(SetupStep.INCOMING_VALIDATION) } Loading @@ -108,7 +109,7 @@ class AccountSetupViewModel( } SetupStep.OUTGOING_CONFIG -> { emitEffect(Effect.UpdateOutgoingConfigValidation) outgoingValidationViewModel.initState(outgoingViewModel.state.value.toValidationState()) changeToSetupStep(SetupStep.OUTGOING_VALIDATION) } Loading @@ -129,15 +130,11 @@ class AccountSetupViewModel( } private fun onFinish() { emitEffect(Effect.CollectExternalStates) } val autoDiscoveryState = autoDiscoveryViewModel.state.value val incomingState = incomingViewModel.state.value val outgoingState = outgoingViewModel.state.value val optionsState = optionsViewModel.state.value private fun onStateCollected( autoDiscoveryState: AccountAutoDiscoveryContract.State, incomingState: AccountIncomingConfigContract.State, outgoingState: AccountOutgoingConfigContract.State, optionsState: AccountOptionsContract.State, ) { viewModelScope.launch { val result = createAccount.execute( emailAddress = autoDiscoveryState.emailAddress.value, Loading
feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/AccountSetupScreenKtTest.kt +1 −30 Original line number Diff line number Diff line Loading @@ -7,11 +7,6 @@ import app.k9mail.core.ui.compose.theme.ThunderbirdTheme import app.k9mail.feature.account.setup.ui.AccountSetupContract.Effect import app.k9mail.feature.account.setup.ui.AccountSetupContract.SetupStep import app.k9mail.feature.account.setup.ui.AccountSetupContract.State import app.k9mail.feature.account.setup.ui.autodiscovery.FakeAccountAutoDiscoveryViewModel import app.k9mail.feature.account.setup.ui.incoming.FakeAccountIncomingConfigViewModel import app.k9mail.feature.account.setup.ui.options.FakeAccountOptionsViewModel import app.k9mail.feature.account.setup.ui.outgoing.FakeAccountOutgoingConfigViewModel import app.k9mail.feature.account.setup.ui.validation.FakeAccountValidationViewModel import assertk.assertThat import assertk.assertions.isEqualTo import kotlinx.coroutines.test.runTest Loading @@ -22,12 +17,6 @@ class AccountSetupScreenKtTest : ComposeTest() { @Test fun `should display correct screen for every setup step`() = runTest { val viewModel = FakeAccountSetupViewModel() val autoDiscoveryViewModel = FakeAccountAutoDiscoveryViewModel() val incomingViewModel = FakeAccountIncomingConfigViewModel() val incomingValidationViewModel = FakeAccountValidationViewModel() val outgoingViewModel = FakeAccountOutgoingConfigViewModel() val outgoingValidationViewModel = FakeAccountValidationViewModel() val optionsViewModel = FakeAccountOptionsViewModel() setContent { ThunderbirdTheme { Loading @@ -35,12 +24,6 @@ class AccountSetupScreenKtTest : ComposeTest() { onFinish = { }, onBack = { }, viewModel = viewModel, autoDiscoveryViewModel = autoDiscoveryViewModel, incomingViewModel = incomingViewModel, incomingValidationViewModel = incomingValidationViewModel, outgoingViewModel = outgoingViewModel, outgoingValidationViewModel = outgoingValidationViewModel, optionsViewModel = optionsViewModel, ) } } Loading @@ -54,13 +37,7 @@ class AccountSetupScreenKtTest : ComposeTest() { @Test fun `should delegate navigation effects`() = runTest { val initialState = State() val viewModel = FakeAccountSetupViewModel(initialState) val autoDiscoveryViewModel = FakeAccountAutoDiscoveryViewModel() val incomingViewModel = FakeAccountIncomingConfigViewModel() val incomingValidationViewModel = FakeAccountValidationViewModel() val outgoingViewModel = FakeAccountOutgoingConfigViewModel() val outgoingValidationViewModel = FakeAccountValidationViewModel() val optionsViewModel = FakeAccountOptionsViewModel() val viewModel = FakeAccountSetupViewModel(initialState = initialState) var onFinishCounter = 0 var onBackCounter = 0 Loading @@ -70,12 +47,6 @@ class AccountSetupScreenKtTest : ComposeTest() { onFinish = { onFinishCounter++ }, onBack = { onBackCounter++ }, viewModel = viewModel, autoDiscoveryViewModel = autoDiscoveryViewModel, incomingViewModel = incomingViewModel, incomingValidationViewModel = incomingValidationViewModel, outgoingViewModel = outgoingViewModel, outgoingValidationViewModel = outgoingValidationViewModel, optionsViewModel = optionsViewModel, ) } } Loading