From f974df2678aced381f88c56c4392b5354da0a42a Mon Sep 17 00:00:00 2001 From: cketti Date: Mon, 15 Jan 2024 21:35:00 +0100 Subject: [PATCH] Add helper for composable previews whose children are using `koinInject()` --- core/ui/compose/common/build.gradle.kts | 1 + .../ui/compose/common/koin/KoinPreview.kt | 27 ++++++++++++++++ .../ui/compose/common/koin/KoinPreviewTest.kt | 32 +++++++++++++++++++ .../ui/ServerCertificateErrorContent.kt | 28 ++++++++-------- .../ui/ServerCertificateErrorScreen.kt | 27 +++++++++------- .../certificate/ui/ServerCertificateView.kt | 17 ++++++---- 6 files changed, 102 insertions(+), 30 deletions(-) create mode 100644 core/ui/compose/common/src/main/kotlin/app/k9mail/core/ui/compose/common/koin/KoinPreview.kt create mode 100644 core/ui/compose/common/src/test/kotlin/app/k9mail/core/ui/compose/common/koin/KoinPreviewTest.kt diff --git a/core/ui/compose/common/build.gradle.kts b/core/ui/compose/common/build.gradle.kts index 88b78e4cd..7a78a1465 100644 --- a/core/ui/compose/common/build.gradle.kts +++ b/core/ui/compose/common/build.gradle.kts @@ -11,4 +11,5 @@ dependencies { implementation(libs.androidx.compose.activity) testImplementation(projects.core.ui.compose.testing) + testImplementation(projects.core.ui.compose.designsystem) } diff --git a/core/ui/compose/common/src/main/kotlin/app/k9mail/core/ui/compose/common/koin/KoinPreview.kt b/core/ui/compose/common/src/main/kotlin/app/k9mail/core/ui/compose/common/koin/KoinPreview.kt new file mode 100644 index 000000000..751987324 --- /dev/null +++ b/core/ui/compose/common/src/main/kotlin/app/k9mail/core/ui/compose/common/koin/KoinPreview.kt @@ -0,0 +1,27 @@ +package app.k9mail.core.ui.compose.common.koin + +import androidx.compose.runtime.Composable +import org.koin.compose.KoinContext +import org.koin.core.Koin +import org.koin.dsl.ModuleDeclaration +import org.koin.dsl.module + +/** + * Helper to make Compose previews work when some dependencies are injected via Koin. + */ +fun koinPreview(moduleDeclaration: ModuleDeclaration): KoinPreview { + val koin = Koin().apply { + loadModules(listOf(module(moduleDeclaration = moduleDeclaration))) + } + + return KoinPreview(koin) +} + +class KoinPreview internal constructor(private val koin: Koin) { + @Composable + infix fun WithContent(content: @Composable () -> Unit) { + KoinContext(context = koin) { + content() + } + } +} diff --git a/core/ui/compose/common/src/test/kotlin/app/k9mail/core/ui/compose/common/koin/KoinPreviewTest.kt b/core/ui/compose/common/src/test/kotlin/app/k9mail/core/ui/compose/common/koin/KoinPreviewTest.kt new file mode 100644 index 000000000..61a5afdbc --- /dev/null +++ b/core/ui/compose/common/src/test/kotlin/app/k9mail/core/ui/compose/common/koin/KoinPreviewTest.kt @@ -0,0 +1,32 @@ +package app.k9mail.core.ui.compose.common.koin + +import androidx.compose.runtime.Composable +import app.k9mail.core.ui.compose.designsystem.atom.text.TextBody1 +import app.k9mail.core.ui.compose.testing.ComposeTest +import app.k9mail.core.ui.compose.testing.onNodeWithText +import kotlin.test.Test +import org.koin.compose.koinInject + +class KoinPreviewTest : ComposeTest() { + @Test + fun `koinPreview should make dependencies available in WithContent block`() = runComposeTest { + val injectString = "Test" + + setContent { + koinPreview { + factory { injectString } + } WithContent { + TestComposable() + } + } + + onNodeWithText(injectString).assertExists() + } +} + +@Composable +private fun TestComposable( + injected: String = koinInject(), +) { + TextBody1(text = injected) +} diff --git a/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateErrorContent.kt b/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateErrorContent.kt index 3e7d80e1f..ca6fc1d03 100644 --- a/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateErrorContent.kt +++ b/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateErrorContent.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import app.k9mail.core.ui.compose.common.baseline.withBaseline +import app.k9mail.core.ui.compose.common.koin.koinPreview import app.k9mail.core.ui.compose.common.resources.annotatedStringResource import app.k9mail.core.ui.compose.common.text.bold import app.k9mail.core.ui.compose.designsystem.atom.Icon @@ -38,13 +39,12 @@ internal fun ServerCertificateErrorContent( innerPadding: PaddingValues, state: State, scrollState: ScrollState, - serverNameFormatter: ServerNameFormatter = koinInject(), ) { ResponsiveWidthContainer(modifier = Modifier.padding(innerPadding)) { Column( modifier = Modifier.verticalScroll(scrollState), ) { - CertificateErrorOverview(state, serverNameFormatter) + CertificateErrorOverview(state) AnimatedContent( targetState = state.isShowServerCertificate, @@ -53,7 +53,6 @@ internal fun ServerCertificateErrorContent( if (isShowServerCertificate) { ServerCertificateView( serverCertificateProperties = state.certificateError!!.serverCertificateProperties, - serverNameFormatter = serverNameFormatter, ) } } @@ -62,7 +61,7 @@ internal fun ServerCertificateErrorContent( } @Composable -private fun CertificateErrorOverview(state: State, serverNameFormatter: ServerNameFormatter) { +private fun CertificateErrorOverview(state: State) { Column( modifier = Modifier.padding(all = MainTheme.spacings.double), ) { @@ -72,7 +71,7 @@ private fun CertificateErrorOverview(state: State, serverNameFormatter: ServerNa Spacer(modifier = Modifier.height(MainTheme.spacings.quadruple)) state.certificateError?.let { certificateError -> - CertificateErrorDescription(certificateError, serverNameFormatter) + CertificateErrorDescription(certificateError) } } } @@ -104,7 +103,7 @@ private fun WarningTitle() { @Composable private fun CertificateErrorDescription( certificateError: FormattedServerCertificateError, - serverNameFormatter: ServerNameFormatter, + serverNameFormatter: ServerNameFormatter = koinInject(), ) { TextBody1( text = annotatedStringResource( @@ -135,12 +134,15 @@ internal fun ServerCertificateErrorContentPreview() { ), ) - K9Theme { - ServerCertificateErrorContent( - innerPadding = PaddingValues(all = 0.dp), - state = state, - scrollState = rememberScrollState(), - serverNameFormatter = DefaultServerNameFormatter(), - ) + koinPreview { + factory { DefaultServerNameFormatter() } + } WithContent { + K9Theme { + ServerCertificateErrorContent( + innerPadding = PaddingValues(all = 0.dp), + state = state, + scrollState = rememberScrollState(), + ) + } } } diff --git a/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateErrorScreen.kt b/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateErrorScreen.kt index 26744342f..c1d72a2ec 100644 --- a/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateErrorScreen.kt +++ b/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateErrorScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import app.k9mail.core.ui.compose.common.annotation.PreviewDevices +import app.k9mail.core.ui.compose.common.koin.koinPreview import app.k9mail.core.ui.compose.common.mvi.observe import app.k9mail.core.ui.compose.designsystem.atom.Surface import app.k9mail.core.ui.compose.designsystem.atom.button.Button @@ -168,16 +169,20 @@ internal fun ServerCertificateErrorScreenK9Preview() { certificateChain = listOf(certificate), ) - K9Theme { - ServerCertificateErrorScreen( - onCertificateAccepted = {}, - onBack = {}, - viewModel = ServerCertificateErrorViewModel( - addServerCertificateException = { _, _, _ -> }, - certificateErrorRepository = InMemoryServerCertificateErrorRepository(serverCertificateError), - formatServerCertificateError = FormatServerCertificateError(), - initialState = State(isShowServerCertificate = false), - ), - ) + koinPreview { + factory { DefaultServerNameFormatter() } + } WithContent { + K9Theme { + ServerCertificateErrorScreen( + onCertificateAccepted = {}, + onBack = {}, + viewModel = ServerCertificateErrorViewModel( + addServerCertificateException = { _, _, _ -> }, + certificateErrorRepository = InMemoryServerCertificateErrorRepository(serverCertificateError), + formatServerCertificateError = FormatServerCertificateError(), + initialState = State(isShowServerCertificate = false), + ), + ) + } } } diff --git a/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateView.kt b/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateView.kt index 3636dfccb..ad08ff843 100644 --- a/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateView.kt +++ b/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/ui/ServerCertificateView.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import app.k9mail.core.ui.compose.common.koin.koinPreview import app.k9mail.core.ui.compose.designsystem.atom.text.TextBody1 import app.k9mail.core.ui.compose.designsystem.atom.text.TextHeadline6 import app.k9mail.core.ui.compose.designsystem.atom.text.TextOverline @@ -17,12 +18,13 @@ import app.k9mail.core.ui.compose.theme.K9Theme import app.k9mail.core.ui.compose.theme.MainTheme import app.k9mail.feature.account.server.certificate.R import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateProperties +import org.koin.compose.koinInject @Composable internal fun ServerCertificateView( serverCertificateProperties: ServerCertificateProperties, - serverNameFormatter: ServerNameFormatter, modifier: Modifier = Modifier, + serverNameFormatter: ServerNameFormatter = koinInject(), ) { Column( modifier = modifier.padding( @@ -108,10 +110,13 @@ internal fun ServerCertificateViewPreview() { "ea6e2b8db2b9da9197d5112fb369fd006da545de", ) - K9Theme { - ServerCertificateView( - serverCertificateProperties = serverCertificateProperties, - serverNameFormatter = DefaultServerNameFormatter(), - ) + koinPreview { + factory { DefaultServerNameFormatter() } + } WithContent { + K9Theme { + ServerCertificateView( + serverCertificateProperties = serverCertificateProperties, + ) + } } }