From b55088f125961f518021a7b59e15329d52cd4cbe Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Fri, 10 Jan 2025 18:04:00 +0100 Subject: [PATCH] propose KoinMultiplatformApplication to handle KoinApplication behavior + automatically manage native context binding --- .../koin/compose/KoinApplication.android.kt | 2 +- .../org/koin/compose/KoinApplication.kt | 36 +++++++++++++++---- .../application/RememberKoinApplication.kt | 22 ++++++------ .../org/koin/compose/KoinApplication.js.kt | 2 +- .../org/koin/compose/KoinApplication.jvm.kt | 2 +- .../koin/compose/KoinApplication.native.kt | 2 +- .../koin/compose/KoinApplication.wasmJS.kt | 2 +- .../kotlin/org/koin/dsl/KoinConfiguration.kt | 4 ++- 8 files changed, 50 insertions(+), 22 deletions(-) diff --git a/projects/compose/koin-compose/src/androidMain/kotlin/org/koin/compose/KoinApplication.android.kt b/projects/compose/koin-compose/src/androidMain/kotlin/org/koin/compose/KoinApplication.android.kt index 9ff8e70fa..74ebbe852 100644 --- a/projects/compose/koin-compose/src/androidMain/kotlin/org/koin/compose/KoinApplication.android.kt +++ b/projects/compose/koin-compose/src/androidMain/kotlin/org/koin/compose/KoinApplication.android.kt @@ -19,7 +19,7 @@ import org.koin.dsl.koinConfiguration import org.koin.dsl.includes @Composable -internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration { +internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration { val appContext = LocalContext.current.applicationContext ?: error("Android ApplicationContext not found in current Compose context!") return koinConfiguration { androidContext(appContext) diff --git a/projects/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/KoinApplication.kt b/projects/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/KoinApplication.kt index b12847e3d..c689e9aa1 100644 --- a/projects/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/KoinApplication.kt +++ b/projects/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/KoinApplication.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.currentComposer import androidx.compose.runtime.remember import org.koin.compose.application.rememberKoinApplication +import org.koin.compose.application.rememberKoinMPApplication import org.koin.compose.error.UnknownKoinContext import org.koin.core.Koin import org.koin.core.KoinApplication @@ -107,11 +108,34 @@ private fun warningNoContext(ctx: Koin) { * Start a new Koin Application context and setup Compose context * if Koin's Default Context is already set, throw an error * - * Note: KoinApplication is calling composeMultiplatformConfiguration to help prepare/anticipate context setup, and avoid to have different configuration in KMP app + * @param application - Koin Application declaration lambda + * @param content - following compose function + * + * @throws org.koin.core.error.KoinApplicationAlreadyStartedException + * + * @author Arnaud Giuliani + */ +@OptIn(KoinInternalApi::class) +@Composable +fun KoinApplication( + application: KoinAppDeclaration, //Better to directly use KoinConfiguration class + content: @Composable () -> Unit +) { + val koin = rememberKoinApplication(application) + KoinContext(koin,content) +} + +/** + * Start a new Koin Application context, configure default context binding (android) & logger, setup Compose context + * if Koin's Default Context is already set, throw an error + * + * Call composeMultiplatformConfiguration to help prepare/anticipate context setup, and avoid to have different configuration in KMP app * this function takes care to setup Android context (androidContext, androidLogger) for you * @see composeMultiplatformConfiguration() * - * @param application - Koin Application declaration lambda + * @param config - Koin Application Configuration (use koinConfiguration { } to declare your Koin application) + * @see KoinConfiguration + * * @param logLevel - KMP active logger (androidLogger or printLogger) * @param content - following compose function * @@ -121,12 +145,12 @@ private fun warningNoContext(ctx: Koin) { */ @OptIn(KoinInternalApi::class) @Composable -fun KoinApplication( - application: KoinAppDeclaration, //Better to directly use KoinConfiguration class +fun KoinMultiplatformApplication( + config: KoinConfiguration, logLevel : Level = Level.INFO, content: @Composable () -> Unit ) { - val koin = rememberKoinApplication(application,logLevel) + val koin = rememberKoinMPApplication(config,logLevel) KoinContext(koin,content) } @@ -136,7 +160,7 @@ fun KoinApplication( */ @Composable @PublishedApi -internal expect fun composeMultiplatformConfiguration(loggerLevel : Level = Level.INFO, config : KoinApplication.() -> Unit) : KoinConfiguration +internal expect fun composeMultiplatformConfiguration(loggerLevel : Level = Level.INFO, config : KoinConfiguration) : KoinConfiguration /** * Use Compose with current existing Koin context, by default 'KoinPlatform.getKoin()' diff --git a/projects/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/application/RememberKoinApplication.kt b/projects/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/application/RememberKoinApplication.kt index 7a1e21ff1..2202e11e6 100644 --- a/projects/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/application/RememberKoinApplication.kt +++ b/projects/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/application/RememberKoinApplication.kt @@ -24,20 +24,22 @@ import org.koin.core.Koin import org.koin.core.annotation.KoinInternalApi import org.koin.core.logger.Level import org.koin.dsl.KoinAppDeclaration +import org.koin.dsl.KoinConfiguration import org.koin.dsl.koinApplication -/** - * Remember Koin Application to handle its closure if necessary - * - * @param koinApplication - * - * @author Arnaud Giuliani - */ +@Composable +internal inline fun rememberKoinApplication(noinline koinAppDeclaration: KoinAppDeclaration): Koin { + val wrapper = remember(koinAppDeclaration) { + CompositionKoinApplicationLoader(koinApplication(koinAppDeclaration)) + } + return wrapper.koin ?: error("Koin context has not been initialized in rememberKoinApplication") +} + @OptIn(KoinInternalApi::class) @Composable -inline fun rememberKoinApplication(noinline koinAppDeclaration: KoinAppDeclaration, logLevel: Level): Koin { - val configuration = composeMultiplatformConfiguration(logLevel, config = koinAppDeclaration) - val wrapper = remember(koinAppDeclaration,logLevel) { +internal inline fun rememberKoinMPApplication(configuration: KoinConfiguration, logLevel: Level): Koin { + val configuration = composeMultiplatformConfiguration(logLevel, config = configuration) + val wrapper = remember(configuration,logLevel) { CompositionKoinApplicationLoader(koinApplication(configuration)) } return wrapper.koin ?: error("Koin context has not been initialized in rememberKoinApplication") diff --git a/projects/compose/koin-compose/src/jsMain/kotlin/org/koin/compose/KoinApplication.js.kt b/projects/compose/koin-compose/src/jsMain/kotlin/org/koin/compose/KoinApplication.js.kt index a3551a118..5f7137700 100644 --- a/projects/compose/koin-compose/src/jsMain/kotlin/org/koin/compose/KoinApplication.js.kt +++ b/projects/compose/koin-compose/src/jsMain/kotlin/org/koin/compose/KoinApplication.js.kt @@ -10,7 +10,7 @@ import org.koin.dsl.includes import org.koin.mp.KoinPlatform @Composable -internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration { +internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration { return koinConfiguration { printLogger(loggerLevel) includes(config) diff --git a/projects/compose/koin-compose/src/jvmMain/kotlin/org/koin/compose/KoinApplication.jvm.kt b/projects/compose/koin-compose/src/jvmMain/kotlin/org/koin/compose/KoinApplication.jvm.kt index a3551a118..5f7137700 100644 --- a/projects/compose/koin-compose/src/jvmMain/kotlin/org/koin/compose/KoinApplication.jvm.kt +++ b/projects/compose/koin-compose/src/jvmMain/kotlin/org/koin/compose/KoinApplication.jvm.kt @@ -10,7 +10,7 @@ import org.koin.dsl.includes import org.koin.mp.KoinPlatform @Composable -internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration { +internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration { return koinConfiguration { printLogger(loggerLevel) includes(config) diff --git a/projects/compose/koin-compose/src/nativeMain/kotlin/org/koin/compose/KoinApplication.native.kt b/projects/compose/koin-compose/src/nativeMain/kotlin/org/koin/compose/KoinApplication.native.kt index a3551a118..5f7137700 100644 --- a/projects/compose/koin-compose/src/nativeMain/kotlin/org/koin/compose/KoinApplication.native.kt +++ b/projects/compose/koin-compose/src/nativeMain/kotlin/org/koin/compose/KoinApplication.native.kt @@ -10,7 +10,7 @@ import org.koin.dsl.includes import org.koin.mp.KoinPlatform @Composable -internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration { +internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration { return koinConfiguration { printLogger(loggerLevel) includes(config) diff --git a/projects/compose/koin-compose/src/wasmJsMain/kotlin/org/koin/compose/KoinApplication.wasmJS.kt b/projects/compose/koin-compose/src/wasmJsMain/kotlin/org/koin/compose/KoinApplication.wasmJS.kt index a3551a118..5f7137700 100644 --- a/projects/compose/koin-compose/src/wasmJsMain/kotlin/org/koin/compose/KoinApplication.wasmJS.kt +++ b/projects/compose/koin-compose/src/wasmJsMain/kotlin/org/koin/compose/KoinApplication.wasmJS.kt @@ -10,7 +10,7 @@ import org.koin.dsl.includes import org.koin.mp.KoinPlatform @Composable -internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration { +internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration { return koinConfiguration { printLogger(loggerLevel) includes(config) diff --git a/projects/core/koin-core/src/commonMain/kotlin/org/koin/dsl/KoinConfiguration.kt b/projects/core/koin-core/src/commonMain/kotlin/org/koin/dsl/KoinConfiguration.kt index 137e3e767..9052860f2 100644 --- a/projects/core/koin-core/src/commonMain/kotlin/org/koin/dsl/KoinConfiguration.kt +++ b/projects/core/koin-core/src/commonMain/kotlin/org/koin/dsl/KoinConfiguration.kt @@ -22,7 +22,9 @@ import org.koin.core.module.KoinApplicationDslMarker //TODO Koin 4.1 - KoinAppDeclaration migration type to KoinConfiguration /** - * Koin Configuration holder - use the koinConfiguration() function to define Koin configuration: + * Koin Configuration class holder, intended to replace KoinAppDeclaration that is a typealias on extension function + * + * use the koinConfiguration() function to define Koin configuration: * koinConfiguration { * modules(...) * }