From d677c542efa450dc469b18478f4d6ff08e479149 Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 28 Jun 2023 15:14:42 +0200 Subject: [PATCH] Add authentication type to incoming server settings screen --- .../setup/domain/entity/AuthenticationType.kt | 3 ++- .../mapper/AuthenticationTypeStringMapper.kt | 22 +++++++++++++++++++ .../incoming/AccountIncomingConfigContent.kt | 13 +++++++++++ .../incoming/AccountIncomingConfigContract.kt | 3 +++ .../AccountIncomingConfigViewModel.kt | 2 ++ .../setup/src/main/res/values/strings.xml | 5 +++++ .../AccountIncomingConfigStateMapperKtTest.kt | 2 ++ .../AccountIncomingConfigStateTest.kt | 2 ++ .../AccountIncomingConfigViewModelTest.kt | 12 ++++++++++ 9 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/common/mapper/AuthenticationTypeStringMapper.kt diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/domain/entity/AuthenticationType.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/domain/entity/AuthenticationType.kt index bd7ec2a0b..e78dc728b 100644 --- a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/domain/entity/AuthenticationType.kt +++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/domain/entity/AuthenticationType.kt @@ -2,9 +2,10 @@ package app.k9mail.feature.account.setup.domain.entity import kotlinx.collections.immutable.toImmutableList -internal enum class AuthenticationType { +enum class AuthenticationType { PasswordCleartext, PasswordEncrypted, + ClientCertificate, OAuth2, ; diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/common/mapper/AuthenticationTypeStringMapper.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/common/mapper/AuthenticationTypeStringMapper.kt new file mode 100644 index 000000000..0cf90c5d7 --- /dev/null +++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/common/mapper/AuthenticationTypeStringMapper.kt @@ -0,0 +1,22 @@ +package app.k9mail.feature.account.setup.ui.common.mapper + +import android.content.res.Resources +import app.k9mail.feature.account.setup.R +import app.k9mail.feature.account.setup.domain.entity.AuthenticationType + +internal fun AuthenticationType.toResourceString(resources: Resources): String { + return when (this) { + AuthenticationType.PasswordCleartext -> { + resources.getString(R.string.account_setup_authentication_password_cleartext) + } + AuthenticationType.PasswordEncrypted -> { + resources.getString(R.string.account_setup_authentication_password_encrypted) + } + AuthenticationType.ClientCertificate -> { + resources.getString(R.string.account_setup_authentication_client_certificate) + } + AuthenticationType.OAuth2 -> { + resources.getString(R.string.account_setup_authentication_client_oauth) + } + } +} diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigContent.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigContent.kt index 74839658a..8c4ea0895 100644 --- a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigContent.kt +++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigContent.kt @@ -26,12 +26,14 @@ 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.setup.R +import app.k9mail.feature.account.setup.domain.entity.AuthenticationType import app.k9mail.feature.account.setup.domain.entity.ConnectionSecurity import app.k9mail.feature.account.setup.domain.entity.IncomingProtocolType import app.k9mail.feature.account.setup.ui.common.item.ErrorItem import app.k9mail.feature.account.setup.ui.common.item.LoadingItem import app.k9mail.feature.account.setup.ui.common.item.SuccessItem import app.k9mail.feature.account.setup.ui.common.item.defaultItemPadding +import app.k9mail.feature.account.setup.ui.common.mapper.toResourceString import app.k9mail.feature.account.setup.ui.common.toResourceString import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigContract.Event import app.k9mail.feature.account.setup.ui.incoming.AccountIncomingConfigContract.State @@ -132,6 +134,17 @@ internal fun AccountIncomingConfigContent( ) } + item { + SelectInput( + options = AuthenticationType.all(), + optionToStringTransformation = { it.toResourceString(resources) }, + selectedOption = state.authenticationType, + onOptionChange = { onEvent(Event.AuthenticationTypeChanged(it)) }, + label = stringResource(id = R.string.account_setup_incoming_config_authentication_label), + contentPadding = defaultItemPadding(), + ) + } + item { TextInput( text = state.username.value, diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigContract.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigContract.kt index ea150906b..d4f424f18 100644 --- a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigContract.kt +++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigContract.kt @@ -2,6 +2,7 @@ package app.k9mail.feature.account.setup.ui.incoming import app.k9mail.core.common.domain.usecase.validation.ValidationResult import app.k9mail.core.ui.compose.common.mvi.UnidirectionalViewModel +import app.k9mail.feature.account.setup.domain.entity.AuthenticationType import app.k9mail.feature.account.setup.domain.entity.ConnectionSecurity import app.k9mail.feature.account.setup.domain.entity.IncomingProtocolType import app.k9mail.feature.account.setup.domain.entity.toDefaultPort @@ -23,6 +24,7 @@ interface AccountIncomingConfigContract { val port: NumberInputField = NumberInputField( IncomingProtocolType.DEFAULT.toDefaultPort(IncomingProtocolType.DEFAULT.defaultConnectionSecurity), ), + val authenticationType: AuthenticationType = AuthenticationType.PasswordCleartext, val username: StringInputField = StringInputField(), val password: StringInputField = StringInputField(), val clientCertificate: String = "", @@ -40,6 +42,7 @@ interface AccountIncomingConfigContract { data class ServerChanged(val server: String) : Event() data class SecurityChanged(val security: ConnectionSecurity) : Event() data class PortChanged(val port: Long?) : Event() + data class AuthenticationTypeChanged(val authenticationType: AuthenticationType) : Event() data class UsernameChanged(val username: String) : Event() data class PasswordChanged(val password: String) : Event() data class ClientCertificateChanged(val clientCertificate: String) : Event() diff --git a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigViewModel.kt b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigViewModel.kt index fe170b0fd..b452716fe 100644 --- a/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigViewModel.kt +++ b/feature/account/setup/src/main/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigViewModel.kt @@ -32,12 +32,14 @@ internal class AccountIncomingConfigViewModel( } } + @Suppress("CyclomaticComplexMethod") override fun event(event: Event) { when (event) { is Event.ProtocolTypeChanged -> updateProtocolType(event.protocolType) is Event.ServerChanged -> updateState { it.copy(server = it.server.updateValue(event.server)) } is Event.SecurityChanged -> updateSecurity(event.security) is Event.PortChanged -> updateState { it.copy(port = it.port.updateValue(event.port)) } + is Event.AuthenticationTypeChanged -> updateState { it.copy(authenticationType = event.authenticationType) } is Event.UsernameChanged -> updateState { it.copy(username = it.username.updateValue(event.username)) } is Event.PasswordChanged -> updateState { it.copy(password = it.password.updateValue(event.password)) } is Event.ClientCertificateChanged -> updateState { it.copy(clientCertificate = event.clientCertificate) } diff --git a/feature/account/setup/src/main/res/values/strings.xml b/feature/account/setup/src/main/res/values/strings.xml index bd0812d54..b7c6c6e48 100644 --- a/feature/account/setup/src/main/res/values/strings.xml +++ b/feature/account/setup/src/main/res/values/strings.xml @@ -7,6 +7,10 @@ None SSL/TLS StartTLS + Normal password + Encrypted password + Client certificate + OAuth 2.0 None available Network @@ -43,6 +47,7 @@ Protocol Server Security + Authentication Auto-detect IMAP namespace IMAP path prefix Use compression diff --git a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigStateMapperKtTest.kt b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigStateMapperKtTest.kt index eab9151ee..b59140a3a 100644 --- a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigStateMapperKtTest.kt +++ b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigStateMapperKtTest.kt @@ -1,5 +1,6 @@ package app.k9mail.feature.account.setup.ui.incoming +import app.k9mail.feature.account.setup.domain.entity.AuthenticationType import app.k9mail.feature.account.setup.domain.entity.ConnectionSecurity import app.k9mail.feature.account.setup.domain.entity.IncomingProtocolType import app.k9mail.feature.account.setup.domain.entity.MailConnectionSecurity @@ -21,6 +22,7 @@ class AccountIncomingConfigStateMapperKtTest { server = StringInputField(value = "imap.example.org"), port = NumberInputField(value = 993), security = ConnectionSecurity.TLS, + authenticationType = AuthenticationType.PasswordCleartext, username = StringInputField(value = "user"), password = StringInputField(value = "password"), clientCertificate = "", diff --git a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigStateTest.kt b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigStateTest.kt index 70410ac85..b9a8557a1 100644 --- a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigStateTest.kt +++ b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigStateTest.kt @@ -1,5 +1,6 @@ package app.k9mail.feature.account.setup.ui.incoming +import app.k9mail.feature.account.setup.domain.entity.AuthenticationType import app.k9mail.feature.account.setup.domain.entity.ConnectionSecurity import app.k9mail.feature.account.setup.domain.entity.IncomingProtocolType import app.k9mail.feature.account.setup.domain.entity.toImapDefaultPort @@ -22,6 +23,7 @@ class AccountIncomingConfigStateTest { server = StringInputField(), security = ConnectionSecurity.DEFAULT, port = NumberInputField(value = ConnectionSecurity.DEFAULT.toImapDefaultPort()), + authenticationType = AuthenticationType.PasswordCleartext, username = StringInputField(), password = StringInputField(), clientCertificate = "", diff --git a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigViewModelTest.kt b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigViewModelTest.kt index 62f46bd74..c92169fb9 100644 --- a/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigViewModelTest.kt +++ b/feature/account/setup/src/test/kotlin/app/k9mail/feature/account/setup/ui/incoming/AccountIncomingConfigViewModelTest.kt @@ -4,6 +4,7 @@ import app.cash.turbine.testIn import app.k9mail.core.common.domain.usecase.validation.ValidationError import app.k9mail.core.common.domain.usecase.validation.ValidationResult import app.k9mail.core.ui.compose.testing.MainDispatcherRule +import app.k9mail.feature.account.setup.domain.entity.AuthenticationType import app.k9mail.feature.account.setup.domain.entity.ConnectionSecurity import app.k9mail.feature.account.setup.domain.entity.IncomingProtocolType import app.k9mail.feature.account.setup.domain.entity.toImapDefaultPort @@ -96,6 +97,17 @@ class AccountIncomingConfigViewModelTest { ) } + @Test + fun `should change authentication type when AuthenticationTypeChanged event is received`() = runTest { + eventStateTest( + viewModel = testSubject, + initialState = State(), + event = Event.AuthenticationTypeChanged(AuthenticationType.PasswordEncrypted), + expectedState = State(authenticationType = AuthenticationType.PasswordEncrypted), + coroutineScope = backgroundScope, + ) + } + @Test fun `should change state when UsernameChanged event is received`() = runTest { eventStateTest(