Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KoinMultiplatformApplication - Compose Application Start + Native Context binding #2114

Merged
merged 3 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import org.koin.dsl.koinConfiguration
import org.koin.dsl.includes

@Composable
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration {
val current = LocalContext.current
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(current)
androidContext(appContext)
androidLogger(loggerLevel)
includes(config)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -34,7 +35,6 @@ import org.koin.core.logger.Level
import org.koin.core.scope.Scope
import org.koin.dsl.KoinAppDeclaration
import org.koin.dsl.KoinConfiguration
import org.koin.dsl.koinApplication
import org.koin.mp.KoinPlatform
import org.koin.mp.KoinPlatformTools

Expand Down Expand Up @@ -105,12 +105,37 @@ private fun warningNoContext(ctx: Koin) {
}

/**
* Start a new Koin Application and associate it for Compose context
* if Koin's Default Context is already set,
* Start a new Koin Application context and setup Compose context
* if Koin's Default Context is already set, throw an error
*
* @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
*
Expand All @@ -120,13 +145,12 @@ private fun warningNoContext(ctx: Koin) {
*/
@OptIn(KoinInternalApi::class)
@Composable
fun KoinApplication(
application: KoinAppDeclaration,
fun KoinMultiplatformApplication(
config: KoinConfiguration,
logLevel : Level = Level.INFO,
content: @Composable () -> Unit
) {
val configuration = composeMultiplatformConfiguration(logLevel, config = application)
val koin = rememberKoinApplication(koinApplication(configuration))
val koin = rememberKoinMPApplication(config,logLevel)
KoinContext(koin,content)
}

Expand All @@ -135,7 +159,8 @@ fun KoinApplication(
* - Help handle automatically Android Logger Anticipate Android context injection, to having to setup androidContext() and androidLogger
*/
@Composable
internal expect fun composeMultiplatformConfiguration(loggerLevel : Level = Level.INFO, config : KoinApplication.() -> Unit) : KoinConfiguration
@PublishedApi
internal expect fun composeMultiplatformConfiguration(loggerLevel : Level = Level.INFO, config : KoinConfiguration) : KoinConfiguration

/**
* Use Compose with current existing Koin context, by default 'KoinPlatform.getKoin()'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,28 @@ package org.koin.compose.application

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import org.koin.compose.composeMultiplatformConfiguration
import org.koin.core.Koin
import org.koin.core.KoinApplication
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

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

/**
* Remember Koin Application to handle its closure if necessary
*
* @param koinApplication
*
* @author Arnaud Giuliani
*/
@OptIn(KoinInternalApi::class)
@Composable
inline fun rememberKoinApplication(koinApplication: KoinApplication): Koin {
val wrapper = remember {
CompositionKoinApplicationLoader(koinApplication)
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")
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(...)
* }
Expand Down
Loading