|
|
@@ -11,77 +11,73 @@ package org.mjdev.tvapp.base.extensions
|
|
|
import android.app.Activity
|
|
|
import android.content.Context
|
|
|
import android.content.ContextWrapper
|
|
|
-import android.os.Bundle
|
|
|
import androidx.compose.runtime.Composable
|
|
|
import androidx.compose.ui.platform.LocalContext
|
|
|
+import androidx.lifecycle.ViewModel
|
|
|
import androidx.lifecycle.ViewModelProvider
|
|
|
import androidx.lifecycle.ViewModelStoreOwner
|
|
|
+import androidx.lifecycle.viewmodel.CreationExtras
|
|
|
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
|
|
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
|
import androidx.navigation.NavBackStackEntry
|
|
|
-import androidx.savedstate.SavedStateRegistryOwner
|
|
|
+import dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.createInternal
|
|
|
import org.mjdev.tvapp.base.extensions.ComposeExt.isEditMode
|
|
|
-import org.mjdev.tvapp.base.viewmodel.BaseViewModel
|
|
|
+import kotlin.reflect.KClass
|
|
|
+import kotlin.reflect.full.companionObject
|
|
|
+import kotlin.reflect.full.functions
|
|
|
|
|
|
object HiltExt {
|
|
|
|
|
|
@Suppress("LocalVariableName")
|
|
|
@Composable
|
|
|
- inline fun <reified VM : BaseViewModel> appViewModel(
|
|
|
+ inline fun <reified VM : ViewModel> appViewModel(
|
|
|
viewModelStoreOwner: ViewModelStoreOwner? = null,
|
|
|
- key: String? = null
|
|
|
- ): VM? {
|
|
|
- return if (isEditMode())
|
|
|
- createMockModel()
|
|
|
- else {
|
|
|
- val _viewModelStoreOwner = viewModelStoreOwner
|
|
|
- ?: LocalViewModelStoreOwner.current!!
|
|
|
- val factory = createHiltViewModelFactory(
|
|
|
- _viewModelStoreOwner
|
|
|
- )
|
|
|
- viewModel(
|
|
|
- viewModelStoreOwner = _viewModelStoreOwner,
|
|
|
- key = key,
|
|
|
- factory = factory
|
|
|
- )
|
|
|
+ key: String? = null,
|
|
|
+ mockFnName :String = String.format("mock%s", VM::class.simpleName),
|
|
|
+ companion: KClass<*>? = VM::class.companionObject,
|
|
|
+ noinline modelMockFnc: ((context: Context) -> VM)? = { context ->
|
|
|
+ companion?.functions?.firstOrNull { fn ->
|
|
|
+ fn.name == mockFnName
|
|
|
+ }?.call(companion, context) as VM
|
|
|
+ }
|
|
|
+ ): VM {
|
|
|
+ val _viewModelStoreOwner = (viewModelStoreOwner ?: LocalViewModelStoreOwner.current)
|
|
|
+ ?: throw (RuntimeException("No view model store."))
|
|
|
+ val modelCreator: MutableMap<KClass<*>, (context: Context) -> Any>.() -> Unit = {
|
|
|
+ put(VM::class) { context ->
|
|
|
+ modelMockFnc?.invoke(context) as VM
|
|
|
+ }
|
|
|
}
|
|
|
+ return viewModel(
|
|
|
+ viewModelStoreOwner = _viewModelStoreOwner,
|
|
|
+ key = key,
|
|
|
+ factory = createHiltViewModelFactory(
|
|
|
+ _viewModelStoreOwner,
|
|
|
+ modelCreator
|
|
|
+ ),
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
- // todo
|
|
|
@Composable
|
|
|
- inline fun <reified VM : BaseViewModel> createMockModel(): VM? {
|
|
|
- return null
|
|
|
-// val context = StateContextWrapper(LocalContext.current)
|
|
|
-// return VM::class.memberFunctions.first { fn ->
|
|
|
-// fn.name == "mock"
|
|
|
-// }.call(VM::class.companionObjectInstance, context) as? VM
|
|
|
-// ?: throw (RuntimeException(
|
|
|
-// "ViewModel ${
|
|
|
-// VM::class.simpleName
|
|
|
-// } does not contain MOCK companion function." +
|
|
|
-// "Please define companion function fun MOCK(context:Context)in this view model."
|
|
|
-// ))
|
|
|
- }
|
|
|
+ fun createHiltViewModelFactory(
|
|
|
+ viewModelStoreOwner: ViewModelStoreOwner,
|
|
|
+ modelCreator: MutableMap<KClass<*>, (context: Context) -> Any>.() -> Unit = {}
|
|
|
+ ): ViewModelProvider.Factory = hiltViewModelFactory(
|
|
|
+ context = LocalContext.current,
|
|
|
+ viewModelStoreOwner = viewModelStoreOwner,
|
|
|
+ modelCreator = modelCreator
|
|
|
+ )
|
|
|
|
|
|
@Composable
|
|
|
- @PublishedApi
|
|
|
- internal fun createHiltViewModelFactory(
|
|
|
- viewModelStoreOwner: ViewModelStoreOwner
|
|
|
- ): ViewModelProvider.Factory? = if (viewModelStoreOwner is NavBackStackEntry) {
|
|
|
- HiltViewModelFactory(
|
|
|
- context = LocalContext.current,
|
|
|
- navBackStackEntry = viewModelStoreOwner
|
|
|
- )
|
|
|
- } else {
|
|
|
- null
|
|
|
- }
|
|
|
-
|
|
|
- @Suppress("FunctionName")
|
|
|
- private fun HiltViewModelFactory(
|
|
|
+ fun hiltViewModelFactory(
|
|
|
context: Context,
|
|
|
- navBackStackEntry: NavBackStackEntry
|
|
|
- ): ViewModelProvider.Factory? {
|
|
|
- try {
|
|
|
+ viewModelStoreOwner: ViewModelStoreOwner,
|
|
|
+ modelCreator: MutableMap<KClass<*>, (context: Context) -> Any>.() -> Unit = {}
|
|
|
+ ): ViewModelProvider.Factory {
|
|
|
+ val navBackStackEntry: NavBackStackEntry? = viewModelStoreOwner as? NavBackStackEntry
|
|
|
+ return if (navBackStackEntry == null || isEditMode())
|
|
|
+ createInternal(context, modelCreator)
|
|
|
+ else {
|
|
|
val activity = context.let {
|
|
|
var ctx = it
|
|
|
while (ctx is ContextWrapper) {
|
|
|
@@ -95,28 +91,37 @@ object HiltExt {
|
|
|
"NavBackStackEntry but instead found: $ctx"
|
|
|
)
|
|
|
}
|
|
|
- return createInternal(
|
|
|
+ createInternal(
|
|
|
activity,
|
|
|
navBackStackEntry,
|
|
|
navBackStackEntry.arguments,
|
|
|
navBackStackEntry.defaultViewModelProviderFactory,
|
|
|
)
|
|
|
- } catch (e: Throwable) {
|
|
|
- return null
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Suppress("UNUSED_PARAMETER")
|
|
|
private fun createInternal(
|
|
|
- activity: Activity,
|
|
|
- owner: SavedStateRegistryOwner,
|
|
|
- defaultArgs: Bundle?,
|
|
|
- delegateFactory: ViewModelProvider.Factory
|
|
|
- ): ViewModelProvider.Factory? {
|
|
|
- return dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.createInternal(
|
|
|
- activity,
|
|
|
- delegateFactory
|
|
|
- )
|
|
|
+ context: Context,
|
|
|
+ modelCreator: MutableMap<KClass<*>, (context: Context) -> Any>.() -> Unit
|
|
|
+ ): ViewModelProvider.Factory = MockViewModelFactory(context, modelCreator)
|
|
|
+
|
|
|
+ @Suppress("UNCHECKED_CAST")
|
|
|
+ class MockViewModelFactory(
|
|
|
+ val context: Context,
|
|
|
+ modelCreator: MutableMap<KClass<*>, (context: Context) -> Any>.() -> Unit
|
|
|
+ ) : ViewModelProvider.Factory {
|
|
|
+
|
|
|
+ private val store = mutableMapOf<KClass<*>, (context: Context) -> Any>()
|
|
|
+ .apply(modelCreator)
|
|
|
+
|
|
|
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
|
|
+ return store[modelClass.kotlin]?.invoke(context) as T
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
|
|
|
+ return store[modelClass.kotlin]?.invoke(context) as T
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
}
|