diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts
index d30aa8d..9614d56 100644
--- a/composeApp/build.gradle.kts
+++ b/composeApp/build.gradle.kts
@@ -85,6 +85,9 @@ kotlin {
implementation("com.arkivanov.decompose:decompose:2.2.2-compose-experimental")
implementation("com.arkivanov.decompose:extensions-compose-jetbrains:2.2.2-compose-experimental")
//decompose step1
+
+ //koin step1
+ implementation("io.insert-koin:koin-core:3.5.3")
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
@@ -92,6 +95,10 @@ kotlin {
androidMain.dependencies {
implementation(libs.ktor.client.android)
+
+ //koin step2
+ implementation("io.insert-koin:koin-android:3.5.3")
+
}
iosMain.dependencies {
diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml
index 92127a9..83d101a 100644
--- a/composeApp/src/androidMain/AndroidManifest.xml
+++ b/composeApp/src/androidMain/AndroidManifest.xml
@@ -4,6 +4,7 @@
{ defaultComponentContext() }
+ }
+
+ init {
+ loadKoinModules(modules)
+ }
+
+ private val rootComponent: RootComponent by inject()
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -28,9 +45,7 @@ class MainActivity : ComponentActivity() {
CompositionLocalProvider(
LocalImageLoader provides remember { generateImageLoader() },
) {
- val homeViewModel = HomeViewModel()
- val root = DefaultRootComponent(defaultComponentContext(), homeViewModel)
- RootContent(root, modifier = Modifier)
+ RootContent(rootComponent, modifier = Modifier)
}
}
}
diff --git a/composeApp/src/androidMain/kotlin/com/codingambitions/kmpapp2/MainApplication.kt b/composeApp/src/androidMain/kotlin/com/codingambitions/kmpapp2/MainApplication.kt
new file mode 100644
index 0000000..8be3b19
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/codingambitions/kmpapp2/MainApplication.kt
@@ -0,0 +1,17 @@
+package com.codingambitions.kmpapp2
+
+import android.app.Application
+import di.initKoin
+import org.koin.android.ext.koin.androidContext
+import org.koin.android.ext.koin.androidLogger
+
+class MainApplication: Application() {
+ override fun onCreate() {
+ super.onCreate()
+
+ initKoin {
+ androidContext(this@MainApplication)
+ androidLogger()
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/HomeRepository.kt b/composeApp/src/commonMain/kotlin/HomeRepository.kt
index 0bddeb2..4246b5b 100644
--- a/composeApp/src/commonMain/kotlin/HomeRepository.kt
+++ b/composeApp/src/commonMain/kotlin/HomeRepository.kt
@@ -1,10 +1,13 @@
import apiClient.httpClient
import data.Product
+import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.get
import kotlinx.coroutines.flow.flow
-class HomeRepository {
+class HomeRepository(
+ private val httpClient: HttpClient
+) {
suspend fun getProductsApi(): List {
val response = httpClient.get("https://fakestoreapi.com/products")
diff --git a/composeApp/src/commonMain/kotlin/HomeViewModel.kt b/composeApp/src/commonMain/kotlin/HomeViewModel.kt
index d359541..e87ef75 100644
--- a/composeApp/src/commonMain/kotlin/HomeViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/HomeViewModel.kt
@@ -5,13 +5,13 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
-class HomeViewModel : ViewModel() {
+class HomeViewModel(
+ private val homeRepository: HomeRepository
+) : ViewModel() {
private val _products = MutableStateFlow>(listOf())
val products = _products.asStateFlow()
- private val homeRepository = HomeRepository()
-
init {
viewModelScope.launch {
homeRepository.getProducts().collect { products ->
diff --git a/composeApp/src/commonMain/kotlin/di/CommonModule.kt b/composeApp/src/commonMain/kotlin/di/CommonModule.kt
new file mode 100644
index 0000000..b7325ce
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/di/CommonModule.kt
@@ -0,0 +1,26 @@
+package di
+
+import HomeRepository
+import HomeViewModel
+import org.koin.dsl.module
+import root.DefaultRootComponent
+import root.RootComponent
+
+fun commonModule() = networkModule() + module {
+
+ single {
+ HomeRepository(get())
+ }
+
+ single {
+ HomeViewModel(get())
+ }
+
+ single {
+ DefaultRootComponent(
+ componentContext = get(),
+ homeViewModel = get()
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/di/Koin.kt b/composeApp/src/commonMain/kotlin/di/Koin.kt
new file mode 100644
index 0000000..0b5bd7f
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/di/Koin.kt
@@ -0,0 +1,13 @@
+package di
+
+import org.koin.core.context.startKoin
+import org.koin.core.module.Module
+import org.koin.dsl.KoinAppDeclaration
+
+fun initKoin(
+ additionalModules: List = emptyList(),
+ appDeclaration: KoinAppDeclaration = {}
+) = startKoin {
+ appDeclaration()
+ modules(additionalModules + commonModule() + platformModule())
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/di/NetworkModule.kt b/composeApp/src/commonMain/kotlin/di/NetworkModule.kt
new file mode 100644
index 0000000..fdd0de2
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/di/NetworkModule.kt
@@ -0,0 +1,20 @@
+package di
+
+import io.ktor.client.HttpClient
+import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
+import io.ktor.serialization.kotlinx.json.json
+import kotlinx.serialization.json.Json
+import org.koin.dsl.module
+
+fun networkModule() = module {
+ single {
+ HttpClient {
+ install(ContentNegotiation) {
+ json(Json {
+ prettyPrint = true
+ ignoreUnknownKeys = true
+ })
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/di/PlatformModule.kt b/composeApp/src/commonMain/kotlin/di/PlatformModule.kt
new file mode 100644
index 0000000..5c5cdd6
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/di/PlatformModule.kt
@@ -0,0 +1,5 @@
+package di
+
+import org.koin.dsl.module
+
+fun platformModule() = module {}
\ No newline at end of file
diff --git a/composeApp/src/desktopMain/kotlin/di/KoinJvm.kt b/composeApp/src/desktopMain/kotlin/di/KoinJvm.kt
new file mode 100644
index 0000000..30738ae
--- /dev/null
+++ b/composeApp/src/desktopMain/kotlin/di/KoinJvm.kt
@@ -0,0 +1,12 @@
+package di
+
+import com.arkivanov.decompose.ComponentContext
+import com.arkivanov.decompose.DefaultComponentContext
+import com.arkivanov.essenty.lifecycle.LifecycleRegistry
+import org.koin.dsl.module
+
+val jvmModule = module {
+ single { LifecycleRegistry() }
+ single { DefaultComponentContext(lifecycle = get()) }
+}
+fun startKoinJvm() = initKoin(additionalModules = listOf(jvmModule))
\ No newline at end of file
diff --git a/composeApp/src/desktopMain/kotlin/main.kt b/composeApp/src/desktopMain/kotlin/main.kt
index 6b1666e..6b5916f 100644
--- a/composeApp/src/desktopMain/kotlin/main.kt
+++ b/composeApp/src/desktopMain/kotlin/main.kt
@@ -8,20 +8,20 @@ import com.arkivanov.essenty.lifecycle.LifecycleRegistry
import com.seiko.imageloader.ImageLoader
import com.seiko.imageloader.component.setupDefaultComponents
import com.seiko.imageloader.defaultImageResultMemoryCache
+import di.startKoinJvm
import okio.Path.Companion.toOkioPath
import root.DefaultRootComponent
+import root.RootComponent
import root.RootContent
import java.io.File
+
+val koin = startKoinJvm().koin
+
fun main() = application {
Window(onCloseRequest = ::exitApplication, title = "KmpApp2") {
- val homeViewModel = HomeViewModel()
- val root =
- DefaultRootComponent(
- componentContext = DefaultComponentContext(LifecycleRegistry()),
- homeViewModel
- )
- RootContent(root, modifier = Modifier)
+ val rootComponent = koin.get()
+ RootContent(rootComponent, modifier = Modifier)
}
}
diff --git a/composeApp/src/iosMain/kotlin/di/DependencyInjection.kt b/composeApp/src/iosMain/kotlin/di/DependencyInjection.kt
new file mode 100644
index 0000000..bce7163
--- /dev/null
+++ b/composeApp/src/iosMain/kotlin/di/DependencyInjection.kt
@@ -0,0 +1,21 @@
+package di
+
+import com.arkivanov.decompose.ComponentContext
+import com.arkivanov.decompose.DefaultComponentContext
+import com.arkivanov.essenty.lifecycle.LifecycleRegistry
+import org.koin.core.Koin
+import org.koin.dsl.module
+import root.RootComponent
+
+val iosModule = module {
+ single { LifecycleRegistry() }
+ single { DefaultComponentContext(lifecycle = get()) }
+}
+
+fun initKoinIOS() = initKoin(additionalModules = listOf(iosModule))
+
+val Koin.rootComponent: RootComponent
+ get() = get()
+
+val Koin.lifecycleRegistry: LifecycleRegistry
+ get() = get()
\ No newline at end of file
diff --git a/composeApp/src/jsMain/kotlin/di/KoinJs.kt b/composeApp/src/jsMain/kotlin/di/KoinJs.kt
new file mode 100644
index 0000000..2e9efd3
--- /dev/null
+++ b/composeApp/src/jsMain/kotlin/di/KoinJs.kt
@@ -0,0 +1,13 @@
+package di
+
+import com.arkivanov.decompose.ComponentContext
+import com.arkivanov.decompose.DefaultComponentContext
+import com.arkivanov.essenty.lifecycle.LifecycleRegistry
+import org.koin.dsl.module
+
+
+val jsModule = module {
+ single { LifecycleRegistry() }
+ single { DefaultComponentContext(lifecycle = get()) }
+}
+fun startKoinJs() = initKoin(additionalModules = listOf(jsModule))
\ No newline at end of file
diff --git a/composeApp/src/jsMain/kotlin/main.kt b/composeApp/src/jsMain/kotlin/main.kt
index 2aa9cf5..c60db33 100644
--- a/composeApp/src/jsMain/kotlin/main.kt
+++ b/composeApp/src/jsMain/kotlin/main.kt
@@ -1,21 +1,21 @@
-import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.CanvasBasedWindow
-import androidx.compose.ui.window.Window
-import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.essenty.lifecycle.LifecycleRegistry
import com.seiko.imageloader.ImageLoader
import com.seiko.imageloader.LocalImageLoader
import com.seiko.imageloader.component.setupDefaultComponents
import com.seiko.imageloader.defaultImageResultMemoryCache
+import di.startKoinJs
import okio.FileSystem
import org.jetbrains.skiko.wasm.onWasmReady
-import root.DefaultRootComponent
+import root.RootComponent
import root.RootContent
+
+val koin = startKoinJs().koin
+
@OptIn(ExperimentalComposeUiApi::class)
fun main() {
@@ -24,12 +24,7 @@ fun main() {
CompositionLocalProvider(
LocalImageLoader provides remember { generateImageLoader() },
) {
- val homeViewModel = HomeViewModel()
- val root =
- DefaultRootComponent(
- componentContext = DefaultComponentContext(LifecycleRegistry()),
- homeViewModel
- )
+ val root = koin.get()
RootContent(root, modifier = Modifier)
}
}
diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj
index 66c59c0..0ce98d6 100644
--- a/iosApp/iosApp.xcodeproj/project.pbxproj
+++ b/iosApp/iosApp.xcodeproj/project.pbxproj
@@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; };
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; };
+ 108200342B56FD090037B781 /* Koin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 108200332B56FD090037B781 /* Koin.swift */; };
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; };
7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; };
/* End PBXBuildFile section */
@@ -16,8 +17,9 @@
/* Begin PBXFileReference section */
058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
+ 108200332B56FD090037B781 /* Koin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Koin.swift; sourceTree = ""; };
2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = ""; };
- 7555FF7B242A565900829871 /* .app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = .app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7555FF7B242A565900829871 /* .app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; name = .app; path = KmpApp2.app; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; };
@@ -65,6 +67,7 @@
7555FF8C242A565B00829871 /* Info.plist */,
2152FB032600AC8F00CF470E /* iOSApp.swift */,
058557D7273AAEEB004C7B11 /* Preview Content */,
+ 108200332B56FD090037B781 /* Koin.swift */,
);
path = iosApp;
sourceTree = "";
@@ -168,6 +171,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 108200342B56FD090037B781 /* Koin.swift in Sources */,
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */,
7555FF83242A565900829871 /* ContentView.swift in Sources */,
);
diff --git a/iosApp/iosApp/Koin.swift b/iosApp/iosApp/Koin.swift
new file mode 100644
index 0000000..165c2f4
--- /dev/null
+++ b/iosApp/iosApp/Koin.swift
@@ -0,0 +1,22 @@
+//
+// Koin.swift
+// iosApp
+//
+// Created by Sunil Kumar on 16/01/24.
+// Copyright © 2024 orgName. All rights reserved.
+//
+
+import Foundation
+import ComposeApp
+
+
+private var _koin: Koin_coreKoin? = nil
+var koin: Koin_coreKoin {
+ return _koin!
+}
+
+
+func startKoin() {
+ let koinApplication = DependencyInjectionKt.doInitKoinIOS()
+ _koin = koinApplication.koin
+}
diff --git a/iosApp/iosApp/iOSApp.swift b/iosApp/iosApp/iOSApp.swift
index 1d1b1f5..af22635 100644
--- a/iosApp/iosApp/iOSApp.swift
+++ b/iosApp/iosApp/iOSApp.swift
@@ -8,7 +8,7 @@ struct iOSApp: App {
var appDelegate: AppDelegate
var rootHolder: RootHolder {
- appDelegate.rootHolder
+ appDelegate.getRootHolder()
}
var body: some Scene {
@@ -40,15 +40,8 @@ class RootHolder: ObservableObject {
let root: RootComponent
init() {
- lifecycle = LifecycleRegistryKt.LifecycleRegistry()
- lifecycle.subscribe(callbacks: LifecycleCallbacksImpl())
- let homeViewModel = HomeViewModel()
-
- root = DefaultRootComponent(
- componentContext: DefaultComponentContext(lifecycle: lifecycle),
- homeViewModel: homeViewModel
- )
-
+ lifecycle = koin.lifecycleRegistry
+ root = koin.rootComponent
LifecycleRegistryExtKt.create(lifecycle)
}
@@ -59,5 +52,20 @@ class RootHolder: ObservableObject {
}
class AppDelegate: NSObject, UIApplicationDelegate {
- let rootHolder: RootHolder = RootHolder()
+ var rootHolder: RootHolder? = nil
+
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
+
+ startKoin()
+ rootHolder = RootHolder()
+
+ return true
+ }
+
+ func getRootHolder() -> RootHolder {
+ if(rootHolder == nil) {
+ rootHolder = RootHolder()
+ }
+ return rootHolder!
+ }
}