Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-23 23:36:32 +04:00
parent 3595fdbf9a
commit 36871cc5c9
17 changed files with 152 additions and 10 deletions

View file

@ -140,6 +140,8 @@ dependencies {
implementation(projects.features.disclaimer.impl) implementation(projects.features.disclaimer.impl)
implementation(projects.features.pushNotifications.api) implementation(projects.features.pushNotifications.api)
implementation(projects.features.pushNotifications.impl) implementation(projects.features.pushNotifications.impl)
implementation(projects.features.walletSettings.api)
implementation(projects.features.walletSettings.impl)
/** AndroidX libraries */ /** AndroidX libraries */
implementation(deps.androidx.core.ktx) implementation(deps.androidx.core.ktx)

View file

@ -2,15 +2,17 @@ package com.tangem.tap
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.ComposableContentComponent
import com.tangem.core.ui.UiDependencies import com.tangem.core.ui.UiDependencies
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.message.EventMessageEffect import com.tangem.core.ui.message.EventMessageEffect
import com.tangem.core.ui.screen.ComposeFragment import com.tangem.core.ui.screen.ComposeFragment
import com.tangem.utils.Provider import com.tangem.utils.Provider
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import java.util.WeakHashMap
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -20,7 +22,10 @@ internal class DecomposeFragment : ComposeFragment() {
override lateinit var uiDependencies: UiDependencies override lateinit var uiDependencies: UiDependencies
private val component by lazy(mode = LazyThreadSafetyMode.NONE) { private val component by lazy(mode = LazyThreadSafetyMode.NONE) {
requireNotNull(componentBuilder?.build()) { val tag = requireArguments().getString(TAG_KEY)
val builder = componentsBuilders[tag]
requireNotNull(builder?.build()) {
"Component builder is not set, call newInstance() for DecomposeFragment creation first." "Component builder is not set, call newInstance() for DecomposeFragment creation first."
} }
} }
@ -46,16 +51,21 @@ internal class DecomposeFragment : ComposeFragment() {
companion object { companion object {
private var componentBuilder: ComponentBuilder<*, *, *>? = null private const val TAG_KEY = "tag"
private val componentsBuilders = WeakHashMap<String, ComponentBuilder<*, *, *>>()
fun <C : ComposableContentComponent, P : Any, F : ComponentFactory<P, C>> newInstance( fun <C : ComposableContentComponent, P : Any, F : ComponentFactory<P, C>> newInstance(
tag: String,
contextProvider: Provider<AppComponentContext>, contextProvider: Provider<AppComponentContext>,
params: P, params: P,
componentFactory: F, componentFactory: F,
): Fragment { ): Fragment {
this@Companion.componentBuilder = ComponentBuilder(contextProvider, params, componentFactory) this@Companion.componentsBuilders[tag] = ComponentBuilder(contextProvider, params, componentFactory)
return DecomposeFragment() return DecomposeFragment().apply {
this.arguments = bundleOf(TAG_KEY to tag)
}
} }
} }
} }

View file

@ -5,6 +5,7 @@ import com.arkivanov.decompose.router.stack.ChildStack
import com.arkivanov.decompose.router.stack.childStack import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.value.Value import com.arkivanov.decompose.value.Value
import com.arkivanov.essenty.backhandler.BackCallback import com.arkivanov.essenty.backhandler.BackCallback
import com.arkivanov.essenty.lifecycle.doOnDestroy
import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRoute
import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.context.childByContext
@ -34,6 +35,10 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
init { init {
backHandler.register(backCallback) backHandler.register(backCallback)
lifecycle.doOnDestroy {
childFactory.doOnDestroy()
}
} }
private fun getInitialRoute(): AppRoute = AppRoute.Initial private fun getInitialRoute(): AppRoute = AppRoute.Initial

View file

@ -163,6 +163,10 @@ internal class ChildFactory @Inject constructor(
} }
} }
fun doOnDestroy() {
componentContexts.clear()
}
private fun contextProvider( private fun contextProvider(
appRoute: AppRoute, appRoute: AppRoute,
contextFactory: (route: AppRoute) -> AppComponentContext, contextFactory: (route: AppRoute) -> AppComponentContext,

View file

@ -5,7 +5,7 @@ import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.bundle.RouteBundleParams import com.tangem.common.routing.bundle.RouteBundleParams
import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.ComposableContentComponent import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.tap.DecomposeFragment import com.tangem.tap.DecomposeFragment
import com.tangem.tap.routing.RoutingComponent.Child import com.tangem.tap.routing.RoutingComponent.Child
import com.tangem.utils.Provider import com.tangem.utils.Provider
@ -29,6 +29,7 @@ internal fun <C : ComposableContentComponent, P : Any, F : ComponentFactory<P, C
): Child { ): Child {
val fragmentProvider = Provider { val fragmentProvider = Provider {
DecomposeFragment.newInstance( DecomposeFragment.newInstance(
tag = path,
contextProvider = contextProvider, contextProvider = contextProvider,
params = params, params = params,
componentFactory = componentFactory, componentFactory = componentFactory,

View file

@ -1,4 +1,4 @@
package com.tangem.core.ui package com.tangem.core.ui.decompose
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable

View file

@ -0,0 +1,14 @@
package com.tangem.core.ui.decompose
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
@Stable
interface ComposableDialogComponent {
val doOnDismiss: () -> Unit
@Composable
@Suppress("TopLevelComposableFunctions") // TODO: Remove this check
fun Dialog()
}

View file

@ -1,7 +1,7 @@
package com.tangem.features.details.component package com.tangem.features.details.component
import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.ComposableContentComponent import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
interface DetailsComponent : ComposableContentComponent { interface DetailsComponent : ComposableContentComponent {

View file

@ -1,7 +1,7 @@
package com.tangem.features.details.component package com.tangem.features.details.component
import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.ComposableContentComponent import com.tangem.core.ui.decompose.ComposableContentComponent
interface UserWalletListComponent : ComposableContentComponent { interface UserWalletListComponent : ComposableContentComponent {

View file

@ -16,10 +16,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.ComposableContentComponent
import com.tangem.core.ui.components.appbar.models.TopAppBarMedium import com.tangem.core.ui.components.appbar.models.TopAppBarMedium
import com.tangem.core.ui.components.block.BlockItem import com.tangem.core.ui.components.block.BlockItem
import com.tangem.core.ui.components.snackbar.TangemSnackbarHost import com.tangem.core.ui.components.snackbar.TangemSnackbarHost
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.LocalSnackbarHostState import com.tangem.core.ui.res.LocalSnackbarHostState
import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTheme

View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,19 @@
plugins {
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
id("configuration")
}
android {
namespace = "com.tangem.feature.walletsettings.api"
}
dependencies {
/* Project - Domain */
implementation(projects.domain.wallets.models)
/* Project - Core */
implementation(projects.core.decompose)
implementation(projects.core.ui)
}

View file

@ -0,0 +1,16 @@
package com.tangem.feature.walletsettings.component
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableDialogComponent
import com.tangem.domain.wallets.models.UserWalletId
interface RenameWalletComponent : ComposableDialogComponent {
data class Params(
val userWalletId: UserWalletId,
val currentName: String,
val onDismiss: () -> Unit,
)
interface Factory : ComponentFactory<Params, RenameWalletComponent>
}

View file

@ -0,0 +1,14 @@
package com.tangem.feature.walletsettings.component
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.wallets.models.UserWalletId
interface WalletSettingsComponent : ComposableContentComponent {
data class Params(
val userWalletId: UserWalletId,
)
interface Factory : ComponentFactory<Params, WalletSettingsComponent>
}

View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,52 @@
plugins {
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
alias(deps.plugins.kotlin.kapt)
alias(deps.plugins.kotlin.serialization)
alias(deps.plugins.hilt.android)
id("configuration")
}
android {
namespace = "com.tangem.feature.walletsettings.impl"
}
dependencies {
/* Project - API */
implementation(projects.features.walletSettings.api)
/* Project - Core */
implementation(projects.core.decompose)
implementation(projects.core.ui)
implementation(projects.core.featuretoggles)
implementation(projects.core.navigation)
implementation(projects.core.analytics.models)
implementation(projects.common.routing)
/* Project - Domain */
implementation(projects.domain.wallets)
implementation(projects.domain.wallets.models)
/* AndroidX */
implementation(deps.androidx.fragment.ktx)
implementation(deps.androidx.activity.compose)
implementation(deps.lifecycle.compose)
/* Compose */
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)
implementation(deps.compose.accompanist.systemUiController)
implementation(deps.compose.foundation)
implementation(deps.compose.material3)
implementation(deps.compose.shimmer)
implementation(deps.decompose.ext.compose)
/* DI */
implementation(deps.hilt.android)
kapt(deps.hilt.kapt)
/* Other */
implementation(deps.kotlin.immutable.collections)
implementation(deps.timber)
}

View file

@ -183,6 +183,9 @@ include(":features:disclaimer:impl")
include(":features:push-notifications:api") include(":features:push-notifications:api")
include(":features:push-notifications:impl") include(":features:push-notifications:impl")
include(":features:wallet-settings:api")
include(":features:wallet-settings:impl")
// endregion Feature modules // endregion Feature modules
// region Domain modules // region Domain modules