Merge pull request #7517 from thunderbird/compose_and_koin
Add helper for composable previews whose children are using `koinInject()`
This commit is contained in:
commit
5ebf7e50af
6 changed files with 102 additions and 30 deletions
|
@ -11,4 +11,5 @@ dependencies {
|
||||||
implementation(libs.androidx.compose.activity)
|
implementation(libs.androidx.compose.activity)
|
||||||
|
|
||||||
testImplementation(projects.core.ui.compose.testing)
|
testImplementation(projects.core.ui.compose.testing)
|
||||||
|
testImplementation(projects.core.ui.compose.designsystem)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import app.k9mail.core.ui.compose.common.baseline.withBaseline
|
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.resources.annotatedStringResource
|
||||||
import app.k9mail.core.ui.compose.common.text.bold
|
import app.k9mail.core.ui.compose.common.text.bold
|
||||||
import app.k9mail.core.ui.compose.designsystem.atom.Icon
|
import app.k9mail.core.ui.compose.designsystem.atom.Icon
|
||||||
|
@ -38,13 +39,12 @@ internal fun ServerCertificateErrorContent(
|
||||||
innerPadding: PaddingValues,
|
innerPadding: PaddingValues,
|
||||||
state: State,
|
state: State,
|
||||||
scrollState: ScrollState,
|
scrollState: ScrollState,
|
||||||
serverNameFormatter: ServerNameFormatter = koinInject(),
|
|
||||||
) {
|
) {
|
||||||
ResponsiveWidthContainer(modifier = Modifier.padding(innerPadding)) {
|
ResponsiveWidthContainer(modifier = Modifier.padding(innerPadding)) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.verticalScroll(scrollState),
|
modifier = Modifier.verticalScroll(scrollState),
|
||||||
) {
|
) {
|
||||||
CertificateErrorOverview(state, serverNameFormatter)
|
CertificateErrorOverview(state)
|
||||||
|
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
targetState = state.isShowServerCertificate,
|
targetState = state.isShowServerCertificate,
|
||||||
|
@ -53,7 +53,6 @@ internal fun ServerCertificateErrorContent(
|
||||||
if (isShowServerCertificate) {
|
if (isShowServerCertificate) {
|
||||||
ServerCertificateView(
|
ServerCertificateView(
|
||||||
serverCertificateProperties = state.certificateError!!.serverCertificateProperties,
|
serverCertificateProperties = state.certificateError!!.serverCertificateProperties,
|
||||||
serverNameFormatter = serverNameFormatter,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +61,7 @@ internal fun ServerCertificateErrorContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CertificateErrorOverview(state: State, serverNameFormatter: ServerNameFormatter) {
|
private fun CertificateErrorOverview(state: State) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(all = MainTheme.spacings.double),
|
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))
|
Spacer(modifier = Modifier.height(MainTheme.spacings.quadruple))
|
||||||
|
|
||||||
state.certificateError?.let { certificateError ->
|
state.certificateError?.let { certificateError ->
|
||||||
CertificateErrorDescription(certificateError, serverNameFormatter)
|
CertificateErrorDescription(certificateError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +103,7 @@ private fun WarningTitle() {
|
||||||
@Composable
|
@Composable
|
||||||
private fun CertificateErrorDescription(
|
private fun CertificateErrorDescription(
|
||||||
certificateError: FormattedServerCertificateError,
|
certificateError: FormattedServerCertificateError,
|
||||||
serverNameFormatter: ServerNameFormatter,
|
serverNameFormatter: ServerNameFormatter = koinInject(),
|
||||||
) {
|
) {
|
||||||
TextBody1(
|
TextBody1(
|
||||||
text = annotatedStringResource(
|
text = annotatedStringResource(
|
||||||
|
@ -135,12 +134,15 @@ internal fun ServerCertificateErrorContentPreview() {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
K9Theme {
|
koinPreview {
|
||||||
ServerCertificateErrorContent(
|
factory<ServerNameFormatter> { DefaultServerNameFormatter() }
|
||||||
innerPadding = PaddingValues(all = 0.dp),
|
} WithContent {
|
||||||
state = state,
|
K9Theme {
|
||||||
scrollState = rememberScrollState(),
|
ServerCertificateErrorContent(
|
||||||
serverNameFormatter = DefaultServerNameFormatter(),
|
innerPadding = PaddingValues(all = 0.dp),
|
||||||
)
|
state = state,
|
||||||
|
scrollState = rememberScrollState(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import app.k9mail.core.ui.compose.common.annotation.PreviewDevices
|
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.common.mvi.observe
|
||||||
import app.k9mail.core.ui.compose.designsystem.atom.Surface
|
import app.k9mail.core.ui.compose.designsystem.atom.Surface
|
||||||
import app.k9mail.core.ui.compose.designsystem.atom.button.Button
|
import app.k9mail.core.ui.compose.designsystem.atom.button.Button
|
||||||
|
@ -168,16 +169,20 @@ internal fun ServerCertificateErrorScreenK9Preview() {
|
||||||
certificateChain = listOf(certificate),
|
certificateChain = listOf(certificate),
|
||||||
)
|
)
|
||||||
|
|
||||||
K9Theme {
|
koinPreview {
|
||||||
ServerCertificateErrorScreen(
|
factory<ServerNameFormatter> { DefaultServerNameFormatter() }
|
||||||
onCertificateAccepted = {},
|
} WithContent {
|
||||||
onBack = {},
|
K9Theme {
|
||||||
viewModel = ServerCertificateErrorViewModel(
|
ServerCertificateErrorScreen(
|
||||||
addServerCertificateException = { _, _, _ -> },
|
onCertificateAccepted = {},
|
||||||
certificateErrorRepository = InMemoryServerCertificateErrorRepository(serverCertificateError),
|
onBack = {},
|
||||||
formatServerCertificateError = FormatServerCertificateError(),
|
viewModel = ServerCertificateErrorViewModel(
|
||||||
initialState = State(isShowServerCertificate = false),
|
addServerCertificateException = { _, _, _ -> },
|
||||||
),
|
certificateErrorRepository = InMemoryServerCertificateErrorRepository(serverCertificateError),
|
||||||
)
|
formatServerCertificateError = FormatServerCertificateError(),
|
||||||
|
initialState = State(isShowServerCertificate = false),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
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.TextBody1
|
||||||
import app.k9mail.core.ui.compose.designsystem.atom.text.TextHeadline6
|
import app.k9mail.core.ui.compose.designsystem.atom.text.TextHeadline6
|
||||||
import app.k9mail.core.ui.compose.designsystem.atom.text.TextOverline
|
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.core.ui.compose.theme.MainTheme
|
||||||
import app.k9mail.feature.account.server.certificate.R
|
import app.k9mail.feature.account.server.certificate.R
|
||||||
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateProperties
|
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateProperties
|
||||||
|
import org.koin.compose.koinInject
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ServerCertificateView(
|
internal fun ServerCertificateView(
|
||||||
serverCertificateProperties: ServerCertificateProperties,
|
serverCertificateProperties: ServerCertificateProperties,
|
||||||
serverNameFormatter: ServerNameFormatter,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
serverNameFormatter: ServerNameFormatter = koinInject(),
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier.padding(
|
modifier = modifier.padding(
|
||||||
|
@ -108,10 +110,13 @@ internal fun ServerCertificateViewPreview() {
|
||||||
"ea6e2b8db2b9da9197d5112fb369fd006da545de",
|
"ea6e2b8db2b9da9197d5112fb369fd006da545de",
|
||||||
)
|
)
|
||||||
|
|
||||||
K9Theme {
|
koinPreview {
|
||||||
ServerCertificateView(
|
factory<ServerNameFormatter> { DefaultServerNameFormatter() }
|
||||||
serverCertificateProperties = serverCertificateProperties,
|
} WithContent {
|
||||||
serverNameFormatter = DefaultServerNameFormatter(),
|
K9Theme {
|
||||||
)
|
ServerCertificateView(
|
||||||
|
serverCertificateProperties = serverCertificateProperties,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue