Updated on 2026-08-14

This commit is contained in:
Tangem 2025-06-16 12:49:16 +05:00
parent e3b1480e32
commit ad4e7e78e9
7 changed files with 96 additions and 24 deletions

View file

@ -3,10 +3,10 @@ package com.tangem.tap.routing.utils
import com.tangem.common.routing.AppRoute
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.domain.qrscanning.models.SourceType
import com.tangem.feature.usedesk.api.UsedeskComponent
import com.tangem.feature.qrscanning.QrScanningComponent
import com.tangem.feature.referral.api.ReferralComponent
import com.tangem.feature.stories.api.StoriesComponent
import com.tangem.feature.usedesk.api.UsedeskComponent
import com.tangem.feature.walletsettings.component.WalletSettingsComponent
import com.tangem.features.details.component.DetailsComponent
import com.tangem.features.disclaimer.api.components.DisclaimerComponent
@ -49,7 +49,7 @@ internal class ChildFactory @Inject constructor(
private val disclaimerComponentFactory: DisclaimerComponent.Factory,
private val manageTokensComponentFactory: ManageTokensComponent.Factory,
private val marketsTokenDetailsComponentFactory: MarketsTokenDetailsComponent.Factory,
private val marketsTokenListComponentFactory: MarketsTokenListComponent.Factory,
private val marketsTokenListComponentFactory: MarketsTokenListComponent.FactoryScreen,
private val onrampComponentFactory: OnrampComponent.Factory,
private val onrampSuccessComponentFactory: OnrampSuccessComponent.Factory,
private val buyCryptoComponentFactory: BuyCryptoComponent.Factory,

View file

@ -5,8 +5,11 @@ import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.TokenMarketParams
import com.tangem.features.markets.entry.BottomSheetState
@Stable
@ -19,5 +22,13 @@ interface MarketsTokenListComponent : ComposableContentComponent {
modifier: Modifier,
)
interface Factory : ComponentFactory<Unit, MarketsTokenListComponent>
interface FactoryScreen : ComponentFactory<Unit, MarketsTokenListComponent>
interface FactoryBottomSheet {
fun create(
context: AppComponentContext,
params: Unit,
onTokenClick: ((TokenMarketParams, AppCurrency) -> Unit)?,
): MarketsTokenListComponent
}
}

View file

@ -5,6 +5,7 @@ import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import com.arkivanov.decompose.ExperimentalDecomposeApi
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.ChildStack
import com.arkivanov.decompose.router.stack.StackNavigation
@ -14,6 +15,9 @@ import com.arkivanov.decompose.value.Value
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.TokenMarketParams
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
import com.tangem.features.markets.entry.BottomSheetState
import com.tangem.features.markets.entry.MarketsEntryComponent
import com.tangem.features.markets.entry.impl.MarketsEntryChildFactory.Child
@ -48,6 +52,7 @@ internal class DefaultMarketsEntryComponent @AssistedInject constructor(
componentContext = factoryContext,
router = innerRouter,
),
onTokenClick = ::marketsListTokenSelected,
)
},
)
@ -67,6 +72,23 @@ internal class DefaultMarketsEntryComponent @AssistedInject constructor(
)
}
@OptIn(ExperimentalDecomposeApi::class)
private fun marketsListTokenSelected(token: TokenMarketParams, appCurrency: AppCurrency) {
innerRouter.push(
route = Child.TokenDetails(
params = MarketsTokenDetailsComponent.Params(
token = token,
appCurrency = appCurrency,
showPortfolio = true,
analyticsParams = MarketsTokenDetailsComponent.AnalyticsParams(
blockchain = null,
source = "Market",
),
),
),
)
}
private fun onChildBack() {
if (stack.value.active.configuration !is Child.TokenList) {
stackNavigation.popWhile { it != Child.TokenList }

View file

@ -3,13 +3,15 @@ package com.tangem.features.markets.entry.impl
import androidx.compose.runtime.Immutable
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.navigation.Route
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.TokenMarketParams
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
import com.tangem.features.markets.tokenlist.MarketsTokenListComponent
import kotlinx.serialization.Serializable
import javax.inject.Inject
internal class MarketsEntryChildFactory @Inject constructor(
private val tokenListComponentFactory: MarketsTokenListComponent.Factory,
private val tokenListComponentFactory: MarketsTokenListComponent.FactoryBottomSheet,
private val tokenDetailsComponentFactory: MarketsTokenDetailsComponent.Factory,
) {
@ -26,7 +28,11 @@ internal class MarketsEntryChildFactory @Inject constructor(
data class TokenDetails(val params: MarketsTokenDetailsComponent.Params) : Child
}
fun createChild(child: Child, appComponentContext: AppComponentContext): Any {
fun createChild(
child: Child,
appComponentContext: AppComponentContext,
onTokenClick: (TokenMarketParams, AppCurrency) -> Unit,
): Any {
return when (child) {
is Child.TokenDetails -> {
tokenDetailsComponentFactory.create(
@ -38,6 +44,7 @@ internal class MarketsEntryChildFactory @Inject constructor(
tokenListComponentFactory.create(
context = appComponentContext,
params = Unit,
onTokenClick = onTokenClick,
)
}
}

View file

@ -46,7 +46,7 @@ internal fun EntryBottomSheetContent(
modifier = modifier,
)
}
MarketsEntryChildFactory.Child.TokenList -> {
is MarketsEntryChildFactory.Child.TokenList -> {
(it.instance as MarketsTokenListComponent).BottomSheetContent(
bottomSheetState = bottomSheetState,
onHeaderSizeChange = onHeaderSizeChange,
@ -84,7 +84,7 @@ private fun BackgroundColorEffects(
animationSpec = tween(durationMillis = 500),
)
}
MarketsEntryChildFactory.Child.TokenList -> {
is MarketsEntryChildFactory.Child.TokenList -> {
backgroundColor.animateTo(
primary,
animationSpec = tween(durationMillis = 500),
@ -119,7 +119,7 @@ private fun BackgroundColorEffects(
is MarketsEntryChildFactory.Child.TokenDetails -> {
backgroundColor.snapTo(tertiary)
}
MarketsEntryChildFactory.Child.TokenList -> {
is MarketsEntryChildFactory.Child.TokenList -> {
backgroundColor.snapTo(primary)
}
}

View file

@ -18,6 +18,8 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.WindowInsetsZero
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.TokenMarketParams
import com.tangem.domain.markets.toSerializableParam
import com.tangem.features.markets.entry.BottomSheetState
import com.tangem.features.markets.tokenlist.MarketsTokenListComponent
@ -31,9 +33,10 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@Suppress("UnusedPrivateMember")
class DefaultMarketsTokenListComponent @AssistedInject constructor(
internal class DefaultMarketsTokenListComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted params: Unit,
@Assisted onTokenClick: ((TokenMarketParams, AppCurrency) -> Unit)? = null,
) : AppComponentContext by appComponentContext, MarketsTokenListComponent {
private val model: MarketsListModel = getOrCreateModel()
@ -41,17 +44,23 @@ class DefaultMarketsTokenListComponent @AssistedInject constructor(
init {
model.tokenSelected
.onEach { (token, appCurrency) ->
router.push(
AppRoute.MarketsTokenDetails(
token = token.toSerializableParam(),
appCurrency = appCurrency,
showPortfolio = true,
analyticsParams = AnalyticsParams(
blockchain = null,
source = "Market",
// If specific routing call back is provided, invoke it (for example inner routing in Bottom Sheet)
// Otherwise navigate using app routing
if (onTokenClick != null) {
onTokenClick(token.toSerializableParam(), appCurrency)
} else {
router.push(
AppRoute.MarketsTokenDetails(
token = token.toSerializableParam(),
appCurrency = appCurrency,
showPortfolio = true,
analyticsParams = AnalyticsParams(
blockchain = null,
source = "Market",
),
),
),
)
)
}
}
.launchIn(componentScope)
}
@ -112,7 +121,11 @@ class DefaultMarketsTokenListComponent @AssistedInject constructor(
}
@AssistedFactory
interface Factory : MarketsTokenListComponent.Factory {
override fun create(context: AppComponentContext, params: Unit): DefaultMarketsTokenListComponent
interface FactoryBottomSheet : MarketsTokenListComponent.FactoryBottomSheet {
override fun create(
context: AppComponentContext,
params: Unit,
onTokenClick: ((TokenMarketParams, AppCurrency) -> Unit)?,
): DefaultMarketsTokenListComponent
}
}

View file

@ -1,9 +1,11 @@
package com.tangem.features.markets.tokenlist.impl.di
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.features.markets.tokenlist.MarketsTokenListComponent
import com.tangem.features.markets.tokenlist.impl.DefaultMarketsTokenListComponent
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@ -14,7 +16,24 @@ internal interface ComponentModule {
@Binds
@Singleton
fun bindMarketsTokenListComponent(
factory: DefaultMarketsTokenListComponent.Factory,
): MarketsTokenListComponent.Factory
fun bindMarketsTokenListBottomSheetComponent(
factory: DefaultMarketsTokenListComponent.FactoryBottomSheet,
): MarketsTokenListComponent.FactoryBottomSheet
}
@Module
@InstallIn(SingletonComponent::class)
internal class ComponentProvideModule {
@Provides
@Singleton
fun providesMarketsTokenListScreenComponent(
factory: DefaultMarketsTokenListComponent.FactoryBottomSheet,
): MarketsTokenListComponent.FactoryScreen {
return object : MarketsTokenListComponent.FactoryScreen {
override fun create(context: AppComponentContext, params: Unit): MarketsTokenListComponent {
return factory.create(context, params, null)
}
}
}
}