Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-17 13:26:18 +04:00
parent d9d3ba2cda
commit 3a6668eee0
10 changed files with 97 additions and 28 deletions

View file

@ -1,5 +1,6 @@
package com.tangem.core.decompose.di
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import dagger.BindsInstance
@ -37,6 +38,14 @@ interface DecomposeComponent {
*/
fun uiMessageSender(@BindsInstance uiMessageSender: UiMessageSender): Builder
/**
* Sets the parameters container for the component.
*
* @param container The parameters container to set.
* @return The builder instance.
*/
fun paramsContainer(@BindsInstance container: ParamsContainer): Builder
/**
* Builds the Decompose component.
*

View file

@ -2,7 +2,7 @@ package com.tangem.core.decompose.factory
import com.tangem.core.decompose.context.AppComponentContext
interface ComponentFactory<Component : Any, Params : Any> {
interface ComponentFactory<P : Any, C : Any> {
fun create(context: AppComponentContext, params: Params): Component
fun create(context: AppComponentContext, params: P): C
}

View file

@ -22,24 +22,43 @@ interface ModelsEntryPoint {
}
/**
* Gets or creates a component's [Model].
* Gets or creates a component's [Model] with no parameters.
*/
inline fun <reified M : Model> AppComponentContext.getOrCreateModel(): M {
val modelKey = "model_${M::class.simpleName}"
inline fun <reified M : Model> AppComponentContext.getOrCreateModel(): M = getOrCreateModel(params = null)
/**
* Gets or creates a component's [Model].
*
* Be careful with objects you pass in parameters as they will be used in [Model] lifecycle.
* If you pass a object with different lifecycle than the [Model] then you can face memory leaks.
*
* @param params The parameters to store in the [ParamsContainer],
*/
inline fun <reified M : Model, reified P : Any> AppComponentContext.getOrCreateModel(params: P?): M {
val entryPoint = instanceKeeper.getOrCreateSimple(key = "modelsEntryPoint") {
val hiltComponent = hiltComponentBuilder
.router(router)
.uiMessageSender(messageSender)
.let { builder ->
if (params != null) {
val container = MutableParamsContainer(params)
builder.paramsContainer(container)
} else {
builder
}
}
.build()
EntryPoints.get(hiltComponent, ModelsEntryPoint::class.java)
}
val modelKey = "model_${M::class.simpleName}"
val model = instanceKeeper.getOrCreate(modelKey) {
requireNotNull(entryPoint.models()[M::class.java]?.get()) {
"Model ${M::class.simpleName} is not provided"
}
} as M
}
val isModelExist = tags.getOrElse(modelKey) { false } as Boolean
@ -47,5 +66,5 @@ inline fun <reified M : Model> AppComponentContext.getOrCreateModel(): M {
tags[modelKey] = true
}
return model as M
return model
}

View file

@ -0,0 +1,45 @@
package com.tangem.core.decompose.model
/**
* Lazy container for [Model] params.
*
* This contrainer can be accessed by DI because it's provided via [com.tangem.core.decompose.di.DecomposeComponent].
* */
interface ParamsContainer {
/** Returns stored value if it is of type [T], otherwise returns null. */
fun <T> get(): T?
/** Returns stored value if it is of type [T], otherwise throws an exception. */
fun <T> require(): T
}
/**
* Mutable implementation of [ParamsContainer].
*
* ***You should not use this class directly in other modules, use immutable [ParamsContainer] instead.***
* */
class MutableParamsContainer private constructor() : ParamsContainer {
private var value: Any? = null
/** Stores [value] inside a container, replaces any previous stored value. */
fun set(value: Any) {
this.value = value
}
@Suppress("UNCHECKED_CAST")
override fun <T> get(): T? = value as? T
override fun <T> require(): T = get() ?: error("Contrainer is empty or contains a value of a different type.")
companion object {
/** Creates a new [MutableParamsContainer] and stores [value] inside it. */
operator fun <T : Any> invoke(value: T): MutableParamsContainer {
return MutableParamsContainer().apply {
set(value)
}
}
}
}