From 31cfd2b931e06ceb23db29c09bba08c3f9503ced Mon Sep 17 00:00:00 2001 From: KhooLy <73142442+KhooLy@users.noreply.github.com> Date: Mon, 13 Jul 2026 03:09:18 +0300 Subject: [PATCH] Add Koin as the DI mechanism for shared code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hilt is Android/Dagger-only and can't run on Kotlin/Native, so it can't be used for anything moving into :shared. Koin is the standard KMP alternative — this wires it up for real: a Koin module (sharedModule) providing GreetingViewModel via the koin viewmodel DSL, CmpSmokeTest now resolves it through koinViewModel() instead of constructing it directly, and AppApplication.onCreate() calls initSharedKoin() at startup so this isn't just compile-checked dead code — Koin actually starts alongside Hilt (the two coexist fine, verified by compiling the full app afterward). This is the pattern for every ViewModel/ScreenModel that moves to :shared going forward. HomeViewModel/DetailViewModel themselves stay Hilt-based in app for now — porting them means porting their repositories to KMP first, which is separate, larger work. Verified compiling for android, iosArm64, iosSimulatorArm64, and both app product flavors still build with Koin initialized at startup. --- app/src/main/java/com/fluxa/app/AppApplication.kt | 2 ++ gradle/libs.versions.toml | 7 +++++++ shared/build.gradle.kts | 4 ++++ .../kotlin/com/fluxa/app/shared/CmpSmokeTest.kt | 5 ++++- .../kotlin/com/fluxa/app/shared/di/InitKoin.kt | 9 +++++++++ .../kotlin/com/fluxa/app/shared/di/SharedModule.kt | 14 ++++++++++++++ 6 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 shared/src/commonMain/kotlin/com/fluxa/app/shared/di/InitKoin.kt create mode 100644 shared/src/commonMain/kotlin/com/fluxa/app/shared/di/SharedModule.kt diff --git a/app/src/main/java/com/fluxa/app/AppApplication.kt b/app/src/main/java/com/fluxa/app/AppApplication.kt index 898c5ed..e531408 100644 --- a/app/src/main/java/com/fluxa/app/AppApplication.kt +++ b/app/src/main/java/com/fluxa/app/AppApplication.kt @@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.AcraApplication import com.lagradost.cloudstream3.app import com.fluxa.app.common.AppStrings import com.fluxa.app.common.initialize +import com.fluxa.app.shared.di.initSharedKoin import com.fluxa.app.ui.catalog.EpisodeReleaseWorker import com.fluxa.app.plugins.PluginAutoUpdateWorker import com.fluxa.app.ui.catalog.TrailerResolver @@ -51,6 +52,7 @@ class AppApplication : Application(), SingletonImageLoader.Factory, Configuratio // CloudStream library's app singleton is auto-initialized by the library AppStrings.initialize(this) + initSharedKoin() TrailerResolver.init(cacheDir) PluginAutoUpdateWorker.enqueue(this) EpisodeReleaseWorker.enqueue(this) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 410747f..d2dbfc6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,7 @@ kotlinMetadataJvm = "2.4.0" kotlinxSerialization = "1.11.0" kotlinxDatetime = "0.8.0" composeMultiplatform = "1.11.1" +koin = "4.2.2" [libraries] # Build-logic plugin artifacts (compileOnly in build-logic) @@ -54,6 +55,7 @@ androidx-activity-compose = { group = "androidx.activity", n androidx-lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" } androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" } androidx-lifecycle-viewmodel-compose= { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" } +androidx-lifecycle-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "lifecycle" } androidx-work-runtime = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workManager" } androidx-hilt-work = { group = "androidx.hilt", name = "hilt-work", version.ref = "hiltAndroidx" } androidx-hilt-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hiltAndroidx" } @@ -124,6 +126,11 @@ kotlin-metadata-jvm = { group = "org.jetbrains.kotlin", name = "kotlin-metadat kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" } kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" } +# Koin (multiplatform DI, replaces Hilt in :shared) +koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } +koin-compose = { group = "io.insert-koin", name = "koin-compose", version.ref = "koin" } +koin-compose-viewmodel = { group = "io.insert-koin", name = "koin-compose-viewmodel", version.ref = "koin" } + # Jackson jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" } jackson-module-kotlin = { group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version.ref = "jackson" } diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 2b1d530..b83030e 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -12,6 +12,10 @@ kotlin { implementation(project(":core")) implementation(libs.coil3) implementation(libs.coil3.compose) + implementation(libs.koin.core) + implementation(libs.koin.compose) + implementation(libs.koin.compose.viewmodel) + implementation(libs.androidx.lifecycle.viewmodel) } } } diff --git a/shared/src/commonMain/kotlin/com/fluxa/app/shared/CmpSmokeTest.kt b/shared/src/commonMain/kotlin/com/fluxa/app/shared/CmpSmokeTest.kt index 61f46ef..6270f7c 100644 --- a/shared/src/commonMain/kotlin/com/fluxa/app/shared/CmpSmokeTest.kt +++ b/shared/src/commonMain/kotlin/com/fluxa/app/shared/CmpSmokeTest.kt @@ -3,10 +3,13 @@ package com.fluxa.app.shared import androidx.compose.foundation.layout.Column import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import com.fluxa.app.shared.di.GreetingViewModel +import org.koin.compose.viewmodel.koinViewModel @Composable fun CmpSmokeTest() { + val viewModel = koinViewModel() Column { - Text("Fluxa on ${platformName()}") + Text(viewModel.greeting) } } diff --git a/shared/src/commonMain/kotlin/com/fluxa/app/shared/di/InitKoin.kt b/shared/src/commonMain/kotlin/com/fluxa/app/shared/di/InitKoin.kt new file mode 100644 index 0000000..8313411 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/fluxa/app/shared/di/InitKoin.kt @@ -0,0 +1,9 @@ +package com.fluxa.app.shared.di + +import org.koin.core.context.startKoin + +fun initSharedKoin() { + startKoin { + modules(sharedModule) + } +} diff --git a/shared/src/commonMain/kotlin/com/fluxa/app/shared/di/SharedModule.kt b/shared/src/commonMain/kotlin/com/fluxa/app/shared/di/SharedModule.kt new file mode 100644 index 0000000..34981fc --- /dev/null +++ b/shared/src/commonMain/kotlin/com/fluxa/app/shared/di/SharedModule.kt @@ -0,0 +1,14 @@ +package com.fluxa.app.shared.di + +import androidx.lifecycle.ViewModel +import com.fluxa.app.shared.platformName +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module + +class GreetingViewModel : ViewModel() { + val greeting: String = "Fluxa on ${platformName()}" +} + +val sharedModule = module { + viewModel { GreetingViewModel() } +}