diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 005557d07b..362ae78fb2 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -12,10 +12,7 @@ import com.tangem.features.disclaimer.api.components.DisclaimerComponent import com.tangem.features.managetokens.component.ManageTokensComponent import com.tangem.features.managetokens.component.ManageTokensSource import com.tangem.features.markets.details.MarketsTokenDetailsComponent -import com.tangem.features.nft.component.NFTCollectionsComponent -import com.tangem.features.nft.component.NFTDetailsComponent -import com.tangem.features.nft.component.NFTReceiveComponent -import com.tangem.features.nft.component.NFTAssetTraitsComponent +import com.tangem.features.nft.component.* import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent import com.tangem.features.onramp.component.* import com.tangem.features.pushnotifications.api.PushNotificationsComponent @@ -85,10 +82,7 @@ internal class ChildFactory @Inject constructor( private val sendComponentFactoryV2: com.tangem.features.send.v2.api.SendComponent.Factory, private val sendFeatureToggles: SendFeatureToggles, private val redesignedWalletConnectComponentFactory: RedisegnedWalletConnectComponent.Factory, - private val nftCollectionsComponentFactory: NFTCollectionsComponent.Factory, - private val nftReceiveComponentFactory: NFTReceiveComponent.Factory, - private val nftDetailsComponentFactory: NFTDetailsComponent.Factory, - private val nftAssetTraitsComponentFactory: NFTAssetTraitsComponent.Factory, + private val nftComponentFactory: NFTComponent.Factory, private val nftSendComponentFactory: NFTSendComponent.Factory, private val testerRouter: TesterRouter, private val routingFeatureToggles: RoutingFeatureToggles, @@ -409,33 +403,11 @@ internal class ChildFactory @Inject constructor( componentFactory = walletComponentFactory, ) } - is AppRoute.NFTCollections -> + is AppRoute.NFT -> createComponentChild( context = context, - params = NFTCollectionsComponent.Params(userWalletId = route.userWalletId), - componentFactory = nftCollectionsComponentFactory, - ) - is AppRoute.NFTReceive -> - createComponentChild( - context = context, - params = NFTReceiveComponent.Params(userWalletId = route.userWalletId), - componentFactory = nftReceiveComponentFactory, - ) - is AppRoute.NFTDetails -> - createComponentChild( - context = context, - params = NFTDetailsComponent.Params( - userWalletId = route.userWalletId, - nftAsset = route.nftAsset, - nftCollectionName = route.collectionName, - ), - componentFactory = nftDetailsComponentFactory, - ) - is AppRoute.NFTAssetTraits -> - createComponentChild( - context = context, - params = NFTAssetTraitsComponent.Params(nftAsset = route.nftAsset), - componentFactory = nftAssetTraitsComponentFactory, + params = NFTComponent.Params(userWalletId = route.userWalletId), + componentFactory = nftComponentFactory, ) is AppRoute.NFTSend -> { createComponentChild( @@ -782,33 +754,11 @@ internal class ChildFactory @Inject constructor( componentFactory = storiesComponentFactory, ) } - is AppRoute.NFTCollections -> + is AppRoute.NFT -> route.asComponentChild( contextProvider = contextProvider(route, contextFactory), - params = NFTCollectionsComponent.Params(userWalletId = route.userWalletId), - componentFactory = nftCollectionsComponentFactory, - ) - is AppRoute.NFTReceive -> - route.asComponentChild( - contextProvider = contextProvider(route, contextFactory), - params = NFTReceiveComponent.Params(userWalletId = route.userWalletId), - componentFactory = nftReceiveComponentFactory, - ) - is AppRoute.NFTDetails -> - route.asComponentChild( - contextProvider = contextProvider(route, contextFactory), - params = NFTDetailsComponent.Params( - userWalletId = route.userWalletId, - nftAsset = route.nftAsset, - nftCollectionName = route.collectionName, - ), - componentFactory = nftDetailsComponentFactory, - ) - is AppRoute.NFTAssetTraits -> - route.asComponentChild( - contextProvider = contextProvider(route, contextFactory), - params = NFTAssetTraitsComponent.Params(nftAsset = route.nftAsset), - componentFactory = nftAssetTraitsComponentFactory, + params = NFTComponent.Params(userWalletId = route.userWalletId), + componentFactory = nftComponentFactory, ) is AppRoute.NFTSend -> { route.asComponentChild( diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index a21f44aa02..508661dac0 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -281,26 +281,9 @@ sealed class AppRoute(val path: String) : Route { ) : AppRoute(path = "/stories$storyId") @Serializable - data class NFTCollections( + data class NFT( val userWalletId: UserWalletId, - ) : AppRoute(path = "/nft_collections/${userWalletId.stringValue}") - - @Serializable - data class NFTReceive( - val userWalletId: UserWalletId, - ) : AppRoute(path = "/nft_receive/${userWalletId.stringValue}") - - @Serializable - data class NFTDetails( - val userWalletId: UserWalletId, - val nftAsset: NFTAsset, - val collectionName: String, - ) : AppRoute(path = "/nft_details/${userWalletId.stringValue}/${nftAsset.collectionId}/${nftAsset.id.stringValue}") - - @Serializable - data class NFTAssetTraits( - val nftAsset: NFTAsset, - ) : AppRoute(path = "/nft_traits/${nftAsset.collectionId}/${nftAsset.id.stringValue}") + ) : AppRoute(path = "/nft/${userWalletId.stringValue}") @Serializable data class NFTSend( diff --git a/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTAssetTraitsComponent.kt b/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTAssetTraitsComponent.kt deleted file mode 100644 index 2be81fbcef..0000000000 --- a/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTAssetTraitsComponent.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.features.nft.component - -import com.tangem.core.decompose.factory.ComponentFactory -import com.tangem.core.ui.decompose.ComposableContentComponent -import com.tangem.domain.nft.models.NFTAsset - -interface NFTAssetTraitsComponent : ComposableContentComponent { - - data class Params( - val nftAsset: NFTAsset, - ) - - interface Factory : ComponentFactory -} \ No newline at end of file diff --git a/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTCollectionsComponent.kt b/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTCollectionsComponent.kt deleted file mode 100644 index 3417b6a1f2..0000000000 --- a/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTCollectionsComponent.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.tangem.features.nft.component - -import com.tangem.core.decompose.factory.ComponentFactory -import com.tangem.core.ui.decompose.ComposableContentComponent -import com.tangem.domain.wallets.models.UserWalletId - -interface NFTCollectionsComponent : ComposableContentComponent { - - data class Params( - val userWalletId: UserWalletId, - ) - - interface Factory : ComponentFactory -} \ No newline at end of file diff --git a/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTReceiveComponent.kt b/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTComponent.kt similarity index 68% rename from features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTReceiveComponent.kt rename to features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTComponent.kt index 9184afa340..f2f8d3f9e5 100644 --- a/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTReceiveComponent.kt +++ b/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTComponent.kt @@ -4,11 +4,11 @@ import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.domain.wallets.models.UserWalletId -interface NFTReceiveComponent : ComposableContentComponent { +interface NFTComponent : ComposableContentComponent { data class Params( val userWalletId: UserWalletId, ) - interface Factory : ComponentFactory + interface Factory : ComponentFactory } \ No newline at end of file diff --git a/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTDetailsComponent.kt b/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTDetailsComponent.kt deleted file mode 100644 index 2848de0dd5..0000000000 --- a/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTDetailsComponent.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.tangem.features.nft.component - -import com.tangem.core.decompose.factory.ComponentFactory -import com.tangem.core.ui.decompose.ComposableContentComponent -import com.tangem.domain.nft.models.NFTAsset -import com.tangem.domain.wallets.models.UserWalletId - -interface NFTDetailsComponent : ComposableContentComponent { - - data class Params( - val userWalletId: UserWalletId, - val nftAsset: NFTAsset, - val nftCollectionName: String, - ) - - interface Factory : ComponentFactory -} \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/DefaultNFTCollectionsComponent.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/NFTCollectionsComponent.kt similarity index 60% rename from features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/DefaultNFTCollectionsComponent.kt rename to features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/NFTCollectionsComponent.kt index bb82591e48..209883f972 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/DefaultNFTCollectionsComponent.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/NFTCollectionsComponent.kt @@ -6,17 +6,18 @@ import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.nft.models.NFTAsset +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.nft.collections.model.NFTCollectionsModel import com.tangem.features.nft.collections.ui.NFTCollections -import com.tangem.features.nft.component.NFTCollectionsComponent import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -internal class DefaultNFTCollectionsComponent @AssistedInject constructor( +internal class NFTCollectionsComponent @AssistedInject constructor( @Assisted context: AppComponentContext, - @Assisted private val params: NFTCollectionsComponent.Params, -) : NFTCollectionsComponent, AppComponentContext by context { + @Assisted private val params: Params, +) : ComposableContentComponent, AppComponentContext by context { private val model: NFTCollectionsModel = getOrCreateModel(params) @@ -27,11 +28,10 @@ internal class DefaultNFTCollectionsComponent @AssistedInject constructor( NFTCollections(state, modifier) } - @AssistedFactory - interface Factory : NFTCollectionsComponent.Factory { - override fun create( - context: AppComponentContext, - params: NFTCollectionsComponent.Params, - ): DefaultNFTCollectionsComponent - } + data class Params( + val userWalletId: UserWalletId, + val onBackClick: () -> Unit, + val onAssetClick: (asset: NFTAsset, collectionName: String) -> Unit, + val onReceiveClick: () -> Unit, + ) } \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt index b8b89b6d9b..2e1ddc7a19 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt @@ -1,24 +1,21 @@ package com.tangem.features.nft.collections.model -import com.tangem.common.routing.AppRoute import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer -import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.components.fields.InputManager import com.tangem.core.ui.components.fields.entity.SearchBarUM import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.nft.FetchNFTCollectionAssetsUseCase import com.tangem.domain.nft.GetNFTCollectionsUseCase -import com.tangem.domain.nft.models.NFTAsset import com.tangem.domain.nft.models.NFTCollection +import com.tangem.features.nft.collections.NFTCollectionsComponent import com.tangem.features.nft.collections.entity.NFTCollectionsStateUM import com.tangem.features.nft.collections.entity.NFTCollectionsUM import com.tangem.features.nft.collections.entity.transformer.ChangeCollectionExpandedStateTransformer import com.tangem.features.nft.collections.entity.transformer.ToggleSearchBarTransformer import com.tangem.features.nft.collections.entity.transformer.UpdateDataStateTransformer import com.tangem.features.nft.collections.entity.transformer.UpdateSearchQueryTransformer -import com.tangem.features.nft.component.NFTCollectionsComponent import com.tangem.features.nft.impl.R import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.* @@ -29,23 +26,22 @@ import javax.inject.Inject @ModelScoped internal class NFTCollectionsModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, - private val router: Router, private val searchManager: InputManager, private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase, private val fetchNFTCollectionAssetsUseCase: FetchNFTCollectionAssetsUseCase, paramsContainer: ParamsContainer, ) : Model() { - val state: StateFlow get() = _state + private val params: NFTCollectionsComponent.Params = paramsContainer.require() private val _state = MutableStateFlow( value = NFTCollectionsStateUM( - onBackClick = ::navigateBack, - content = NFTCollectionsUM.Loading(::onReceiveClick), + onBackClick = params.onBackClick, + content = NFTCollectionsUM.Loading(params.onBackClick), ), ) - private val params: NFTCollectionsComponent.Params = paramsContainer.require() + val state: StateFlow get() = _state init { subscribeToNFTCollections() @@ -60,11 +56,15 @@ internal class NFTCollectionsModel @Inject constructor( UpdateDataStateTransformer( nftCollections = nftCollections, searchQuery = query, - onReceiveClick = ::onReceiveClick, + onReceiveClick = { + params.onReceiveClick() + }, onRetryClick = ::onRetryClick, onExpandCollectionClick = ::onExpandCollectionClick, onRetryAssetsClick = ::onRetryAssetsClick, - onAssetClick = ::onAssetClick, + onAssetClick = { asset, collectionName -> + params.onAssetClick(asset, collectionName) + }, initialSearchBarFactory = ::getInitialSearchBar, ).transform(it) } @@ -115,28 +115,6 @@ internal class NFTCollectionsModel @Inject constructor( // TODO refresh all } - private fun onAssetClick(asset: NFTAsset, collectionName: String) { - router.push( - AppRoute.NFTDetails( - userWalletId = params.userWalletId, - nftAsset = asset, - collectionName = collectionName, - ), - ) - } - - private fun onReceiveClick() { - router.push( - AppRoute.NFTReceive( - userWalletId = params.userWalletId, - ), - ) - } - - private fun navigateBack() { - router.pop() - } - private fun loadCollectionAssets(collection: NFTCollection) { modelScope.launch { fetchNFTCollectionAssetsUseCase( diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/DefaultNFTComponent.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/DefaultNFTComponent.kt new file mode 100644 index 0000000000..1c85ec5d39 --- /dev/null +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/DefaultNFTComponent.kt @@ -0,0 +1,172 @@ +package com.tangem.features.nft.common + +import androidx.activity.compose.BackHandler +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import com.arkivanov.decompose.extensions.compose.subscribeAsState +import com.arkivanov.decompose.router.stack.StackNavigation +import com.arkivanov.decompose.router.stack.childStack +import com.arkivanov.decompose.router.stack.pop +import com.arkivanov.decompose.value.ObserveLifecycleMode +import com.arkivanov.decompose.value.subscribe +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.core.ui.decompose.ComposableContentComponent +import com.tangem.features.nft.collections.NFTCollectionsComponent +import com.tangem.features.nft.common.ui.NFTContent +import com.tangem.features.nft.component.NFTComponent +import com.tangem.features.nft.details.NFTDetailsComponent +import com.tangem.features.nft.receive.NFTReceiveComponent +import com.tangem.features.nft.traits.NFTAssetTraitsComponent +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.launch + +internal class DefaultNFTComponent @AssistedInject constructor( + @Assisted appComponentContext: AppComponentContext, + @Assisted private val params: NFTComponent.Params, +) : NFTComponent, AppComponentContext by appComponentContext { + + private val stackNavigation = StackNavigation() + + private val innerRouter = InnerRouter( + stackNavigation = stackNavigation, + popCallback = { onChildBack() }, + ) + + private val initialRoute: NFTRoute = NFTRoute.Collections(params.userWalletId) + private val currentRoute = MutableStateFlow(initialRoute) + + private val childStack = childStack( + key = "sendInnerStack", + source = stackNavigation, + serializer = null, + initialConfiguration = initialRoute, + handleBackButton = true, + childFactory = { configuration, factoryContext -> + createChild( + configuration, + childByContext( + componentContext = factoryContext, + router = innerRouter, + ), + ) + }, + ) + + init { + childStack.subscribe( + lifecycle = lifecycle, + mode = ObserveLifecycleMode.CREATE_DESTROY, + ) { stack -> + componentScope.launch { + currentRoute.emit(stack.active.configuration) + } + } + } + + @Composable + override fun Content(modifier: Modifier) { + val stackState by childStack.subscribeAsState() + + BackHandler(onBack = ::onChildBack) + NFTContent( + stackState = stackState, + ) + } + + private fun createChild(route: NFTRoute, factoryContext: AppComponentContext) = when (route) { + is NFTRoute.Collections -> getCollectionsComponent(factoryContext, route) + is NFTRoute.Receive -> getReceiveComponent(factoryContext, route) + is NFTRoute.Details -> getDetailsComponent(factoryContext, route) + is NFTRoute.AssetTraits -> getAssetTraitsComponent(factoryContext, route) + } + + private fun getCollectionsComponent( + factoryContext: AppComponentContext, + route: NFTRoute.Collections, + ): ComposableContentComponent = NFTCollectionsComponent( + context = factoryContext, + params = NFTCollectionsComponent.Params( + userWalletId = route.userWalletId, + onBackClick = ::onChildBack, + onReceiveClick = { + innerRouter.push( + NFTRoute.Receive( + userWalletId = route.userWalletId, + ), + ) + }, + onAssetClick = { asset, collectionName -> + innerRouter.push( + NFTRoute.Details( + userWalletId = route.userWalletId, + nftAsset = asset, + collectionName = collectionName, + ), + ) + }, + ), + ) + + private fun getReceiveComponent( + factoryContext: AppComponentContext, + route: NFTRoute.Receive, + ): ComposableContentComponent = NFTReceiveComponent( + context = factoryContext, + params = NFTReceiveComponent.Params( + userWalletId = route.userWalletId, + onBackClick = ::onChildBack, + ), + ) + + private fun getDetailsComponent( + factoryContext: AppComponentContext, + route: NFTRoute.Details, + ): ComposableContentComponent = NFTDetailsComponent( + context = factoryContext, + params = NFTDetailsComponent.Params( + userWalletId = route.userWalletId, + nftAsset = route.nftAsset, + nftCollectionName = route.collectionName, + onBackClick = ::onChildBack, + onAllTraitsClick = { + innerRouter.push( + NFTRoute.AssetTraits( + nftAsset = route.nftAsset, + ), + ) + }, + ), + ) + + private fun getAssetTraitsComponent( + factoryContext: AppComponentContext, + route: NFTRoute.AssetTraits, + ): ComposableContentComponent = NFTAssetTraitsComponent( + context = factoryContext, + params = NFTAssetTraitsComponent.Params( + nftAsset = route.nftAsset, + onBackClick = ::onChildBack, + ), + ) + + private fun onChildBack() { + val isEmptyStack = childStack.value.backStack.isEmpty() + + if (isEmptyStack) { + router.pop() + } else { + stackNavigation.pop() + } + } + + @AssistedFactory + interface Factory : NFTComponent.Factory { + override fun create(context: AppComponentContext, params: NFTComponent.Params): DefaultNFTComponent + } +} \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/NFTRoute.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/NFTRoute.kt new file mode 100644 index 0000000000..5c3482f2f6 --- /dev/null +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/NFTRoute.kt @@ -0,0 +1,31 @@ +package com.tangem.features.nft.common + +import com.tangem.core.decompose.navigation.Route +import com.tangem.domain.nft.models.NFTAsset +import com.tangem.domain.wallets.models.UserWalletId +import kotlinx.serialization.Serializable + +internal sealed class NFTRoute : Route { + + @Serializable + data class Collections( + val userWalletId: UserWalletId, + ) : NFTRoute() + + @Serializable + data class Receive( + val userWalletId: UserWalletId, + ) : NFTRoute() + + @Serializable + data class Details( + val userWalletId: UserWalletId, + val nftAsset: NFTAsset, + val collectionName: String, + ) : NFTRoute() + + @Serializable + data class AssetTraits( + val nftAsset: NFTAsset, + ) : NFTRoute() +} \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/ui/NFTContent.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/ui/NFTContent.kt new file mode 100644 index 0000000000..ef907f1e0f --- /dev/null +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/common/ui/NFTContent.kt @@ -0,0 +1,37 @@ +package com.tangem.features.nft.common.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.arkivanov.decompose.extensions.compose.stack.Children +import com.arkivanov.decompose.extensions.compose.stack.animation.slide +import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation +import com.arkivanov.decompose.router.stack.ChildStack +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.nft.common.NFTRoute + +@Composable +internal fun NFTContent(stackState: ChildStack) { + Column( + modifier = Modifier.Companion + .background(color = TangemTheme.colors.background.tertiary) + .fillMaxSize() + .imePadding() + .systemBarsPadding(), + horizontalAlignment = Alignment.Companion.CenterHorizontally, + ) { + Children( + stack = stackState, + animation = stackAnimation(slide()), + modifier = Modifier.weight(1f), + ) { + it.instance.Content(Modifier.weight(1f)) + } + } +} \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/DefaultNFTDetailsComponent.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/NFTDetailsComponent.kt similarity index 59% rename from features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/DefaultNFTDetailsComponent.kt rename to features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/NFTDetailsComponent.kt index bb220d9f9f..274d87d25e 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/DefaultNFTDetailsComponent.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/NFTDetailsComponent.kt @@ -6,17 +6,18 @@ import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.model.getOrCreateModel -import com.tangem.features.nft.component.NFTDetailsComponent +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.nft.models.NFTAsset +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.nft.details.model.NFTDetailsModel import com.tangem.features.nft.details.ui.NFTDetails import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -internal class DefaultNFTDetailsComponent @AssistedInject constructor( +internal class NFTDetailsComponent @AssistedInject constructor( @Assisted context: AppComponentContext, - @Assisted private val params: NFTDetailsComponent.Params, -) : NFTDetailsComponent, AppComponentContext by context { + @Assisted private val params: Params, +) : ComposableContentComponent, AppComponentContext by context { private val model: NFTDetailsModel = getOrCreateModel(params) @@ -27,11 +28,11 @@ internal class DefaultNFTDetailsComponent @AssistedInject constructor( NFTDetails(state, modifier) } - @AssistedFactory - interface Factory : NFTDetailsComponent.Factory { - override fun create( - context: AppComponentContext, - params: NFTDetailsComponent.Params, - ): DefaultNFTDetailsComponent - } + data class Params( + val userWalletId: UserWalletId, + val nftAsset: NFTAsset, + val nftCollectionName: String, + val onBackClick: () -> Unit, + val onAllTraitsClick: () -> Unit, + ) } \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt index 4c45c7a714..c81f317e67 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt @@ -5,7 +5,7 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router -import com.tangem.features.nft.component.NFTDetailsComponent +import com.tangem.features.nft.details.NFTDetailsComponent import com.tangem.features.nft.details.entity.NFTAssetUM import com.tangem.features.nft.details.entity.NFTDetailsUM import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -35,9 +35,9 @@ internal class NFTDetailsModel @Inject constructor( traits = persistentListOf(), baseInfoItems = persistentListOf(), ), - onBackClick = ::navigateBack, + onBackClick = params.onBackClick, onReadMoreClick = ::onReadMoreClick, - onSeeAllTraitsClick = ::onSeeAllTraitsClick, + onSeeAllTraitsClick = params.onAllTraitsClick, onExploreClick = ::onExploreClick, onSendClick = ::onSendClick, bottomSheetConfig = null, @@ -48,14 +48,6 @@ internal class NFTDetailsModel @Inject constructor( // TODO implement } - private fun onSeeAllTraitsClick() { - router.push( - AppRoute.NFTAssetTraits( - nftAsset = params.nftAsset, - ), - ) - } - private fun onExploreClick() { // TODO implement } @@ -69,8 +61,4 @@ internal class NFTDetailsModel @Inject constructor( ), ) } - - private fun navigateBack() { - router.pop() - } } \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/di/NFTFeatureModule.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/di/NFTFeatureModule.kt index af79399a92..abc85dcd0a 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/di/NFTFeatureModule.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/di/NFTFeatureModule.kt @@ -4,19 +4,12 @@ import com.tangem.core.configtoggle.feature.FeatureTogglesManager import com.tangem.core.decompose.model.Model import com.tangem.features.nft.DefaultNFTFeatureToggles import com.tangem.features.nft.NFTFeatureToggles -import com.tangem.features.nft.collections.DefaultNFTCollectionsComponent import com.tangem.features.nft.collections.model.NFTCollectionsModel -import com.tangem.features.nft.component.NFTCollectionsComponent -import com.tangem.features.nft.component.NFTDetailsBlockComponent -import com.tangem.features.nft.component.NFTDetailsComponent -import com.tangem.features.nft.component.NFTReceiveComponent -import com.tangem.features.nft.component.NFTAssetTraitsComponent -import com.tangem.features.nft.details.DefaultNFTDetailsComponent +import com.tangem.features.nft.common.DefaultNFTComponent +import com.tangem.features.nft.component.* import com.tangem.features.nft.details.block.DefaultNFTDetailsBlockComponent import com.tangem.features.nft.details.model.NFTDetailsModel -import com.tangem.features.nft.receive.DefaultNFTReceiveComponent import com.tangem.features.nft.receive.model.NFTReceiveModel -import com.tangem.features.nft.traits.DefaultNFTAssetTraitsComponent import com.tangem.features.nft.traits.model.NFTAssetTraitsModel import dagger.Binds import dagger.Module @@ -43,28 +36,18 @@ internal object NFTFeatureModule { internal interface NFTFeatureModuleBinds { @Binds @Singleton - fun bindNFTCollectionsComponentFactory( - impl: DefaultNFTCollectionsComponent.Factory, - ): NFTCollectionsComponent.Factory + fun bindNFTComponentFactory(impl: DefaultNFTComponent.Factory): NFTComponent.Factory @Binds @IntoMap @ClassKey(NFTCollectionsModel::class) fun bindNFTCollectionsModel(model: NFTCollectionsModel): Model - @Binds - @Singleton - fun bindNFTReceiveComponentFactory(impl: DefaultNFTReceiveComponent.Factory): NFTReceiveComponent.Factory - @Binds @IntoMap @ClassKey(NFTReceiveModel::class) fun bindNFTReceiveModel(model: NFTReceiveModel): Model - @Binds - @Singleton - fun bindNFTDetailsComponentFactory(impl: DefaultNFTDetailsComponent.Factory): NFTDetailsComponent.Factory - @Binds @IntoMap @ClassKey(NFTDetailsModel::class) @@ -76,10 +59,6 @@ internal interface NFTFeatureModuleBinds { impl: DefaultNFTDetailsBlockComponent.Factory, ): NFTDetailsBlockComponent.Factory - @Binds - @Singleton - fun bindNFTTraitsComponentFactory(impl: DefaultNFTAssetTraitsComponent.Factory): NFTAssetTraitsComponent.Factory - @Binds @IntoMap @ClassKey(NFTAssetTraitsModel::class) diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/DefaultNFTReceiveComponent.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/NFTReceiveComponent.kt similarity index 60% rename from features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/DefaultNFTReceiveComponent.kt rename to features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/NFTReceiveComponent.kt index f9651f18e3..0be6d0b5f7 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/DefaultNFTReceiveComponent.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/NFTReceiveComponent.kt @@ -6,17 +6,17 @@ import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.model.getOrCreateModel -import com.tangem.features.nft.component.NFTReceiveComponent +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.nft.receive.model.NFTReceiveModel import com.tangem.features.nft.receive.ui.NFTReceive import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -internal class DefaultNFTReceiveComponent @AssistedInject constructor( +internal class NFTReceiveComponent @AssistedInject constructor( @Assisted context: AppComponentContext, - @Assisted private val params: NFTReceiveComponent.Params, -) : NFTReceiveComponent, AppComponentContext by context { + @Assisted private val params: Params, +) : ComposableContentComponent, AppComponentContext by context { private val model: NFTReceiveModel = getOrCreateModel(params) @@ -27,11 +27,8 @@ internal class DefaultNFTReceiveComponent @AssistedInject constructor( NFTReceive(state, modifier) } - @AssistedFactory - interface Factory : NFTReceiveComponent.Factory { - override fun create( - context: AppComponentContext, - params: NFTReceiveComponent.Params, - ): DefaultNFTReceiveComponent - } + data class Params( + val userWalletId: UserWalletId, + val onBackClick: () -> Unit, + ) } \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt index dc0eefd9b3..83bfeedb42 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt @@ -3,7 +3,6 @@ package com.tangem.features.nft.receive.model import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer -import com.tangem.core.decompose.navigation.Router import com.tangem.core.navigation.share.ShareManager import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.core.ui.components.fields.InputManager @@ -14,8 +13,8 @@ import com.tangem.domain.nft.GetNFTAvailableNetworksUseCase import com.tangem.domain.nft.GetNFTNetworkStatusUseCase import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.model.NetworkStatus -import com.tangem.features.nft.component.NFTReceiveComponent import com.tangem.features.nft.impl.R +import com.tangem.features.nft.receive.NFTReceiveComponent import com.tangem.features.nft.receive.entity.NFTReceiveUM import com.tangem.features.nft.receive.entity.transformer.ShowReceiveBottomSheetTransformer import com.tangem.features.nft.receive.entity.transformer.ToggleSearchBarTransformer @@ -31,7 +30,6 @@ import javax.inject.Inject @ModelScoped internal class NFTReceiveModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, - private val router: Router, private val searchManager: InputManager, private val getNFTAvailableNetworksUseCase: GetNFTAvailableNetworksUseCase, private val filterNFTAvailableNetworksUseCase: FilterNFTAvailableNetworksUseCase, @@ -41,18 +39,18 @@ internal class NFTReceiveModel @Inject constructor( paramsContainer: ParamsContainer, ) : Model() { - val state: StateFlow get() = _state + private val params: NFTReceiveComponent.Params = paramsContainer.require() private val _state = MutableStateFlow( value = NFTReceiveUM( - onBackClick = ::navigateBack, + onBackClick = params.onBackClick, search = getInitialSearchBar(), networks = NFTReceiveUM.Networks.Content(persistentListOf()), bottomSheetConfig = null, ), ) - private val params: NFTReceiveComponent.Params = paramsContainer.require() + val state: StateFlow get() = _state init { subscribeToNFTAvailableNetworks() @@ -140,8 +138,4 @@ internal class NFTReceiveModel @Inject constructor( private fun onShareClick(text: String) { shareManager.shareText(text = text) } - - private fun navigateBack() { - router.pop() - } } \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/DefaultNFTAssetTraitsComponent.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/NFTAssetTraitsComponent.kt similarity index 59% rename from features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/DefaultNFTAssetTraitsComponent.kt rename to features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/NFTAssetTraitsComponent.kt index ce9f6af262..ec54b5846d 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/DefaultNFTAssetTraitsComponent.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/NFTAssetTraitsComponent.kt @@ -6,17 +6,17 @@ import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.model.getOrCreateModel -import com.tangem.features.nft.component.NFTAssetTraitsComponent -import com.tangem.features.nft.traits.ui.NFTAssetTraits +import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.domain.nft.models.NFTAsset import com.tangem.features.nft.traits.model.NFTAssetTraitsModel +import com.tangem.features.nft.traits.ui.NFTAssetTraits import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -internal class DefaultNFTAssetTraitsComponent @AssistedInject constructor( +internal class NFTAssetTraitsComponent @AssistedInject constructor( @Assisted context: AppComponentContext, - @Assisted private val params: NFTAssetTraitsComponent.Params, -) : NFTAssetTraitsComponent, AppComponentContext by context { + @Assisted private val params: Params, +) : ComposableContentComponent, AppComponentContext by context { private val model: NFTAssetTraitsModel = getOrCreateModel(params) @@ -27,11 +27,8 @@ internal class DefaultNFTAssetTraitsComponent @AssistedInject constructor( NFTAssetTraits(state) } - @AssistedFactory - interface Factory : NFTAssetTraitsComponent.Factory { - override fun create( - context: AppComponentContext, - params: NFTAssetTraitsComponent.Params, - ): DefaultNFTAssetTraitsComponent - } + data class Params( + val nftAsset: NFTAsset, + val onBackClick: () -> Unit, + ) } \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/model/NFTAssetTraitsModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/model/NFTAssetTraitsModel.kt index 73c030f059..52ed09006f 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/model/NFTAssetTraitsModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/traits/model/NFTAssetTraitsModel.kt @@ -3,9 +3,8 @@ package com.tangem.features.nft.traits.model import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer -import com.tangem.core.decompose.navigation.Router import com.tangem.domain.nft.models.NFTAsset -import com.tangem.features.nft.component.NFTAssetTraitsComponent +import com.tangem.features.nft.traits.NFTAssetTraitsComponent import com.tangem.features.nft.traits.entity.NFTAssetTraitUM import com.tangem.features.nft.traits.entity.NFTAssetTraitsUM import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -17,21 +16,20 @@ import javax.inject.Inject @ModelScoped internal class NFTAssetTraitsModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, - private val router: Router, paramsContainer: ParamsContainer, ) : Model() { private val params: NFTAssetTraitsComponent.Params = paramsContainer.require() - val state: StateFlow get() = _state - private val _state = MutableStateFlow( value = NFTAssetTraitsUM( traits = params.nftAsset.transform(), - onBackClick = ::navigateBack, + onBackClick = { params.onBackClick() }, ), ) + val state: StateFlow get() = _state + private fun NFTAsset.transform(): ImmutableList = this .traits .mapIndexed { index, trait -> @@ -41,8 +39,4 @@ internal class NFTAssetTraitsModel @Inject constructor( value = trait.value, ) }.toPersistentList() - - private fun navigateBack() { - router.pop() - } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt index 79fd4f1a7f..c1e1f1fde0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt @@ -240,6 +240,6 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( } override fun onNFTClick(userWalletId: UserWalletId) { - router.openNFTCollectionsScreen(userWalletId) + router.openNFT(userWalletId) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index f6305b826f..23ac155b8b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -116,7 +116,7 @@ internal class DefaultWalletRouter @Inject constructor( reduxStateHolder.dispatchDialogShow(StateDialog.ScanFailsDialog(StateDialog.ScanFailsSource.MAIN, onTryAgain)) } - override fun openNFTCollectionsScreen(userWalletId: UserWalletId) { - router.push(AppRoute.NFTCollections(userWalletId)) + override fun openNFT(userWalletId: UserWalletId) { + router.push(AppRoute.NFT(userWalletId)) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt index 4e49fb9f70..ad25778b8a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt @@ -58,5 +58,5 @@ internal interface InnerWalletRouter { fun openScanFailedDialog(onTryAgain: () -> Unit) /** Open NFT collections screen */ - fun openNFTCollectionsScreen(userWalletId: UserWalletId) + fun openNFT(userWalletId: UserWalletId) } \ No newline at end of file