All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.paoapps.fifi.di.Koin.kt Maven / Gradle / Ivy

Go to download

Kotlin Multiplatform Mobile framework for optimal code sharing between iOS and Android.

There is a newer version: 0.0.31
Show newest version
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