Skip to content

Commit

Permalink
Add Dependency Injection
Browse files Browse the repository at this point in the history
  • Loading branch information
sunildhiman90 committed Jan 17, 2024
1 parent 35b31d0 commit 089edde
Show file tree
Hide file tree
Showing 18 changed files with 219 additions and 37 deletions.
7 changes: 7 additions & 0 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,20 @@ 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)
}

androidMain.dependencies {
implementation(libs.ktor.client.android)

//koin step2
implementation("io.insert-koin:koin-android:3.5.3")

}

iosMain.dependencies {
Expand Down
1 change: 1 addition & 0 deletions composeApp/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.defaultComponentContext
import com.seiko.imageloader.ImageLoader
import com.seiko.imageloader.LocalImageLoader
Expand All @@ -17,20 +18,34 @@ import com.seiko.imageloader.component.setupDefaultComponents
import com.seiko.imageloader.defaultImageResultMemoryCache
import com.seiko.imageloader.option.androidContext
import okio.Path.Companion.toOkioPath
import org.koin.android.ext.android.inject
import org.koin.core.context.loadKoinModules
import org.koin.dsl.module
import root.DefaultRootComponent
import root.RootComponent
import root.RootContent

class MainActivity : ComponentActivity() {


private val modules = module {
single<ComponentContext> { defaultComponentContext() }
}

init {
loadKoinModules(modules)
}

private val rootComponent: RootComponent by inject()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContent {
CompositionLocalProvider(
LocalImageLoader provides remember { generateImageLoader() },
) {
val homeViewModel = HomeViewModel()
val root = DefaultRootComponent(defaultComponentContext(), homeViewModel)
RootContent(root, modifier = Modifier)
RootContent(rootComponent, modifier = Modifier)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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()
}
}
}
5 changes: 4 additions & 1 deletion composeApp/src/commonMain/kotlin/HomeRepository.kt
Original file line number Diff line number Diff line change
@@ -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<Product> {
val response = httpClient.get("https://fakestoreapi.com/products")
Expand Down
6 changes: 3 additions & 3 deletions composeApp/src/commonMain/kotlin/HomeViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<List<Product>>(listOf())
val products = _products.asStateFlow()

private val homeRepository = HomeRepository()

init {
viewModelScope.launch {
homeRepository.getProducts().collect { products ->
Expand Down
26 changes: 26 additions & 0 deletions composeApp/src/commonMain/kotlin/di/CommonModule.kt
Original file line number Diff line number Diff line change
@@ -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<RootComponent> {
DefaultRootComponent(
componentContext = get(),
homeViewModel = get()
)
}

}
13 changes: 13 additions & 0 deletions composeApp/src/commonMain/kotlin/di/Koin.kt
Original file line number Diff line number Diff line change
@@ -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<Module> = emptyList(),
appDeclaration: KoinAppDeclaration = {}
) = startKoin {
appDeclaration()
modules(additionalModules + commonModule() + platformModule())
}
20 changes: 20 additions & 0 deletions composeApp/src/commonMain/kotlin/di/NetworkModule.kt
Original file line number Diff line number Diff line change
@@ -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
})
}
}
}
}
5 changes: 5 additions & 0 deletions composeApp/src/commonMain/kotlin/di/PlatformModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package di

import org.koin.dsl.module

fun platformModule() = module {}
12 changes: 12 additions & 0 deletions composeApp/src/desktopMain/kotlin/di/KoinJvm.kt
Original file line number Diff line number Diff line change
@@ -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<ComponentContext> { DefaultComponentContext(lifecycle = get<LifecycleRegistry>()) }
}
fun startKoinJvm() = initKoin(additionalModules = listOf(jvmModule))
14 changes: 7 additions & 7 deletions composeApp/src/desktopMain/kotlin/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<RootComponent>()
RootContent(rootComponent, modifier = Modifier)

}
}
Expand Down
21 changes: 21 additions & 0 deletions composeApp/src/iosMain/kotlin/di/DependencyInjection.kt
Original file line number Diff line number Diff line change
@@ -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<ComponentContext> { DefaultComponentContext(lifecycle = get<LifecycleRegistry>()) }
}

fun initKoinIOS() = initKoin(additionalModules = listOf(iosModule))

val Koin.rootComponent: RootComponent
get() = get()

val Koin.lifecycleRegistry: LifecycleRegistry
get() = get()
13 changes: 13 additions & 0 deletions composeApp/src/jsMain/kotlin/di/KoinJs.kt
Original file line number Diff line number Diff line change
@@ -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<ComponentContext> { DefaultComponentContext(lifecycle = get<LifecycleRegistry>()) }
}
fun startKoinJs() = initKoin(additionalModules = listOf(jsModule))
17 changes: 6 additions & 11 deletions composeApp/src/jsMain/kotlin/main.kt
Original file line number Diff line number Diff line change
@@ -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() {

Expand All @@ -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<RootComponent>()
RootContent(root, modifier = Modifier)
}
}
Expand Down
6 changes: 5 additions & 1 deletion iosApp/iosApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@
/* 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 */

/* Begin PBXFileReference section */
058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
108200332B56FD090037B781 /* Koin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Koin.swift; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; };
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 = "<group>"; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
Expand Down Expand Up @@ -65,6 +67,7 @@
7555FF8C242A565B00829871 /* Info.plist */,
2152FB032600AC8F00CF470E /* iOSApp.swift */,
058557D7273AAEEB004C7B11 /* Preview Content */,
108200332B56FD090037B781 /* Koin.swift */,
);
path = iosApp;
sourceTree = "<group>";
Expand Down Expand Up @@ -168,6 +171,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
108200342B56FD090037B781 /* Koin.swift in Sources */,
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */,
7555FF83242A565900829871 /* ContentView.swift in Sources */,
);
Expand Down
22 changes: 22 additions & 0 deletions iosApp/iosApp/Koin.swift
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 089edde

Please sign in to comment.