commonMain.com.paoapps.fifi.di.Koin.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fifi-framework Show documentation
Show all versions of fifi-framework Show documentation
Kotlin Multiplatform Mobile framework for optimal code sharing between iOS and Android.
package com.paoapps.fifi.di
import com.paoapps.fifi.api.ApiFactory
import com.paoapps.fifi.api.ClientApi
import com.paoapps.fifi.domain.LaunchData
import com.paoapps.fifi.localization.DefaultLanguageProvider
import com.paoapps.fifi.localization.LanguageProvider
import com.paoapps.fifi.model.EnvironmentSettings
import com.paoapps.fifi.model.Model
import com.paoapps.fifi.model.ModelEnvironment
import com.paoapps.fifi.model.ModelEnvironmentFactory
import com.paoapps.fifi.model.ModelHelper
import com.paoapps.fifi.model.datacontainer.CDataContainer
import com.paoapps.fifi.model.datacontainer.DataContainerImpl
import com.paoapps.fifi.model.datacontainer.DataProcessor
import com.paoapps.fifi.model.datacontainer.wrap
import com.paoapps.fifi.utils.settings
import com.russhwolf.settings.Settings
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.serialization.KSerializer
import org.koin.core.context.startKoin
import org.koin.core.logger.Logger
import org.koin.core.module.Module
import org.koin.core.qualifier.Qualifier
import org.koin.core.qualifier.named
import org.koin.core.qualifier.qualifier
import org.koin.dsl.KoinAppDeclaration
import org.koin.dsl.module
private fun initKoin(
modules: List,
model: () -> Model,
logger: Logger? = null,
appDeclaration: KoinAppDeclaration = {},
) = startKoin {
logger?.let { logger(it) }
appDeclaration()
modules(
sharedModule(model) + modules
)
}
interface PersistentDataRegistry {
fun registerPersistentData(
name: String,
serializer: KSerializer,
initialData: T,
dataPreProcessors: List> = emptyList(),
)
fun > registerPersistentData(
enum: E,
serializer: KSerializer,
initialData: T,
dataPreProcessors: List> = emptyList(),
)
}
val LAUNCH_DATA_QUALIFIER = named("launchData")
internal val DATA_CONTAINERS_QUALIFIER = named("dataContainers")
val API_FLOW_QUALIFIER = named("apiFlow")
internal val API_STATE_FLOW_QUALIFIER = named("apiStateFlow")
/**
* This is the main app definition that is used to initialize the FiFi framework.
*/
interface AppDefinition {
/**
* The version of the app.
*/
val appVersion: String
/**
* Whether the app is in debug mode or not.
*/
val isDebugMode: Boolean
/**
* The factory that is used to create the environment.
*/
val environmentFactory: ModelEnvironmentFactory
/**
* The factory that is used to create the api.
* @param appVersion The version of the app. Could be used for a custom user agent header.
*/
fun apiFactory(appVersion: String): ApiFactory
/**
* The koin modules that are shared between the app and the model.
*/
val modules: List
/**
* The Koin app declaration that is used to declare additional modules.
*/
fun appDeclaration(): KoinAppDeclaration = {}
/**
* The model that is used by the app. This is the "main" model of the app that provides access to data, repositories and apis.
*/
fun model(): Model
/**
* The data registrations that are used to register persistent data.
*/
fun dataRegistrations(): PersistentDataRegistry.() -> Unit = {}
/**
* The language provider that is used to localize the app.
*/
fun languageProvider(): LanguageProvider = DefaultLanguageProvider(fallbackLanguageCode = "en")
}
/**
* This initializes the FiFi framework and registers the app module with Koin.
*
* @param appDefinition The app definition that is used to initialize the FiFi framework.
*/
fun initKoinApp(
appDefinition: AppDefinition,
additionalModules: List = emptyList(),
logger: Logger? = null,
appDeclaration: KoinAppDeclaration = {},
) = initKoin(
modules = module {
single { settings(this) }
single { appDefinition.languageProvider() }
single { EnvironmentSettings() }
single { appDefinition.environmentFactory }
single { appDefinition.apiFactory(appDefinition.appVersion) }
single>(API_STATE_FLOW_QUALIFIER) {
val environmentFactory: ModelEnvironmentFactory = get()
val apiFactory: ApiFactory = get()
val settings: EnvironmentSettings = get()
MutableStateFlow(apiFactory.createApi(
settings.environmentName?.let {
environmentFactory.fromName(it)
} ?: environmentFactory.defaultEnvironment)
)
}
single>(API_FLOW_QUALIFIER) { get>(API_STATE_FLOW_QUALIFIER) }
val registry = object : PersistentDataRegistry {
val dataContainersQualifiers = mutableSetOf()
fun registerPersistentData(
qualifier: Qualifier,
serializer: KSerializer,
initialData: T,
dataPreProcessors: List>
) {
single(qualifier) {
val dataContainer = DataContainerImpl(serializer, initialData, dataPreProcessors).wrap()
ModelHelper(qualifier.value, dataContainer)
}
dataContainersQualifiers.add(qualifier)
}
override fun registerPersistentData(
name: String,
serializer: KSerializer,
initialData: T,
dataPreProcessors: List>
) {
registerPersistentData(named(name), serializer, initialData, dataPreProcessors)
}
override fun > registerPersistentData(
name: E,
serializer: KSerializer,
initialData: T,
dataPreProcessors: List>
) {
registerPersistentData(name.qualifier, serializer, initialData, dataPreProcessors)
}
}
registry.registerPersistentData(
qualifier = LAUNCH_DATA_QUALIFIER,
serializer = LaunchData.serializer(),
initialData = LaunchData(currentAppVersion = appDefinition.appVersion),
dataPreProcessors = listOf(object: DataProcessor {
override fun process(data: LaunchData): LaunchData {
return data.copy(
isFirstLaunch = false,
previousAppVersion = if (data.currentAppVersion == appDefinition.appVersion) data.previousAppVersion else data.currentAppVersion,
currentAppVersion = appDefinition.appVersion
)
}
})
)
registry.apply(appDefinition.dataRegistrations())
single(DATA_CONTAINERS_QUALIFIER) {
val dataContainers = mutableMapOf>()
registry.dataContainersQualifiers.forEach { qualifier ->
val modelHelper: ModelHelper<*, Api> = get(qualifier)
dataContainers[modelHelper.name] = modelHelper.modelDataContainer.wrap()
}
dataContainers
}
} + appDefinition.modules + additionalModules,
model = { appDefinition.model() },
logger = logger
) {
this.apply(appDefinition.appDeclaration())
appDeclaration()
}
fun sharedModule(
model: () -> Model,
): Module {
return module {
single { model() }
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy