Skip to content

Commit

Permalink
Start koin-compose-viewmodel
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaudgiuliani committed May 15, 2024
1 parent a2af6e9 commit f62912c
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 9 deletions.
30 changes: 30 additions & 0 deletions projects/compose/koin-compose-viewmodel/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.compose)
}

val koinComposeVersion: String by project
version = koinComposeVersion

kotlin {
jvm {
withJava()
}

iosX64()
iosArm64()
iosSimulatorArm64()

sourceSets {
commonMain.dependencies {
api(project(":compose:koin-compose"))
api(libs.compose.jb)
api(libs.androidx.composeViewModel)
}
}
}

apply(from = file("../../gradle/publish.gradle.kts"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("DeprecatedCallableAddReplaceWith")

package org.koin.compose

import androidx.compose.runtime.Composable
import androidx.lifecycle.*
import androidx.lifecycle.viewmodel.CreationExtras
import org.koin.core.annotation.KoinExperimentalAPI
import org.koin.core.annotation.KoinInternalApi
import org.koin.core.parameter.ParametersDefinition
import org.koin.core.qualifier.Qualifier
import org.koin.core.scope.Scope

/**
* Resolve ViewModel instance
*
* @param qualifier
* @param parameters
*
* @author Arnaud Giuliani
*/

@OptIn(KoinInternalApi::class)
@KoinExperimentalAPI
@Composable
inline fun <reified T : ViewModel> koinViewModel(
qualifier: Qualifier? = null,
viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
"No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
},
key: String? = null,
extras: CreationExtras = defaultExtras(viewModelStoreOwner),
scope: Scope = currentKoinScope(),
noinline parameters: ParametersDefinition? = null,
): T {
return resolveViewModel(
T::class, viewModelStoreOwner.viewModelStore, key, extras, qualifier, scope, parameters
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.koin.compose

import androidx.compose.runtime.Composable
import androidx.lifecycle.HasDefaultViewModelProviderFactory
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.viewmodel.CreationExtras
import org.koin.core.annotation.KoinInternalApi
import org.koin.core.parameter.ParametersDefinition
import org.koin.core.parameter.ParametersHolder
import org.koin.core.qualifier.Qualifier
import org.koin.core.scope.Scope
import kotlin.reflect.KClass

@KoinInternalApi
fun <T : ViewModel> resolveViewModel(
vmClass: KClass<T>,
viewModelStore: ViewModelStore,
key: String?,
extras: CreationExtras,
qualifier: Qualifier?,
scope: Scope,
parameters: (() -> ParametersHolder)?
): T {
val factory = KoinViewModelFactory(vmClass, scope, qualifier, parameters)
val provider = ViewModelProvider.create(viewModelStore, factory, extras)
val vmKey = getViewModelKey(qualifier, key, vmClass.qualifiedName)
return when {
vmKey != null -> provider[vmKey, vmClass]
else -> provider[vmClass]
}
}

@KoinInternalApi
internal fun getViewModelKey(qualifier: Qualifier? = null, key: String? = null, className: String? = null): String? {
return when {
key != null -> key
qualifier != null -> qualifier.value + (className?.let { "_$className" } ?: "")
else -> null
}
}

class KoinViewModelFactory(
private val kClass: KClass<out ViewModel>,
private val scope: Scope,
private val qualifier: Qualifier? = null,
private val params: ParametersDefinition? = null
) : ViewModelProvider.Factory {

//TODO Handle Extras/Bundle

override fun <T : ViewModel> create(modelClass: KClass<T>, extras: CreationExtras): T {
return scope.get(kClass, qualifier,params)
}
}

/**
* Resolve ViewModel instance
*
* @param qualifier
* @param parameters
*
* @author Arnaud Giuliani
*/
@Composable
fun defaultExtras(viewModelStoreOwner: ViewModelStoreOwner): CreationExtras = when {
viewModelStoreOwner is HasDefaultViewModelProviderFactory -> viewModelStoreOwner.defaultViewModelCreationExtras
else -> CreationExtras.Empty
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("DeprecatedCallableAddReplaceWith")

package org.koin.compose

import androidx.compose.runtime.Composable
import androidx.lifecycle.*
import org.koin.compose.LocalKoinScope
import org.koin.compose.currentKoinScope
import org.koin.compose.rememberCurrentKoinScope
import org.koin.core.annotation.KoinInternalApi
import org.koin.core.parameter.ParametersDefinition
import org.koin.core.qualifier.Qualifier
import org.koin.core.scope.Scope

/**
* Resolve ViewModel instance
*
* @param qualifier
* @param parameters
*
* @author Arnaud Giuliani
*/


@OptIn(KoinInternalApi::class)
@Composable
inline fun <reified T : ViewModel> koinViewModel(
qualifier: Qualifier? = null,
viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
"No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
},
key: String? = null,
extras: CreationExtras = defaultExtras(viewModelStoreOwner),
scope: Scope = currentKoinScope(),
noinline parameters: ParametersDefinition? = null,
): T {
return resolveViewModel(
T::class, viewModelStoreOwner.viewModelStore, key, extras, qualifier, scope, parameters
)
}
2 changes: 1 addition & 1 deletion projects/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ koinVersion=3.6.0-Beta4
koinComposeVersion=1.2.0-Beta4

#Compose
jetpackComposeCompiler=1.5.11
jetpackComposeCompiler=1.5.13
#Android
android.useAndroidX=true
androidMinSDK=14
Expand Down
14 changes: 6 additions & 8 deletions projects/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@ dokka = "1.9.10"
agp = "7.4.2"
android-appcompat = "1.6.1"
android-activity = "1.9.0"
android-fragment = "1.7.0"
androidx-viewmodel = "2.7.0"
androidx-commonJava8 = "2.7.0"
android-fragment = "1.7.1"
androidx-lifecycle = "2.8.0"
androidx-workmanager = "2.9.0"
androidx-navigation = "2.7.7"
# Compose
# /!\ Compose compiler in gradle.properties /!\
composeJB = "1.6.2"
composeJB = "1.6.10-rc01"
composeJetpackRuntime = "1.6.7"
composeJetpackViewmodel = "2.7.0"
# Test
stately = "2.0.6"
junit = "4.13.2"
Expand Down Expand Up @@ -49,8 +47,8 @@ test-mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
android-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "android-appcompat" }
android-activity = { module = "androidx.activity:activity-ktx", version.ref = "android-activity" }
android-fragment = { module = "androidx.fragment:fragment-ktx", version.ref = "android-fragment" }
androidx-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-viewmodel" }
androidx-commonJava8 = { module = "androidx.lifecycle:lifecycle-common-java8", version.ref = "androidx-commonJava8" }
androidx-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" }
androidx-commonJava8 = { module = "androidx.lifecycle:lifecycle-common-java8", version.ref = "androidx-lifecycle" }
androidx-navigation = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" }
androidx-workmanager = { module = "androidx.work:work-runtime-ktx", version.ref = "androidx-workmanager" }
# Ktor
Expand All @@ -61,7 +59,7 @@ ktor-slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
# Compose
compose-jb = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "composeJB" }
androidx-composeRuntime = { module = "androidx.compose.runtime:runtime", version.ref = "composeJetpackRuntime" }
androidx-composeViewModel = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "composeJetpackViewmodel" }
androidx-composeViewModel = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }
androidx-composeNavigation = { module = "androidx.navigation:navigation-compose", version.ref = "androidx-navigation" }

[plugins]
Expand Down
1 change: 1 addition & 0 deletions projects/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ include(
":android:koin-android-test",
// Compose
":compose:koin-compose",
":compose:koin-compose-viewmodel",
":compose:koin-androidx-compose",
":compose:koin-androidx-compose-navigation",
// Plugin
Expand Down

0 comments on commit f62912c

Please sign in to comment.