From d721153062ee673704de15b4cb25f2a204f3b3eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montw=C3=A9?= Date: Mon, 11 Sep 2023 17:52:28 +0200 Subject: [PATCH 1/4] Change server settings to support interaction mode --- .../account/common/domain/entity/InteractionMode.kt | 9 +++++++++ .../feature/account/common/ui/WithInteractionMode.kt | 10 ++++++++++ .../edit/ui/EditIncomingServerSettingsViewModel.kt | 2 ++ .../edit/ui/EditOutgoingServerSettingsViewModel.kt | 2 ++ .../feature/account/edit/AccountEditModuleKtTest.kt | 2 ++ .../account/server/settings/ServerSettingsModule.kt | 3 +++ .../ui/incoming/IncomingServerSettingsContract.kt | 3 ++- .../ui/incoming/IncomingServerSettingsScreen.kt | 3 +++ .../ui/incoming/IncomingServerSettingsViewModel.kt | 2 ++ .../fake/FakeIncomingServerSettingsViewModel.kt | 2 ++ .../ui/outgoing/OutgoingServerSettingsContract.kt | 3 ++- .../ui/outgoing/OutgoingServerSettingsScreen.kt | 3 +++ .../ui/outgoing/OutgoingServerSettingsViewModel.kt | 2 ++ .../fake/FakeOutgoingServerSettingsViewModel.kt | 2 ++ .../ui/incoming/IncomingServerSettingsScreenKtTest.kt | 2 +- .../ui/incoming/IncomingServerSettingsViewModelTest.kt | 3 +++ .../ui/outgoing/OutgoingServerSettingsScreenKtTest.kt | 2 +- .../ui/outgoing/OutgoingServerSettingsViewModelTest.kt | 2 ++ .../feature/account/setup/AccountSetupModuleKtTest.kt | 2 ++ 19 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/domain/entity/InteractionMode.kt create mode 100644 feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/WithInteractionMode.kt diff --git a/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/domain/entity/InteractionMode.kt b/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/domain/entity/InteractionMode.kt new file mode 100644 index 00000000000..c4ffe81bff7 --- /dev/null +++ b/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/domain/entity/InteractionMode.kt @@ -0,0 +1,9 @@ +package app.k9mail.feature.account.common.domain.entity + +/** + * Enum representing the mode a user is interacting with an account or setting. + */ +enum class InteractionMode { + Create, + Edit, +} diff --git a/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/WithInteractionMode.kt b/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/WithInteractionMode.kt new file mode 100644 index 00000000000..f43fb945b7d --- /dev/null +++ b/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/WithInteractionMode.kt @@ -0,0 +1,10 @@ +package app.k9mail.feature.account.common.ui + +import app.k9mail.feature.account.common.domain.entity.InteractionMode + +/** + * Interface for screens that can be used in different interaction modes. + */ +interface WithInteractionMode { + val mode: InteractionMode +} diff --git a/feature/account/edit/src/main/kotlin/app/k9mail/feature/account/edit/ui/EditIncomingServerSettingsViewModel.kt b/feature/account/edit/src/main/kotlin/app/k9mail/feature/account/edit/ui/EditIncomingServerSettingsViewModel.kt index 23a04c604a7..e873747e379 100644 --- a/feature/account/edit/src/main/kotlin/app/k9mail/feature/account/edit/ui/EditIncomingServerSettingsViewModel.kt +++ b/feature/account/edit/src/main/kotlin/app/k9mail/feature/account/edit/ui/EditIncomingServerSettingsViewModel.kt @@ -2,6 +2,7 @@ package app.k9mail.feature.account.edit.ui import androidx.lifecycle.viewModelScope import app.k9mail.feature.account.common.domain.AccountDomainContract +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.edit.domain.AccountEditDomainContract import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsViewModel @@ -15,6 +16,7 @@ class EditIncomingServerSettingsViewModel( accountStateRepository: AccountDomainContract.AccountStateRepository, initialState: IncomingServerSettingsContract.State = IncomingServerSettingsContract.State(), ) : IncomingServerSettingsViewModel( + mode = InteractionMode.Edit, validator = validator, accountStateRepository = accountStateRepository, initialState = initialState, diff --git a/feature/account/edit/src/main/kotlin/app/k9mail/feature/account/edit/ui/EditOutgoingServerSettingsViewModel.kt b/feature/account/edit/src/main/kotlin/app/k9mail/feature/account/edit/ui/EditOutgoingServerSettingsViewModel.kt index 67453cbe0d0..a6f8287f69e 100644 --- a/feature/account/edit/src/main/kotlin/app/k9mail/feature/account/edit/ui/EditOutgoingServerSettingsViewModel.kt +++ b/feature/account/edit/src/main/kotlin/app/k9mail/feature/account/edit/ui/EditOutgoingServerSettingsViewModel.kt @@ -2,6 +2,7 @@ package app.k9mail.feature.account.edit.ui import androidx.lifecycle.viewModelScope import app.k9mail.feature.account.common.domain.AccountDomainContract +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.edit.domain.AccountEditDomainContract import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsViewModel @@ -15,6 +16,7 @@ class EditOutgoingServerSettingsViewModel( accountStateRepository: AccountDomainContract.AccountStateRepository, initialState: OutgoingServerSettingsContract.State = OutgoingServerSettingsContract.State(), ) : OutgoingServerSettingsViewModel( + mode = InteractionMode.Edit, validator = validator, accountStateRepository = accountStateRepository, initialState = initialState, diff --git a/feature/account/edit/src/test/kotlin/app/k9mail/feature/account/edit/AccountEditModuleKtTest.kt b/feature/account/edit/src/test/kotlin/app/k9mail/feature/account/edit/AccountEditModuleKtTest.kt index 41954b79672..696854a4096 100644 --- a/feature/account/edit/src/test/kotlin/app/k9mail/feature/account/edit/AccountEditModuleKtTest.kt +++ b/feature/account/edit/src/test/kotlin/app/k9mail/feature/account/edit/AccountEditModuleKtTest.kt @@ -4,6 +4,7 @@ import android.content.Context import app.k9mail.core.common.oauth.OAuthConfigurationFactory import app.k9mail.feature.account.common.AccountCommonExternalContract import app.k9mail.feature.account.common.domain.entity.AccountState +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract @@ -58,6 +59,7 @@ class AccountEditModuleKtTest : KoinTest { ServerCertificateErrorContract.State::class, IncomingServerSettingsContract.State::class, OutgoingServerSettingsContract.State::class, + InteractionMode::class, ), ) diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ServerSettingsModule.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ServerSettingsModule.kt index 79002e6b6b1..8b1fcd8911f 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ServerSettingsModule.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ServerSettingsModule.kt @@ -1,5 +1,6 @@ package app.k9mail.feature.account.server.settings +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsValidator import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsViewModel @@ -16,6 +17,7 @@ val featureAccountServerSettingsModule: Module = module { viewModel { IncomingServerSettingsViewModel( + mode = InteractionMode.Create, validator = get(), accountStateRepository = get(), ) @@ -23,6 +25,7 @@ val featureAccountServerSettingsModule: Module = module { viewModel { OutgoingServerSettingsViewModel( + mode = InteractionMode.Create, validator = get(), accountStateRepository = get(), ) diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContract.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContract.kt index 07e203f1e76..517f20518c3 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContract.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContract.kt @@ -8,10 +8,11 @@ import app.k9mail.feature.account.common.domain.entity.IncomingProtocolType import app.k9mail.feature.account.common.domain.entity.toDefaultPort import app.k9mail.feature.account.common.domain.input.NumberInputField import app.k9mail.feature.account.common.domain.input.StringInputField +import app.k9mail.feature.account.common.ui.WithInteractionMode interface IncomingServerSettingsContract { - interface ViewModel : UnidirectionalViewModel + interface ViewModel : UnidirectionalViewModel, WithInteractionMode data class State( val protocolType: IncomingProtocolType = IncomingProtocolType.DEFAULT, diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt index 9340103d7d1..e1a54911b1c 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt @@ -10,6 +10,7 @@ import app.k9mail.core.ui.compose.common.mvi.observe import app.k9mail.core.ui.compose.designsystem.template.Scaffold import app.k9mail.core.ui.compose.theme.K9Theme import app.k9mail.core.ui.compose.theme.ThunderbirdTheme +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.common.ui.AccountTopAppBar import app.k9mail.feature.account.common.ui.WizardNavigationBar import app.k9mail.feature.account.common.ui.preview.PreviewAccountStateRepository @@ -70,6 +71,7 @@ internal fun IncomingServerSettingsScreenK9Preview() { onNext = {}, onBack = {}, viewModel = IncomingServerSettingsViewModel( + mode = InteractionMode.Create, validator = IncomingServerSettingsValidator(), accountStateRepository = PreviewAccountStateRepository(), ), @@ -85,6 +87,7 @@ internal fun IncomingServerSettingsScreenThunderbirdPreview() { onNext = {}, onBack = {}, viewModel = IncomingServerSettingsViewModel( + mode = InteractionMode.Create, validator = IncomingServerSettingsValidator(), accountStateRepository = PreviewAccountStateRepository(), ), diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsViewModel.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsViewModel.kt index 22f814cd97c..c0560fb0e03 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsViewModel.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsViewModel.kt @@ -5,6 +5,7 @@ import app.k9mail.core.ui.compose.common.mvi.BaseViewModel import app.k9mail.feature.account.common.domain.AccountDomainContract import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity import app.k9mail.feature.account.common.domain.entity.IncomingProtocolType +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.common.domain.entity.toDefaultPort import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.Effect import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.Event @@ -13,6 +14,7 @@ import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSett import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.ViewModel open class IncomingServerSettingsViewModel( + override val mode: InteractionMode, private val validator: Validator, private val accountStateRepository: AccountDomainContract.AccountStateRepository, initialState: State = State(), diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/fake/FakeIncomingServerSettingsViewModel.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/fake/FakeIncomingServerSettingsViewModel.kt index dec4c3a7594..b12966c23c8 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/fake/FakeIncomingServerSettingsViewModel.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/fake/FakeIncomingServerSettingsViewModel.kt @@ -1,12 +1,14 @@ package app.k9mail.feature.account.server.settings.ui.incoming.fake import app.k9mail.core.ui.compose.common.mvi.BaseViewModel +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.Effect import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.Event import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.State import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.ViewModel class FakeIncomingServerSettingsViewModel( + override val mode: InteractionMode = InteractionMode.Create, initialState: State = State(), ) : BaseViewModel(initialState), ViewModel { diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsContract.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsContract.kt index 27c6dce5f19..574a4dd6189 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsContract.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsContract.kt @@ -7,10 +7,11 @@ import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity import app.k9mail.feature.account.common.domain.entity.toSmtpDefaultPort import app.k9mail.feature.account.common.domain.input.NumberInputField import app.k9mail.feature.account.common.domain.input.StringInputField +import app.k9mail.feature.account.common.ui.WithInteractionMode interface OutgoingServerSettingsContract { - interface ViewModel : UnidirectionalViewModel + interface ViewModel : UnidirectionalViewModel, WithInteractionMode data class State( val server: StringInputField = StringInputField(), diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreen.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreen.kt index e06d230c483..f5af4475647 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreen.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreen.kt @@ -10,6 +10,7 @@ import app.k9mail.core.ui.compose.common.mvi.observe import app.k9mail.core.ui.compose.designsystem.template.Scaffold import app.k9mail.core.ui.compose.theme.K9Theme import app.k9mail.core.ui.compose.theme.ThunderbirdTheme +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.common.ui.AccountTopAppBar import app.k9mail.feature.account.common.ui.WizardNavigationBar import app.k9mail.feature.account.common.ui.preview.PreviewAccountStateRepository @@ -70,6 +71,7 @@ internal fun OutgoingServerSettingsScreenK9Preview() { onNext = {}, onBack = {}, viewModel = OutgoingServerSettingsViewModel( + mode = InteractionMode.Create, validator = OutgoingServerSettingsValidator(), accountStateRepository = PreviewAccountStateRepository(), ), @@ -85,6 +87,7 @@ internal fun OutgoingServerSettingsScreenThunderbirdPreview() { onNext = {}, onBack = {}, viewModel = OutgoingServerSettingsViewModel( + mode = InteractionMode.Create, validator = OutgoingServerSettingsValidator(), accountStateRepository = PreviewAccountStateRepository(), ), diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsViewModel.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsViewModel.kt index 34f37159890..b1dd4566eb7 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsViewModel.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsViewModel.kt @@ -4,6 +4,7 @@ import app.k9mail.core.common.domain.usecase.validation.ValidationResult import app.k9mail.core.ui.compose.common.mvi.BaseViewModel import app.k9mail.feature.account.common.domain.AccountDomainContract import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.common.domain.entity.toSmtpDefaultPort import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.Effect import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.Event @@ -12,6 +13,7 @@ import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSett import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.ViewModel open class OutgoingServerSettingsViewModel( + override val mode: InteractionMode, private val validator: Validator, private val accountStateRepository: AccountDomainContract.AccountStateRepository, initialState: State = State(), diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/fake/FakeOutgoingServerSettingsViewModel.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/fake/FakeOutgoingServerSettingsViewModel.kt index 60c3feb127d..f02f0f546f1 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/fake/FakeOutgoingServerSettingsViewModel.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/fake/FakeOutgoingServerSettingsViewModel.kt @@ -1,12 +1,14 @@ package app.k9mail.feature.account.server.settings.ui.outgoing.fake import app.k9mail.core.ui.compose.common.mvi.BaseViewModel +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.Effect import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.Event import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.State import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.ViewModel class FakeOutgoingServerSettingsViewModel( + override val mode: InteractionMode = InteractionMode.Create, initialState: State = State(), ) : BaseViewModel(initialState), ViewModel { diff --git a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreenKtTest.kt b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreenKtTest.kt index 26591d87a7e..f42b5f5b5fb 100644 --- a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreenKtTest.kt +++ b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreenKtTest.kt @@ -15,7 +15,7 @@ class IncomingServerSettingsScreenKtTest : ComposeTest() { @Test fun `should delegate navigation effects`() = runTest { val initialState = State() - val viewModel = FakeIncomingServerSettingsViewModel(initialState) + val viewModel = FakeIncomingServerSettingsViewModel(initialState = initialState) var onNextCounter = 0 var onBackCounter = 0 diff --git a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsViewModelTest.kt b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsViewModelTest.kt index d9ea32523dc..8ca6ab6b072 100644 --- a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsViewModelTest.kt +++ b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsViewModelTest.kt @@ -12,6 +12,7 @@ import app.k9mail.feature.account.common.domain.entity.AccountState import app.k9mail.feature.account.common.domain.entity.AuthenticationType import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity import app.k9mail.feature.account.common.domain.entity.IncomingProtocolType +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.common.domain.entity.MailConnectionSecurity import app.k9mail.feature.account.common.domain.entity.toImapDefaultPort import app.k9mail.feature.account.common.domain.entity.toPop3DefaultPort @@ -350,6 +351,7 @@ class IncomingServerSettingsViewModelTest { fun `should change state and not emit NavigateNext effect when OnNextClicked event received and input invalid`() = runTest { val testSubject = IncomingServerSettingsViewModel( + mode = InteractionMode.Create, validator = FakeIncomingServerSettingsValidator( serverAnswer = ValidationResult.Failure(TestError), ), @@ -398,6 +400,7 @@ class IncomingServerSettingsViewModelTest { validator: IncomingServerSettingsContract.Validator = FakeIncomingServerSettingsValidator(), repository: AccountDomainContract.AccountStateRepository = InMemoryAccountStateRepository(), ) = IncomingServerSettingsViewModel( + mode = InteractionMode.Create, validator = validator, accountStateRepository = repository, initialState = initialState, diff --git a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreenKtTest.kt b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreenKtTest.kt index a6237be5054..957c088a457 100644 --- a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreenKtTest.kt +++ b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreenKtTest.kt @@ -15,7 +15,7 @@ class OutgoingServerSettingsScreenKtTest : ComposeTest() { @Test fun `should delegate navigation effects`() = runTest { val initialState = State() - val viewModel = FakeOutgoingServerSettingsViewModel(initialState) + val viewModel = FakeOutgoingServerSettingsViewModel(initialState = initialState) var onNextCounter = 0 var onBackCounter = 0 diff --git a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsViewModelTest.kt b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsViewModelTest.kt index 988a94e5b26..e2448dee51d 100644 --- a/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsViewModelTest.kt +++ b/feature/account/server/settings/src/test/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsViewModelTest.kt @@ -11,6 +11,7 @@ import app.k9mail.feature.account.common.domain.AccountDomainContract import app.k9mail.feature.account.common.domain.entity.AccountState import app.k9mail.feature.account.common.domain.entity.AuthenticationType import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.common.domain.entity.MailConnectionSecurity import app.k9mail.feature.account.common.domain.entity.toSmtpDefaultPort import app.k9mail.feature.account.common.domain.input.NumberInputField @@ -305,6 +306,7 @@ class OutgoingServerSettingsViewModelTest { validator: OutgoingServerSettingsContract.Validator = FakeOutgoingServerSettingsValidator(), repository: AccountDomainContract.AccountStateRepository = InMemoryAccountStateRepository(), ) = OutgoingServerSettingsViewModel( + mode = InteractionMode.Create, validator = validator, accountStateRepository = repository, initialState = initialState, diff --git a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/AccountSetupModuleKtTest.kt b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/AccountSetupModuleKtTest.kt index 21acaf21944..da4ecf0e75c 100644 --- a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/AccountSetupModuleKtTest.kt +++ b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/AccountSetupModuleKtTest.kt @@ -4,6 +4,7 @@ import android.content.Context import app.k9mail.core.common.oauth.OAuthConfigurationFactory import app.k9mail.feature.account.common.AccountCommonExternalContract import app.k9mail.feature.account.common.domain.entity.AccountState +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.oauth.ui.AccountOAuthContract import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract @@ -77,6 +78,7 @@ class AccountSetupModuleKtTest : KoinTest { Context::class, Boolean::class, Class.forName("net.openid.appauth.AppAuthConfiguration").kotlin, + InteractionMode::class, ), ) From 66e1d44abfed573042771cce7d008ff5be8b50ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montw=C3=A9?= Date: Tue, 19 Sep 2023 10:44:06 +0200 Subject: [PATCH 2/4] Refactor server settings to move form content into own declaration --- .../incoming/IncomingServerSettingsContent.kt | 154 +----------------- .../ui/incoming/content/ImapFormItems.kt | 64 ++++++++ .../ui/incoming/content/IncomingFormItems.kt | 120 ++++++++++++++ .../outgoing/OutgoingServerSettingsContent.kt | 101 +----------- .../ui/outgoing/content/OutgoingFormItems.kt | 112 +++++++++++++ 5 files changed, 308 insertions(+), 243 deletions(-) create mode 100644 feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/ImapFormItems.kt create mode 100644 feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/IncomingFormItems.kt create mode 100644 feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/content/OutgoingFormItems.kt diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContent.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContent.kt index 447e6beb404..85957281454 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContent.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContent.kt @@ -2,39 +2,25 @@ package app.k9mail.feature.account.server.settings.ui.incoming import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource import app.k9mail.core.ui.compose.common.DevicePreviews -import app.k9mail.core.ui.compose.designsystem.molecule.input.CheckboxInput -import app.k9mail.core.ui.compose.designsystem.molecule.input.NumberInput -import app.k9mail.core.ui.compose.designsystem.molecule.input.PasswordInput -import app.k9mail.core.ui.compose.designsystem.molecule.input.SelectInput -import app.k9mail.core.ui.compose.designsystem.molecule.input.TextInput import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer import app.k9mail.core.ui.compose.theme.K9Theme import app.k9mail.core.ui.compose.theme.MainTheme import app.k9mail.core.ui.compose.theme.ThunderbirdTheme -import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity -import app.k9mail.feature.account.common.domain.entity.IncomingProtocolType -import app.k9mail.feature.account.common.ui.item.defaultItemPadding -import app.k9mail.feature.account.server.settings.R -import app.k9mail.feature.account.server.settings.ui.common.ClientCertificateInput -import app.k9mail.feature.account.server.settings.ui.common.mapper.toResourceString import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.Event import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.State +import app.k9mail.feature.account.server.settings.ui.incoming.content.incomingFormItems -@Suppress("LongMethod") @Composable internal fun IncomingServerSettingsContent( state: State, @@ -58,139 +44,11 @@ internal fun IncomingServerSettingsContent( horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default), ) { - item { - Spacer(modifier = Modifier.requiredHeight(MainTheme.sizes.smaller)) - } - - item { - SelectInput( - options = IncomingProtocolType.all(), - selectedOption = state.protocolType, - onOptionChange = { onEvent(Event.ProtocolTypeChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_protocol_type_label), - contentPadding = defaultItemPadding(), - ) - } - - item { - TextInput( - text = state.server.value, - errorMessage = state.server.error?.toResourceString(resources), - onTextChange = { onEvent(Event.ServerChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_server_label), - contentPadding = defaultItemPadding(), - ) - } - - item { - SelectInput( - options = ConnectionSecurity.all(), - optionToStringTransformation = { it.toResourceString(resources) }, - selectedOption = state.security, - onOptionChange = { onEvent(Event.SecurityChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_security_label), - contentPadding = defaultItemPadding(), - ) - } - - item { - NumberInput( - value = state.port.value, - errorMessage = state.port.error?.toResourceString(resources), - onValueChange = { onEvent(Event.PortChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_port_label), - contentPadding = defaultItemPadding(), - ) - } - - item { - SelectInput( - options = state.allowedAuthenticationTypes, - optionToStringTransformation = { it.toResourceString(resources) }, - selectedOption = state.authenticationType, - onOptionChange = { onEvent(Event.AuthenticationTypeChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_authentication_label), - contentPadding = defaultItemPadding(), - ) - } - - item { - TextInput( - text = state.username.value, - errorMessage = state.username.error?.toResourceString(resources), - onTextChange = { onEvent(Event.UsernameChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_username_label), - contentPadding = defaultItemPadding(), - ) - } - - if (state.isPasswordFieldVisible) { - item { - PasswordInput( - password = state.password.value, - errorMessage = state.password.error?.toResourceString(resources), - onPasswordChange = { onEvent(Event.PasswordChanged(it)) }, - contentPadding = defaultItemPadding(), - ) - } - } - - item { - ClientCertificateInput( - alias = state.clientCertificateAlias, - onValueChange = { onEvent(Event.ClientCertificateChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_client_certificate_label), - contentPadding = defaultItemPadding(), - ) - } - - if (state.protocolType == IncomingProtocolType.IMAP) { - item { - CheckboxInput( - text = stringResource(id = R.string.account_server_settings_incoming_imap_namespace_label), - checked = state.imapAutodetectNamespaceEnabled, - onCheckedChange = { onEvent(Event.ImapAutoDetectNamespaceChanged(it)) }, - contentPadding = defaultItemPadding(), - ) - } - - item { - if (state.imapAutodetectNamespaceEnabled) { - TextInput( - onTextChange = {}, - label = stringResource(id = R.string.account_server_settings_incoming_imap_prefix_label), - contentPadding = defaultItemPadding(), - isEnabled = false, - ) - } else { - TextInput( - text = state.imapPrefix.value, - errorMessage = state.imapPrefix.error?.toResourceString(resources), - onTextChange = { onEvent(Event.ImapPrefixChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_incoming_imap_prefix_label), - contentPadding = defaultItemPadding(), - ) - } - } - - item { - CheckboxInput( - text = stringResource(id = R.string.account_server_settings_incoming_imap_compression_label), - checked = state.imapUseCompression, - onCheckedChange = { onEvent(Event.ImapUseCompressionChanged(it)) }, - contentPadding = defaultItemPadding(), - ) - } - - item { - CheckboxInput( - text = stringResource(R.string.account_server_settings_incoming_imap_send_client_id_label), - checked = state.imapSendClientId, - onCheckedChange = { onEvent(Event.ImapSendClientIdChanged(it)) }, - contentPadding = defaultItemPadding(), - ) - } - } + incomingFormItems( + state = state, + onEvent = onEvent, + resources = resources, + ) } } } diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/ImapFormItems.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/ImapFormItems.kt new file mode 100644 index 00000000000..cdbba43aa73 --- /dev/null +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/ImapFormItems.kt @@ -0,0 +1,64 @@ +package app.k9mail.feature.account.server.settings.ui.incoming.content + +import android.content.res.Resources +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.ui.res.stringResource +import app.k9mail.core.ui.compose.designsystem.molecule.input.CheckboxInput +import app.k9mail.core.ui.compose.designsystem.molecule.input.TextInput +import app.k9mail.feature.account.common.ui.item.defaultItemPadding +import app.k9mail.feature.account.server.settings.R +import app.k9mail.feature.account.server.settings.ui.common.mapper.toResourceString +import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.Event +import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.State + +internal fun LazyListScope.imapFormItems( + state: State, + onEvent: (Event) -> Unit, + resources: Resources, +) { + item { + CheckboxInput( + text = stringResource(id = R.string.account_server_settings_incoming_imap_namespace_label), + checked = state.imapAutodetectNamespaceEnabled, + onCheckedChange = { onEvent(Event.ImapAutoDetectNamespaceChanged(it)) }, + contentPadding = defaultItemPadding(), + ) + } + + item { + if (state.imapAutodetectNamespaceEnabled) { + TextInput( + onTextChange = {}, + label = stringResource(id = R.string.account_server_settings_incoming_imap_prefix_label), + contentPadding = defaultItemPadding(), + isEnabled = false, + ) + } else { + TextInput( + text = state.imapPrefix.value, + errorMessage = state.imapPrefix.error?.toResourceString(resources), + onTextChange = { onEvent(Event.ImapPrefixChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_incoming_imap_prefix_label), + contentPadding = defaultItemPadding(), + ) + } + } + + item { + CheckboxInput( + text = stringResource(id = R.string.account_server_settings_incoming_imap_compression_label), + checked = state.imapUseCompression, + onCheckedChange = { onEvent(Event.ImapUseCompressionChanged(it)) }, + contentPadding = defaultItemPadding(), + ) + } + + item { + CheckboxInput( + text = stringResource(R.string.account_server_settings_incoming_imap_send_client_id_label), + checked = state.imapSendClientId, + onCheckedChange = { onEvent(Event.ImapSendClientIdChanged(it)) }, + contentPadding = defaultItemPadding(), + ) + } +} diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/IncomingFormItems.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/IncomingFormItems.kt new file mode 100644 index 00000000000..94c5364b608 --- /dev/null +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/IncomingFormItems.kt @@ -0,0 +1,120 @@ +package app.k9mail.feature.account.server.settings.ui.incoming.content + +import android.content.res.Resources +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import app.k9mail.core.ui.compose.designsystem.molecule.input.NumberInput +import app.k9mail.core.ui.compose.designsystem.molecule.input.PasswordInput +import app.k9mail.core.ui.compose.designsystem.molecule.input.SelectInput +import app.k9mail.core.ui.compose.designsystem.molecule.input.TextInput +import app.k9mail.core.ui.compose.theme.MainTheme +import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity +import app.k9mail.feature.account.common.domain.entity.IncomingProtocolType +import app.k9mail.feature.account.common.ui.item.defaultItemPadding +import app.k9mail.feature.account.server.settings.R +import app.k9mail.feature.account.server.settings.ui.common.ClientCertificateInput +import app.k9mail.feature.account.server.settings.ui.common.mapper.toResourceString +import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.Event +import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.State +import app.k9mail.feature.account.server.settings.ui.incoming.allowedAuthenticationTypes +import app.k9mail.feature.account.server.settings.ui.incoming.isPasswordFieldVisible + +@Suppress("LongMethod") +internal fun LazyListScope.incomingFormItems( + state: State, + onEvent: (Event) -> Unit, + resources: Resources, +) { + item { + Spacer(modifier = Modifier.requiredHeight(MainTheme.sizes.smaller)) + } + + item { + SelectInput( + options = IncomingProtocolType.all(), + selectedOption = state.protocolType, + onOptionChange = { onEvent(Event.ProtocolTypeChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_protocol_type_label), + contentPadding = defaultItemPadding(), + ) + } + + item { + TextInput( + text = state.server.value, + errorMessage = state.server.error?.toResourceString(resources), + onTextChange = { onEvent(Event.ServerChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_server_label), + contentPadding = defaultItemPadding(), + ) + } + + item { + SelectInput( + options = ConnectionSecurity.all(), + optionToStringTransformation = { it.toResourceString(resources) }, + selectedOption = state.security, + onOptionChange = { onEvent(Event.SecurityChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_security_label), + contentPadding = defaultItemPadding(), + ) + } + + item { + NumberInput( + value = state.port.value, + errorMessage = state.port.error?.toResourceString(resources), + onValueChange = { onEvent(Event.PortChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_port_label), + contentPadding = defaultItemPadding(), + ) + } + + item { + SelectInput( + options = state.allowedAuthenticationTypes, + optionToStringTransformation = { it.toResourceString(resources) }, + selectedOption = state.authenticationType, + onOptionChange = { onEvent(Event.AuthenticationTypeChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_authentication_label), + contentPadding = defaultItemPadding(), + ) + } + + item { + TextInput( + text = state.username.value, + errorMessage = state.username.error?.toResourceString(resources), + onTextChange = { onEvent(Event.UsernameChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_username_label), + contentPadding = defaultItemPadding(), + ) + } + + if (state.isPasswordFieldVisible) { + item { + PasswordInput( + password = state.password.value, + errorMessage = state.password.error?.toResourceString(resources), + onPasswordChange = { onEvent(Event.PasswordChanged(it)) }, + contentPadding = defaultItemPadding(), + ) + } + } + + item { + ClientCertificateInput( + alias = state.clientCertificateAlias, + onValueChange = { onEvent(Event.ClientCertificateChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_client_certificate_label), + contentPadding = defaultItemPadding(), + ) + } + + if (state.protocolType == IncomingProtocolType.IMAP) { + imapFormItems(state, onEvent, resources) + } +} diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsContent.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsContent.kt index 61a07cc54a6..bdac52dcf50 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsContent.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsContent.kt @@ -2,38 +2,25 @@ package app.k9mail.feature.account.server.settings.ui.outgoing import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource import app.k9mail.core.ui.compose.common.DevicePreviews -import app.k9mail.core.ui.compose.designsystem.molecule.input.NumberInput -import app.k9mail.core.ui.compose.designsystem.molecule.input.PasswordInput -import app.k9mail.core.ui.compose.designsystem.molecule.input.SelectInput -import app.k9mail.core.ui.compose.designsystem.molecule.input.TextInput import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer import app.k9mail.core.ui.compose.theme.K9Theme import app.k9mail.core.ui.compose.theme.MainTheme import app.k9mail.core.ui.compose.theme.ThunderbirdTheme -import app.k9mail.feature.account.common.domain.entity.AuthenticationType -import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity -import app.k9mail.feature.account.common.ui.item.defaultItemPadding -import app.k9mail.feature.account.server.settings.R -import app.k9mail.feature.account.server.settings.ui.common.ClientCertificateInput -import app.k9mail.feature.account.server.settings.ui.common.mapper.toResourceString import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.Event import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.State +import app.k9mail.feature.account.server.settings.ui.outgoing.content.outgoingFormItems -@Suppress("LongMethod") @Composable internal fun OutgoingServerSettingsContent( state: State, @@ -57,87 +44,11 @@ internal fun OutgoingServerSettingsContent( horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default), ) { - item { - Spacer(modifier = Modifier.requiredHeight(MainTheme.sizes.smaller)) - } - - item { - TextInput( - text = state.server.value, - errorMessage = state.server.error?.toResourceString(resources), - onTextChange = { onEvent(Event.ServerChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_server_label), - isRequired = true, - contentPadding = defaultItemPadding(), - ) - } - - item { - SelectInput( - options = ConnectionSecurity.all(), - optionToStringTransformation = { it.toResourceString(resources) }, - selectedOption = state.security, - onOptionChange = { onEvent(Event.SecurityChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_security_label), - contentPadding = defaultItemPadding(), - ) - } - - item { - NumberInput( - value = state.port.value, - errorMessage = state.port.error?.toResourceString(resources), - onValueChange = { onEvent(Event.PortChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_port_label), - isRequired = true, - contentPadding = defaultItemPadding(), - ) - } - - item { - SelectInput( - options = AuthenticationType.outgoing(), - optionToStringTransformation = { it.toResourceString(resources) }, - selectedOption = state.authenticationType, - onOptionChange = { onEvent(Event.AuthenticationTypeChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_authentication_label), - contentPadding = defaultItemPadding(), - ) - } - - if (state.isUsernameFieldVisible) { - item { - TextInput( - text = state.username.value, - errorMessage = state.username.error?.toResourceString(resources), - onTextChange = { onEvent(Event.UsernameChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_username_label), - isRequired = true, - contentPadding = defaultItemPadding(), - ) - } - } - - if (state.isPasswordFieldVisible) { - item { - PasswordInput( - password = state.password.value, - errorMessage = state.password.error?.toResourceString(resources), - onPasswordChange = { onEvent(Event.PasswordChanged(it)) }, - isRequired = true, - contentPadding = defaultItemPadding(), - ) - } - } - - item { - ClientCertificateInput( - alias = state.clientCertificateAlias, - onValueChange = { onEvent(Event.ClientCertificateChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_client_certificate_label), - contentPadding = defaultItemPadding(), - ) - } + outgoingFormItems( + state = state, + onEvent = onEvent, + resources = resources, + ) } } } diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/content/OutgoingFormItems.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/content/OutgoingFormItems.kt new file mode 100644 index 00000000000..ff579bb4101 --- /dev/null +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/content/OutgoingFormItems.kt @@ -0,0 +1,112 @@ +package app.k9mail.feature.account.server.settings.ui.outgoing.content + +import android.content.res.Resources +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import app.k9mail.core.ui.compose.designsystem.molecule.input.NumberInput +import app.k9mail.core.ui.compose.designsystem.molecule.input.PasswordInput +import app.k9mail.core.ui.compose.designsystem.molecule.input.SelectInput +import app.k9mail.core.ui.compose.designsystem.molecule.input.TextInput +import app.k9mail.core.ui.compose.theme.MainTheme +import app.k9mail.feature.account.common.domain.entity.AuthenticationType +import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity +import app.k9mail.feature.account.common.ui.item.defaultItemPadding +import app.k9mail.feature.account.server.settings.R +import app.k9mail.feature.account.server.settings.ui.common.ClientCertificateInput +import app.k9mail.feature.account.server.settings.ui.common.mapper.toResourceString +import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.Event +import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.State +import app.k9mail.feature.account.server.settings.ui.outgoing.isPasswordFieldVisible +import app.k9mail.feature.account.server.settings.ui.outgoing.isUsernameFieldVisible + +@Suppress("LongMethod") +internal fun LazyListScope.outgoingFormItems( + state: State, + onEvent: (Event) -> Unit, + resources: Resources, +) { + item { + Spacer(modifier = Modifier.requiredHeight(MainTheme.sizes.smaller)) + } + + item { + TextInput( + text = state.server.value, + errorMessage = state.server.error?.toResourceString(resources), + onTextChange = { onEvent(Event.ServerChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_server_label), + isRequired = true, + contentPadding = defaultItemPadding(), + ) + } + + item { + SelectInput( + options = ConnectionSecurity.all(), + optionToStringTransformation = { it.toResourceString(resources) }, + selectedOption = state.security, + onOptionChange = { onEvent(Event.SecurityChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_security_label), + contentPadding = defaultItemPadding(), + ) + } + + item { + NumberInput( + value = state.port.value, + errorMessage = state.port.error?.toResourceString(resources), + onValueChange = { onEvent(Event.PortChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_port_label), + isRequired = true, + contentPadding = defaultItemPadding(), + ) + } + + item { + SelectInput( + options = AuthenticationType.outgoing(), + optionToStringTransformation = { it.toResourceString(resources) }, + selectedOption = state.authenticationType, + onOptionChange = { onEvent(Event.AuthenticationTypeChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_authentication_label), + contentPadding = defaultItemPadding(), + ) + } + + if (state.isUsernameFieldVisible) { + item { + TextInput( + text = state.username.value, + errorMessage = state.username.error?.toResourceString(resources), + onTextChange = { onEvent(Event.UsernameChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_username_label), + isRequired = true, + contentPadding = defaultItemPadding(), + ) + } + } + + if (state.isPasswordFieldVisible) { + item { + PasswordInput( + password = state.password.value, + errorMessage = state.password.error?.toResourceString(resources), + onPasswordChange = { onEvent(Event.PasswordChanged(it)) }, + isRequired = true, + contentPadding = defaultItemPadding(), + ) + } + } + + item { + ClientCertificateInput( + alias = state.clientCertificateAlias, + onValueChange = { onEvent(Event.ClientCertificateChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_client_certificate_label), + contentPadding = defaultItemPadding(), + ) + } +} From c9003a5386183da4ef3bbe86da5af3b34d3294e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montw=C3=A9?= Date: Thu, 12 Oct 2023 16:21:30 +0200 Subject: [PATCH 3/4] Add AccountTopAppBarWithBackButton --- .../account/common/ui/AccountTopAppBar.kt | 20 +++----- .../ui/AccountTopAppBarWithBackButton.kt | 49 +++++++++++++++++++ .../incoming/IncomingServerSettingsScreen.kt | 14 ++++-- .../outgoing/OutgoingServerSettingsScreen.kt | 14 ++++-- 4 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/AccountTopAppBarWithBackButton.kt diff --git a/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/AccountTopAppBar.kt b/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/AccountTopAppBar.kt index daced9fb93f..4c76a81bc32 100644 --- a/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/AccountTopAppBar.kt +++ b/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/AccountTopAppBar.kt @@ -6,11 +6,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import app.k9mail.core.ui.compose.common.DevicePreviews import app.k9mail.core.ui.compose.designsystem.organism.TopAppBar -import app.k9mail.core.ui.compose.theme.K9Theme import app.k9mail.core.ui.compose.theme.MainTheme -import app.k9mail.core.ui.compose.theme.ThunderbirdTheme +import app.k9mail.core.ui.compose.theme.PreviewWithThemes import app.k9mail.feature.account.common.R +/** + * Top app bar for the account screens. + */ @Composable fun AccountTopAppBar( title: String, @@ -28,18 +30,8 @@ fun AccountTopAppBar( @DevicePreviews @Composable -internal fun AccountTopAppBarK9Preview() { - K9Theme { - AccountTopAppBar( - title = "Title", - ) - } -} - -@DevicePreviews -@Composable -internal fun AccountTopAppBarThunderbirdPreview() { - ThunderbirdTheme { +internal fun AccountTopAppBarPreview() { + PreviewWithThemes { AccountTopAppBar( title = "Title", ) diff --git a/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/AccountTopAppBarWithBackButton.kt b/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/AccountTopAppBarWithBackButton.kt new file mode 100644 index 00000000000..a1c66ab0343 --- /dev/null +++ b/feature/account/common/src/main/kotlin/app/k9mail/feature/account/common/ui/AccountTopAppBarWithBackButton.kt @@ -0,0 +1,49 @@ +package app.k9mail.feature.account.common.ui + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import app.k9mail.core.ui.compose.common.DevicePreviews +import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonIcon +import app.k9mail.core.ui.compose.designsystem.organism.TopAppBar +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.R + +/** + * Top app bar for the account screens with a back button. + */ +@Composable +fun AccountTopAppBarWithBackButton( + title: String, + modifier: Modifier = Modifier, + onBackClicked: () -> Unit, +) { + TopAppBar( + title = title, + modifier = modifier, + subtitle = stringResource(id = R.string.account_common_title), + titleContentPadding = PaddingValues( + start = MainTheme.spacings.default, + ), + navigationIcon = { + ButtonIcon( + onClick = onBackClicked, + imageVector = Icons.Outlined.arrowBack, + ) + }, + ) +} + +@DevicePreviews +@Composable +internal fun AccountTopAppBarWithBackButtonPreview() { + PreviewWithThemes { + AccountTopAppBarWithBackButton( + title = "Title", + onBackClicked = {}, + ) + } +} diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt index e1a54911b1c..6407a5b6d19 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt @@ -12,6 +12,7 @@ import app.k9mail.core.ui.compose.theme.K9Theme import app.k9mail.core.ui.compose.theme.ThunderbirdTheme import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.common.ui.AccountTopAppBar +import app.k9mail.feature.account.common.ui.AccountTopAppBarWithBackButton import app.k9mail.feature.account.common.ui.WizardNavigationBar import app.k9mail.feature.account.common.ui.preview.PreviewAccountStateRepository import app.k9mail.feature.account.server.settings.R @@ -43,9 +44,16 @@ fun IncomingServerSettingsScreen( Scaffold( topBar = { - AccountTopAppBar( - title = stringResource(id = R.string.account_server_settings_incoming_top_bar_title), - ) + if (viewModel.mode == InteractionMode.Edit) { + AccountTopAppBarWithBackButton( + title = stringResource(id = R.string.account_server_settings_incoming_top_bar_title), + onBackClicked = { dispatch(Event.OnBackClicked) }, + ) + } else { + AccountTopAppBar( + title = stringResource(id = R.string.account_server_settings_incoming_top_bar_title), + ) + } }, bottomBar = { WizardNavigationBar( diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreen.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreen.kt index f5af4475647..11673dc30f7 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreen.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/outgoing/OutgoingServerSettingsScreen.kt @@ -12,6 +12,7 @@ import app.k9mail.core.ui.compose.theme.K9Theme import app.k9mail.core.ui.compose.theme.ThunderbirdTheme import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.common.ui.AccountTopAppBar +import app.k9mail.feature.account.common.ui.AccountTopAppBarWithBackButton import app.k9mail.feature.account.common.ui.WizardNavigationBar import app.k9mail.feature.account.common.ui.preview.PreviewAccountStateRepository import app.k9mail.feature.account.server.settings.R @@ -43,9 +44,16 @@ fun OutgoingServerSettingsScreen( Scaffold( topBar = { - AccountTopAppBar( - title = stringResource(id = R.string.account_server_settings_outgoing_top_bar_title), - ) + if (viewModel.mode == InteractionMode.Edit) { + AccountTopAppBarWithBackButton( + title = stringResource(id = R.string.account_server_settings_outgoing_top_bar_title), + onBackClicked = { dispatch(Event.OnBackClicked) }, + ) + } else { + AccountTopAppBar( + title = stringResource(id = R.string.account_server_settings_outgoing_top_bar_title), + ) + } }, bottomBar = { WizardNavigationBar( From e898296d5841024e0470ba78882a4f322d497911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Martell=20Montw=C3=A9?= Date: Thu, 12 Oct 2023 17:00:34 +0200 Subject: [PATCH 4/4] Change IncomingFormItems to only add protocol when interaction mode is create --- .../incoming/IncomingServerSettingsContent.kt | 5 +++++ .../incoming/IncomingServerSettingsScreen.kt | 1 + .../ui/incoming/content/IncomingFormItems.kt | 20 +++++++++++-------- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContent.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContent.kt index 85957281454..83e39c27f2b 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContent.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsContent.kt @@ -17,12 +17,14 @@ import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer import app.k9mail.core.ui.compose.theme.K9Theme import app.k9mail.core.ui.compose.theme.MainTheme import app.k9mail.core.ui.compose.theme.ThunderbirdTheme +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.Event import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.State import app.k9mail.feature.account.server.settings.ui.incoming.content.incomingFormItems @Composable internal fun IncomingServerSettingsContent( + mode: InteractionMode, state: State, onEvent: (Event) -> Unit, contentPadding: PaddingValues, @@ -45,6 +47,7 @@ internal fun IncomingServerSettingsContent( verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default), ) { incomingFormItems( + mode = mode, state = state, onEvent = onEvent, resources = resources, @@ -58,6 +61,7 @@ internal fun IncomingServerSettingsContent( internal fun IncomingServerSettingsContentK9Preview() { K9Theme { IncomingServerSettingsContent( + mode = InteractionMode.Create, onEvent = { }, state = State(), contentPadding = PaddingValues(), @@ -70,6 +74,7 @@ internal fun IncomingServerSettingsContentK9Preview() { internal fun IncomingServerSettingsContentThunderbirdPreview() { ThunderbirdTheme { IncomingServerSettingsContent( + mode = InteractionMode.Create, onEvent = { }, state = State(), contentPadding = PaddingValues(), diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt index 6407a5b6d19..50b36dee6c7 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/IncomingServerSettingsScreen.kt @@ -64,6 +64,7 @@ fun IncomingServerSettingsScreen( modifier = modifier, ) { innerPadding -> IncomingServerSettingsContent( + mode = viewModel.mode, onEvent = { dispatch(it) }, state = state.value, contentPadding = innerPadding, diff --git a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/IncomingFormItems.kt b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/IncomingFormItems.kt index 94c5364b608..ce72ce3b6a6 100644 --- a/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/IncomingFormItems.kt +++ b/feature/account/server/settings/src/main/kotlin/app/k9mail/feature/account/server/settings/ui/incoming/content/IncomingFormItems.kt @@ -13,6 +13,7 @@ import app.k9mail.core.ui.compose.designsystem.molecule.input.TextInput import app.k9mail.core.ui.compose.theme.MainTheme import app.k9mail.feature.account.common.domain.entity.ConnectionSecurity import app.k9mail.feature.account.common.domain.entity.IncomingProtocolType +import app.k9mail.feature.account.common.domain.entity.InteractionMode import app.k9mail.feature.account.common.ui.item.defaultItemPadding import app.k9mail.feature.account.server.settings.R import app.k9mail.feature.account.server.settings.ui.common.ClientCertificateInput @@ -24,6 +25,7 @@ import app.k9mail.feature.account.server.settings.ui.incoming.isPasswordFieldVis @Suppress("LongMethod") internal fun LazyListScope.incomingFormItems( + mode: InteractionMode, state: State, onEvent: (Event) -> Unit, resources: Resources, @@ -32,14 +34,16 @@ internal fun LazyListScope.incomingFormItems( Spacer(modifier = Modifier.requiredHeight(MainTheme.sizes.smaller)) } - item { - SelectInput( - options = IncomingProtocolType.all(), - selectedOption = state.protocolType, - onOptionChange = { onEvent(Event.ProtocolTypeChanged(it)) }, - label = stringResource(id = R.string.account_server_settings_protocol_type_label), - contentPadding = defaultItemPadding(), - ) + if (mode == InteractionMode.Create) { + item { + SelectInput( + options = IncomingProtocolType.all(), + selectedOption = state.protocolType, + onOptionChange = { onEvent(Event.ProtocolTypeChanged(it)) }, + label = stringResource(id = R.string.account_server_settings_protocol_type_label), + contentPadding = defaultItemPadding(), + ) + } } item {