diff --git a/composeApp/src/androidMain/kotlin/com/jetbrains/spacetutorial/MainApplication.kt b/composeApp/src/androidMain/kotlin/com/jetbrains/spacetutorial/MainApplication.kt index b63a2b4..600c48d 100644 --- a/composeApp/src/androidMain/kotlin/com/jetbrains/spacetutorial/MainApplication.kt +++ b/composeApp/src/androidMain/kotlin/com/jetbrains/spacetutorial/MainApplication.kt @@ -1,12 +1,18 @@ package com.jetbrains.spacetutorial import android.app.Application -import com.jetbrains.spacetutorial.di.AndroidKoinApp +import com.jetbrains.spacetutorial.di.KoinApp +import org.koin.android.ext.koin.androidContext +import org.koin.ksp.generated.startKoin class MainApplication : Application() { override fun onCreate() { super.onCreate() - AndroidKoinApp.initKoin(this) + // use startKoin generated in KoinApp (thanks to @KoinApplication) + // allow to pass extra arguments like androidContext + KoinApp.startKoin { + androidContext(this@MainApplication) + } } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ff80f7e..16ec732 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ coroutinesVersion = "1.10.2" dateTimeVersion = "0.7.1" koin = "4.1.1" koin-ksp = "2.3.1" -ksp = "2.2.21-2.0.4" +ksp = "2.3.2" ktor = "3.1.3" sqlDelight = "2.1.0" lifecycleViewmodelCompose = "2.9.1" diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index c3f5018..2b95045 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -57,20 +57,14 @@ kotlin { implementation("io.insert-koin:koin-compose:4.1.1") } } -} -android { - namespace = "com.jetbrains.spacetutorial.shared" - compileSdk = libs.versions.android.compileSdk.get().toInt() - compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } - defaultConfig { - minSdk = libs.versions.android.minSdk.get().toInt() + // KSP Common sourceSet + sourceSets.named("commonMain").configure { + kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin") } } + sqldelight { databases { create("AppDatabase") { @@ -79,6 +73,7 @@ sqldelight { } } +// KSP Tasks dependencies { add("kspCommonMainMetadata", libs.koin.compiler) add("kspAndroid", libs.koin.compiler) @@ -86,3 +81,25 @@ dependencies { add("kspIosArm64", libs.koin.compiler) add("kspIosSimulatorArm64", libs.koin.compiler) } + +// KSP Metadata Trigger +tasks.matching { it.name.startsWith("ksp") && it.name != "kspCommonMainKotlinMetadata" }.configureEach { + dependsOn("kspCommonMainKotlinMetadata") +} + +ksp { + arg("KOIN_CONFIG_CHECK","true") +} + +android { + namespace = "com.jetbrains.spacetutorial.shared" + compileSdk = libs.versions.android.compileSdk.get().toInt() + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + defaultConfig { + minSdk = libs.versions.android.minSdk.get().toInt() + } +} + diff --git a/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/cache/AndroidDatabaseDriverFactory.kt b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/cache/AndroidDatabaseDriverFactory.kt index e631b6c..71329d1 100644 --- a/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/cache/AndroidDatabaseDriverFactory.kt +++ b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/cache/AndroidDatabaseDriverFactory.kt @@ -4,8 +4,8 @@ import android.content.Context import app.cash.sqldelight.db.SqlDriver import app.cash.sqldelight.driver.android.AndroidSqliteDriver -class AndroidDatabaseDriverFactory(private val context: Context) : DatabaseDriverFactory { - override fun createDriver(): SqlDriver { - return AndroidSqliteDriver(AppDatabase.Schema, context, "launch.db") - } -} \ No newline at end of file +//class AndroidDatabaseDriverFactory(private val context: Context) : DatabaseDriverFactory { +// override fun createDriver(): SqlDriver { +// return AndroidSqliteDriver(AppDatabase.Schema, context, "launch.db") +// } +//} \ No newline at end of file diff --git a/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.android.kt b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.android.kt new file mode 100644 index 0000000..f17e232 --- /dev/null +++ b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.android.kt @@ -0,0 +1,16 @@ +package com.jetbrains.spacetutorial.cache + +import app.cash.sqldelight.db.SqlDriver +import app.cash.sqldelight.driver.android.AndroidSqliteDriver +import com.jetbrains.spacetutorial.di.ContextWrapper +import org.koin.core.annotation.Single + +// Singleton - +// Uses ContextWrapper to inject Android context +@Single +actual class DatabaseDriverFactory actual constructor(val contextWrapper: ContextWrapper) { + actual fun createDriver(): SqlDriver { + // use of Android context + return AndroidSqliteDriver(AppDatabase.Schema, contextWrapper.context, "launch.db") + } +} \ No newline at end of file diff --git a/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AndroidKoinApp.kt b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AndroidKoinApp.kt index 323cdd8..767c8c5 100644 --- a/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AndroidKoinApp.kt +++ b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AndroidKoinApp.kt @@ -1,13 +1,13 @@ -package com.jetbrains.spacetutorial.di - -import android.content.Context -import org.koin.android.ext.koin.androidContext -import org.koin.core.annotation.KoinApplication -import org.koin.core.context.startKoin - -@KoinApplication(modules = [AndroidAppModule::class]) -object AndroidKoinApp { - fun initKoin(context: Context){ - startKoin { androidContext(context) } - } -} \ No newline at end of file +//package com.jetbrains.spacetutorial.di +// +//import android.content.Context +//import org.koin.android.ext.koin.androidContext +//import org.koin.core.annotation.KoinApplication +//import org.koin.core.context.startKoin +// +//@KoinApplication(modules = [AndroidAppModule::class]) +//object AndroidKoinApp { +// fun initKoin(context: Context){ +// startKoin { androidContext(context) } +// } +//} \ No newline at end of file diff --git a/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.android.kt b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.android.kt new file mode 100644 index 0000000..6dcff32 --- /dev/null +++ b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.android.kt @@ -0,0 +1,29 @@ +package com.jetbrains.spacetutorial.di + +import android.content.Context +import com.jetbrains.spacetutorial.RocketLaunchViewModel +import com.jetbrains.spacetutorial.SpaceXSDK +import org.koin.android.annotation.KoinViewModel +import org.koin.core.annotation.Module +import org.koin.core.annotation.Single +import org.koin.core.scope.Scope + +// Native Context Wrapper for Android +actual class ContextWrapper(val context : Context) + +// Native Module to define ContextWrapper +@Module +actual class ContextModule actual constructor() { + + // Uses Scope injection to retrieve dynamically the Android context + // Allow to have a stable Wrapper + @Single + actual fun providesContextWrapper(scope: Scope): ContextWrapper = ContextWrapper(scope.get()) +} + +@Module(includes = [CommonModule::class]) +actual class NativeModule { + + @KoinViewModel + fun rocketLaunchViewModel(sdk: SpaceXSDK) = RocketLaunchViewModel(sdk) +} \ No newline at end of file diff --git a/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt index 71908cb..136b5a2 100644 --- a/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt +++ b/shared/src/androidMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt @@ -1,26 +1,26 @@ -package com.jetbrains.spacetutorial.di - -import android.content.Context -import com.jetbrains.spacetutorial.RocketLaunchViewModel -import com.jetbrains.spacetutorial.SpaceXSDK -import com.jetbrains.spacetutorial.cache.AndroidDatabaseDriverFactory -import com.jetbrains.spacetutorial.network.SpaceXApi -import org.koin.android.annotation.KoinViewModel -import org.koin.core.annotation.Configuration -import org.koin.core.annotation.Module -import org.koin.core.annotation.Single - -@Module -@Configuration -class AndroidAppModule : AppModule { - @Single - override fun spaceApi() = SpaceXApi() - - @Single - fun spaceXSDK(api: SpaceXApi, context: Context) = - SpaceXSDK(databaseDriverFactory = AndroidDatabaseDriverFactory(context), api = api) - - @KoinViewModel - fun rocketLaunchViewModel(sdk: SpaceXSDK) = RocketLaunchViewModel(sdk) -} - +//package com.jetbrains.spacetutorial.di +// +//import android.content.Context +//import com.jetbrains.spacetutorial.RocketLaunchViewModel +//import com.jetbrains.spacetutorial.SpaceXSDK +//import com.jetbrains.spacetutorial.cache.AndroidDatabaseDriverFactory +//import com.jetbrains.spacetutorial.network.SpaceXApi +//import org.koin.android.annotation.KoinViewModel +//import org.koin.core.annotation.Configuration +//import org.koin.core.annotation.Module +//import org.koin.core.annotation.Single +// +//@Module +//@Configuration +//class AndroidAppModule : AppModule { +// @Single +// override fun spaceApi() = SpaceXApi() +// +// @Single +// fun spaceXSDK(api: SpaceXApi, context: Context) = +// SpaceXSDK(databaseDriverFactory = AndroidDatabaseDriverFactory(context), api = api) +// +// @KoinViewModel +// fun rocketLaunchViewModel(sdk: SpaceXSDK) = RocketLaunchViewModel(sdk) +//} +// diff --git a/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/SpaceXSDK.kt b/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/SpaceXSDK.kt index a1aea80..ed35d87 100644 --- a/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/SpaceXSDK.kt +++ b/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/SpaceXSDK.kt @@ -4,7 +4,9 @@ import com.jetbrains.spacetutorial.cache.Database import com.jetbrains.spacetutorial.cache.DatabaseDriverFactory import com.jetbrains.spacetutorial.entity.RocketLaunch import com.jetbrains.spacetutorial.network.SpaceXApi +import org.koin.core.annotation.Single +@Single class SpaceXSDK(databaseDriverFactory: DatabaseDriverFactory, val api: SpaceXApi) { private val database = Database(databaseDriverFactory) diff --git a/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.kt b/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.kt index ed41af3..7361f84 100644 --- a/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.kt +++ b/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.kt @@ -1,7 +1,11 @@ package com.jetbrains.spacetutorial.cache import app.cash.sqldelight.db.SqlDriver +import com.jetbrains.spacetutorial.di.ContextWrapper +import org.koin.core.annotation.Single -interface DatabaseDriverFactory { +// define Driver with ContextWrapper +@Single +expect class DatabaseDriverFactory(contextWrapper: ContextWrapper) { fun createDriver(): SqlDriver } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt b/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt index 3633094..f8bec69 100644 --- a/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt +++ b/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt @@ -1,7 +1,39 @@ package com.jetbrains.spacetutorial.di -import com.jetbrains.spacetutorial.network.SpaceXApi +import org.koin.core.annotation.ComponentScan +import org.koin.core.annotation.KoinApplication +import org.koin.core.annotation.Module +import org.koin.core.annotation.Single +import org.koin.core.scope.Scope -interface AppModule { - fun spaceApi(): SpaceXApi -} \ No newline at end of file +// Context Wrapper Pattern, to allow pass native context as KMP +expect class ContextWrapper + +// Define Context Wrapper +@Module +expect class ContextModule() { + + @Single + fun providesContextWrapper(scope : Scope) : ContextWrapper +} + +// Gather all common KMP components +@Module(includes = [ContextModule::class]) +@ComponentScan("com.jetbrains.spacetutorial") +class CommonModule + +// Native module, to give the hand back for native Components (like ViewModel on Android) +@Module(includes = [CommonModule::class]) +expect class NativeModule() + +// Main Module, uses includes +// KSP2 is introducing an issue and prevent any @Configuration scanning +// need to specify modules by hand +@Module(includes = [CommonModule::class, NativeModule::class]) +class AppModule + +// Main Koin Entry point +// includes modules to start +// KSP2 is introducing an issue and prevent any @Configuration scanning +@KoinApplication(modules = [AppModule::class]) +object KoinApp \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/network/SpaceXApi.kt b/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/network/SpaceXApi.kt index 66223cf..9106162 100644 --- a/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/network/SpaceXApi.kt +++ b/shared/src/commonMain/kotlin/com/jetbrains/spacetutorial/network/SpaceXApi.kt @@ -7,7 +7,9 @@ import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.request.get import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.json.Json +import org.koin.core.annotation.Single +@Single class SpaceXApi { private val httpClient = HttpClient { install(ContentNegotiation) { diff --git a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/KoinHelper.kt b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/KoinHelper.kt index 4aaae21..a5d014b 100644 --- a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/KoinHelper.kt +++ b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/KoinHelper.kt @@ -1,13 +1,13 @@ package com.jetbrains.spacetutorial +import com.jetbrains.spacetutorial.di.KoinApp import org.koin.ksp.generated.* import com.jetbrains.spacetutorial.entity.RocketLaunch import org.koin.core.component.KoinComponent import org.koin.core.component.inject -import com.jetbrains.spacetutorial.di.IOSKoinApp class KoinHelper : KoinComponent { - private val sdk: SpaceXSDK by inject() + private val sdk: SpaceXSDK by inject() suspend fun getLaunches(forceReload: Boolean): List { return sdk.getLaunches(forceReload = forceReload) @@ -15,5 +15,5 @@ class KoinHelper : KoinComponent { } fun initKoin() { - IOSKoinApp.startKoin() + KoinApp.startKoin() } \ No newline at end of file diff --git a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.ios.kt b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.ios.kt new file mode 100644 index 0000000..7fcc32c --- /dev/null +++ b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.ios.kt @@ -0,0 +1,11 @@ +package com.jetbrains.spacetutorial.cache + +import app.cash.sqldelight.db.SqlDriver +import app.cash.sqldelight.driver.native.NativeSqliteDriver +import com.jetbrains.spacetutorial.di.ContextWrapper +import org.koin.core.annotation.Single + +@Single +actual class DatabaseDriverFactory actual constructor(contextWrapper: ContextWrapper) { + actual fun createDriver(): SqlDriver = NativeSqliteDriver(AppDatabase.Schema, "launch.db") +} \ No newline at end of file diff --git a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.kt b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.kt index f1ba842..ef31bb5 100644 --- a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.kt +++ b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/cache/DatabaseDriverFactory.kt @@ -3,8 +3,8 @@ package com.jetbrains.spacetutorial.cache import app.cash.sqldelight.db.SqlDriver import app.cash.sqldelight.driver.native.NativeSqliteDriver -class IOSDatabaseDriverFactory : DatabaseDriverFactory { - override fun createDriver(): SqlDriver { - return NativeSqliteDriver(AppDatabase.Schema, "launch.db") - } -} \ No newline at end of file +//class IOSDatabaseDriverFactory : DatabaseDriverFactory { +// override fun createDriver(): SqlDriver { +// return NativeSqliteDriver(AppDatabase.Schema, "launch.db") +// } +//} \ No newline at end of file diff --git a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.ios.kt b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.ios.kt new file mode 100644 index 0000000..8ca2921 --- /dev/null +++ b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.ios.kt @@ -0,0 +1,19 @@ +package com.jetbrains.spacetutorial.di + +import org.koin.core.annotation.ComponentScan +import org.koin.core.annotation.Module +import org.koin.core.annotation.Single +import org.koin.core.scope.Scope + +actual class ContextWrapper() + +@Module +actual class ContextModule actual constructor() { + + @Single + actual fun providesContextWrapper(scope: Scope): ContextWrapper = ContextWrapper() +} + +@Module +@ComponentScan(" com.jetbrains.spacetutorial") +actual class NativeModule \ No newline at end of file diff --git a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt index adc60bb..a749f97 100644 --- a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt +++ b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/AppDi.kt @@ -1,21 +1,21 @@ -package com.jetbrains.spacetutorial.di - -import com.jetbrains.spacetutorial.SpaceXSDK -import com.jetbrains.spacetutorial.cache.IOSDatabaseDriverFactory -import com.jetbrains.spacetutorial.network.SpaceXApi -import org.koin.android.annotation.KoinViewModel -import org.koin.core.annotation.Configuration -import org.koin.core.annotation.Module -import org.koin.core.annotation.Single - -@Module -@Configuration -class IOSAppModule : AppModule { - @Single - override fun spaceApi() = SpaceXApi() - - @Single - fun spaceXSDK(api: SpaceXApi) = - SpaceXSDK(databaseDriverFactory = IOSDatabaseDriverFactory(), api = api) - -} \ No newline at end of file +//package com.jetbrains.spacetutorial.di +// +//import com.jetbrains.spacetutorial.SpaceXSDK +//import com.jetbrains.spacetutorial.cache.IOSDatabaseDriverFactory +//import com.jetbrains.spacetutorial.network.SpaceXApi +//import org.koin.android.annotation.KoinViewModel +//import org.koin.core.annotation.Configuration +//import org.koin.core.annotation.Module +//import org.koin.core.annotation.Single +// +//@Module +//@Configuration +//class IOSAppModule : AppModule { +// @Single +// override fun spaceApi() = SpaceXApi() +// +// @Single +// fun spaceXSDK(api: SpaceXApi) = +// SpaceXSDK(databaseDriverFactory = IOSDatabaseDriverFactory(), api = api) +// +//} \ No newline at end of file diff --git a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/IOSKoinApp.kt b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/IOSKoinApp.kt index 30e182a..6e1af96 100644 --- a/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/IOSKoinApp.kt +++ b/shared/src/iosMain/kotlin/com/jetbrains/spacetutorial/di/IOSKoinApp.kt @@ -1,6 +1,6 @@ -package com.jetbrains.spacetutorial.di - -import org.koin.core.annotation.KoinApplication - -@KoinApplication(modules = [IOSAppModule::class]) -object IOSKoinApp \ No newline at end of file +//package com.jetbrains.spacetutorial.di +// +//import org.koin.core.annotation.KoinApplication +// +//@KoinApplication(modules = [IOSAppModule::class]) +//object IOSKoinApp \ No newline at end of file