Loading app-feature-preview/src/main/java/app/k9mail/feature/preview/FeatureModule.kt +2 −0 Original line number Diff line number Diff line package app.k9mail.feature.preview import app.k9mail.core.common.oauth.OAuthConfigurationFactory import app.k9mail.feature.account.common.AccountCommonExternalContract import app.k9mail.feature.account.edit.AccountEditExternalContract import app.k9mail.feature.account.setup.AccountSetupExternalContract import app.k9mail.feature.account.setup.featureAccountSetupModule Loading @@ -23,6 +24,7 @@ val accountModule: Module = module { single { InMemoryAccountStore() } .binds( arrayOf( AccountCommonExternalContract.AccountStateLoader::class, AccountSetupExternalContract.AccountCreator::class, AccountEditExternalContract.AccountUpdater::class, ), Loading app-feature-preview/src/main/java/app/k9mail/feature/preview/account/InMemoryAccountStore.kt +23 −1 Original line number Diff line number Diff line package app.k9mail.feature.preview.account import app.k9mail.feature.account.common.AccountCommonExternalContract.AccountStateLoader import app.k9mail.feature.account.common.domain.entity.Account import app.k9mail.feature.account.common.domain.entity.AccountState import app.k9mail.feature.account.common.domain.entity.AuthorizationState import app.k9mail.feature.account.edit.AccountEditExternalContract.AccountUpdater import app.k9mail.feature.account.edit.AccountEditExternalContract.AccountUpdater.AccountUpdaterResult import app.k9mail.feature.account.setup.AccountSetupExternalContract.AccountCreator Loading @@ -8,7 +11,15 @@ import app.k9mail.feature.account.setup.AccountSetupExternalContract.AccountCrea class InMemoryAccountStore( private val accountMap: MutableMap<String, Account> = mutableMapOf(), ) : AccountCreator, AccountUpdater { ) : AccountCreator, AccountUpdater, AccountStateLoader { suspend fun load(accountUuid: String): Account? { return accountMap[accountUuid] } override suspend fun loadAccountState(accountUuid: String): AccountState? { return accountMap[accountUuid]?.let { mapToAccountState(it) } } override suspend fun createAccount(account: Account): AccountCreatorResult { accountMap[account.uuid] = account Loading @@ -25,4 +36,15 @@ class InMemoryAccountStore( AccountUpdaterResult.Success(account.uuid) } } private fun mapToAccountState(account: Account): AccountState { return AccountState( uuid = account.uuid, emailAddress = account.emailAddress, incomingServerSettings = account.incomingServerSettings, outgoingServerSettings = account.outgoingServerSettings, authorizationState = account.authorizationState?.let { AuthorizationState(it) }, options = account.options, ) } } app/k9mail/src/main/java/com/fsck/k9/account/AccountModule.kt +7 −0 Original line number Diff line number Diff line package com.fsck.k9.account import app.k9mail.feature.account.common.AccountCommonExternalContract import app.k9mail.feature.account.edit.AccountEditExternalContract import app.k9mail.feature.account.setup.AccountSetupExternalContract import org.koin.android.ext.koin.androidApplication Loading @@ -21,6 +22,12 @@ val newAccountModule = module { ) } factory<AccountCommonExternalContract.AccountStateLoader> { AccountStateLoader( accountManager = get(), ) } factory<AccountEditExternalContract.AccountUpdater> { AccountUpdater( preferences = get(), Loading app/k9mail/src/main/java/com/fsck/k9/account/AccountStateLoader.kt 0 → 100644 +44 −0 Original line number Diff line number Diff line package com.fsck.k9.account import app.k9mail.feature.account.common.AccountCommonExternalContract import app.k9mail.feature.account.common.domain.entity.AccountState import app.k9mail.feature.account.common.domain.entity.AuthorizationState import com.fsck.k9.logging.Timber import com.fsck.k9.preferences.AccountManager import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import com.fsck.k9.Account as K9Account class AccountStateLoader( private val accountManager: AccountManager, private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, ) : AccountCommonExternalContract.AccountStateLoader { @Suppress("TooGenericExceptionCaught") override suspend fun loadAccountState(accountUuid: String): AccountState? { return try { withContext(coroutineDispatcher) { load(accountUuid) } } catch (e: Exception) { Timber.e(e, "Error while loading account") null } } private fun load(accountUuid: String): AccountState? { return accountManager.getAccount(accountUuid)?.let { mapToAccountState(it) } } private fun mapToAccountState(account: K9Account): AccountState { return AccountState( uuid = account.uuid, emailAddress = account.email, incomingServerSettings = account.incomingServerSettings, outgoingServerSettings = account.outgoingServerSettings, authorizationState = AuthorizationState(account.oAuthState), ) } } app/k9mail/src/test/java/com/fsck/k9/account/AccountStateLoaderTest.kt 0 → 100644 +80 −0 Original line number Diff line number Diff line package com.fsck.k9.account import app.k9mail.feature.account.common.domain.entity.AccountState import app.k9mail.feature.account.common.domain.entity.AuthorizationState import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isNull import com.fsck.k9.Account import com.fsck.k9.Identity import com.fsck.k9.mail.AuthType import com.fsck.k9.mail.ConnectionSecurity import com.fsck.k9.mail.ServerSettings import kotlinx.coroutines.test.runTest import org.junit.Test class AccountStateLoaderTest { @Test fun `loadAccountState() should return null when accountManager returns null`() = runTest { val accountManager = FakeAccountManager() val accountLoader = AccountStateLoader(accountManager) val result = accountLoader.loadAccountState("accountUuid") assertThat(result).isNull() } @Test fun `loadAccountState() should return account when present in accountManager`() = runTest { val accounts = mapOf( "accountUuid" to Account(uuid = "accountUuid").apply { identities = mutableListOf(Identity()) email = "emailAddress" incomingServerSettings = INCOMING_SERVER_SETTINGS outgoingServerSettings = OUTGOING_SERVER_SETTINGS oAuthState = "oAuthState" }, ) val accountManager = FakeAccountManager(accounts = accounts) val accountLoader = AccountStateLoader(accountManager) val result = accountLoader.loadAccountState("accountUuid") assertThat(result).isEqualTo( AccountState( uuid = "accountUuid", emailAddress = "emailAddress", incomingServerSettings = INCOMING_SERVER_SETTINGS, outgoingServerSettings = OUTGOING_SERVER_SETTINGS, authorizationState = AuthorizationState("oAuthState"), ), ) } private companion object { val INCOMING_SERVER_SETTINGS = ServerSettings( type = "imap", host = "imap.example.org", port = 143, connectionSecurity = ConnectionSecurity.SSL_TLS_REQUIRED, authenticationType = AuthType.PLAIN, username = "username", password = "password", clientCertificateAlias = null, extra = emptyMap(), ) val OUTGOING_SERVER_SETTINGS = ServerSettings( type = "smtp", host = "smtp.example.org", port = 587, connectionSecurity = ConnectionSecurity.SSL_TLS_REQUIRED, authenticationType = AuthType.PLAIN, username = "username", password = "password", clientCertificateAlias = null, extra = emptyMap(), ) } } Loading
app-feature-preview/src/main/java/app/k9mail/feature/preview/FeatureModule.kt +2 −0 Original line number Diff line number Diff line package app.k9mail.feature.preview import app.k9mail.core.common.oauth.OAuthConfigurationFactory import app.k9mail.feature.account.common.AccountCommonExternalContract import app.k9mail.feature.account.edit.AccountEditExternalContract import app.k9mail.feature.account.setup.AccountSetupExternalContract import app.k9mail.feature.account.setup.featureAccountSetupModule Loading @@ -23,6 +24,7 @@ val accountModule: Module = module { single { InMemoryAccountStore() } .binds( arrayOf( AccountCommonExternalContract.AccountStateLoader::class, AccountSetupExternalContract.AccountCreator::class, AccountEditExternalContract.AccountUpdater::class, ), Loading
app-feature-preview/src/main/java/app/k9mail/feature/preview/account/InMemoryAccountStore.kt +23 −1 Original line number Diff line number Diff line package app.k9mail.feature.preview.account import app.k9mail.feature.account.common.AccountCommonExternalContract.AccountStateLoader import app.k9mail.feature.account.common.domain.entity.Account import app.k9mail.feature.account.common.domain.entity.AccountState import app.k9mail.feature.account.common.domain.entity.AuthorizationState import app.k9mail.feature.account.edit.AccountEditExternalContract.AccountUpdater import app.k9mail.feature.account.edit.AccountEditExternalContract.AccountUpdater.AccountUpdaterResult import app.k9mail.feature.account.setup.AccountSetupExternalContract.AccountCreator Loading @@ -8,7 +11,15 @@ import app.k9mail.feature.account.setup.AccountSetupExternalContract.AccountCrea class InMemoryAccountStore( private val accountMap: MutableMap<String, Account> = mutableMapOf(), ) : AccountCreator, AccountUpdater { ) : AccountCreator, AccountUpdater, AccountStateLoader { suspend fun load(accountUuid: String): Account? { return accountMap[accountUuid] } override suspend fun loadAccountState(accountUuid: String): AccountState? { return accountMap[accountUuid]?.let { mapToAccountState(it) } } override suspend fun createAccount(account: Account): AccountCreatorResult { accountMap[account.uuid] = account Loading @@ -25,4 +36,15 @@ class InMemoryAccountStore( AccountUpdaterResult.Success(account.uuid) } } private fun mapToAccountState(account: Account): AccountState { return AccountState( uuid = account.uuid, emailAddress = account.emailAddress, incomingServerSettings = account.incomingServerSettings, outgoingServerSettings = account.outgoingServerSettings, authorizationState = account.authorizationState?.let { AuthorizationState(it) }, options = account.options, ) } }
app/k9mail/src/main/java/com/fsck/k9/account/AccountModule.kt +7 −0 Original line number Diff line number Diff line package com.fsck.k9.account import app.k9mail.feature.account.common.AccountCommonExternalContract import app.k9mail.feature.account.edit.AccountEditExternalContract import app.k9mail.feature.account.setup.AccountSetupExternalContract import org.koin.android.ext.koin.androidApplication Loading @@ -21,6 +22,12 @@ val newAccountModule = module { ) } factory<AccountCommonExternalContract.AccountStateLoader> { AccountStateLoader( accountManager = get(), ) } factory<AccountEditExternalContract.AccountUpdater> { AccountUpdater( preferences = get(), Loading
app/k9mail/src/main/java/com/fsck/k9/account/AccountStateLoader.kt 0 → 100644 +44 −0 Original line number Diff line number Diff line package com.fsck.k9.account import app.k9mail.feature.account.common.AccountCommonExternalContract import app.k9mail.feature.account.common.domain.entity.AccountState import app.k9mail.feature.account.common.domain.entity.AuthorizationState import com.fsck.k9.logging.Timber import com.fsck.k9.preferences.AccountManager import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import com.fsck.k9.Account as K9Account class AccountStateLoader( private val accountManager: AccountManager, private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, ) : AccountCommonExternalContract.AccountStateLoader { @Suppress("TooGenericExceptionCaught") override suspend fun loadAccountState(accountUuid: String): AccountState? { return try { withContext(coroutineDispatcher) { load(accountUuid) } } catch (e: Exception) { Timber.e(e, "Error while loading account") null } } private fun load(accountUuid: String): AccountState? { return accountManager.getAccount(accountUuid)?.let { mapToAccountState(it) } } private fun mapToAccountState(account: K9Account): AccountState { return AccountState( uuid = account.uuid, emailAddress = account.email, incomingServerSettings = account.incomingServerSettings, outgoingServerSettings = account.outgoingServerSettings, authorizationState = AuthorizationState(account.oAuthState), ) } }
app/k9mail/src/test/java/com/fsck/k9/account/AccountStateLoaderTest.kt 0 → 100644 +80 −0 Original line number Diff line number Diff line package com.fsck.k9.account import app.k9mail.feature.account.common.domain.entity.AccountState import app.k9mail.feature.account.common.domain.entity.AuthorizationState import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isNull import com.fsck.k9.Account import com.fsck.k9.Identity import com.fsck.k9.mail.AuthType import com.fsck.k9.mail.ConnectionSecurity import com.fsck.k9.mail.ServerSettings import kotlinx.coroutines.test.runTest import org.junit.Test class AccountStateLoaderTest { @Test fun `loadAccountState() should return null when accountManager returns null`() = runTest { val accountManager = FakeAccountManager() val accountLoader = AccountStateLoader(accountManager) val result = accountLoader.loadAccountState("accountUuid") assertThat(result).isNull() } @Test fun `loadAccountState() should return account when present in accountManager`() = runTest { val accounts = mapOf( "accountUuid" to Account(uuid = "accountUuid").apply { identities = mutableListOf(Identity()) email = "emailAddress" incomingServerSettings = INCOMING_SERVER_SETTINGS outgoingServerSettings = OUTGOING_SERVER_SETTINGS oAuthState = "oAuthState" }, ) val accountManager = FakeAccountManager(accounts = accounts) val accountLoader = AccountStateLoader(accountManager) val result = accountLoader.loadAccountState("accountUuid") assertThat(result).isEqualTo( AccountState( uuid = "accountUuid", emailAddress = "emailAddress", incomingServerSettings = INCOMING_SERVER_SETTINGS, outgoingServerSettings = OUTGOING_SERVER_SETTINGS, authorizationState = AuthorizationState("oAuthState"), ), ) } private companion object { val INCOMING_SERVER_SETTINGS = ServerSettings( type = "imap", host = "imap.example.org", port = 143, connectionSecurity = ConnectionSecurity.SSL_TLS_REQUIRED, authenticationType = AuthType.PLAIN, username = "username", password = "password", clientCertificateAlias = null, extra = emptyMap(), ) val OUTGOING_SERVER_SETTINGS = ServerSettings( type = "smtp", host = "smtp.example.org", port = 587, connectionSecurity = ConnectionSecurity.SSL_TLS_REQUIRED, authenticationType = AuthType.PLAIN, username = "username", password = "password", clientCertificateAlias = null, extra = emptyMap(), ) } }