Merge pull request #7517 from thunderbird/compose_and_koin

Add helper for composable previews whose children are using `koinInject()`
This commit is contained in:
cketti 2024-01-16 13:19:50 +01:00 committed by GitHub
commit 5ebf7e50af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 102 additions and 30 deletions

View file

@ -11,4 +11,5 @@ dependencies {
implementation(libs.androidx.compose.activity)
testImplementation(projects.core.ui.compose.testing)
testImplementation(projects.core.ui.compose.designsystem)
}

View file

@ -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()
}
}
}

View file

@ -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)
}

View file

@ -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<ServerNameFormatter> { DefaultServerNameFormatter() }
} WithContent {
K9Theme {
ServerCertificateErrorContent(
innerPadding = PaddingValues(all = 0.dp),
state = state,
scrollState = rememberScrollState(),
)
}
}
}

View file

@ -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<ServerNameFormatter> { DefaultServerNameFormatter() }
} WithContent {
K9Theme {
ServerCertificateErrorScreen(
onCertificateAccepted = {},
onBack = {},
viewModel = ServerCertificateErrorViewModel(
addServerCertificateException = { _, _, _ -> },
certificateErrorRepository = InMemoryServerCertificateErrorRepository(serverCertificateError),
formatServerCertificateError = FormatServerCertificateError(),
initialState = State(isShowServerCertificate = false),
),
)
}
}
}

View file

@ -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<ServerNameFormatter> { DefaultServerNameFormatter() }
} WithContent {
K9Theme {
ServerCertificateView(
serverCertificateProperties = serverCertificateProperties,
)
}
}
}