Updated on 2026-08-14
This commit is contained in:
parent
fc4c7ef9ab
commit
cb04ddc533
21 changed files with 325 additions and 269 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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<Params, NFTAssetTraitsComponent>
|
||||
}
|
||||
|
|
@ -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<Params, NFTCollectionsComponent>
|
||||
}
|
||||
|
|
@ -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<Params, NFTReceiveComponent>
|
||||
interface Factory : ComponentFactory<Params, NFTComponent>
|
||||
}
|
||||
|
|
@ -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<Params, NFTDetailsComponent>
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -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<NFTCollectionsStateUM> 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<NFTCollectionsStateUM> 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(
|
||||
|
|
|
|||
|
|
@ -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<NFTRoute>()
|
||||
|
||||
private val innerRouter = InnerRouter<NFTRoute>(
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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<NFTRoute, ComposableContentComponent>) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -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<NFTReceiveUM> 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<NFTReceiveUM> 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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -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<NFTAssetTraitsUM> get() = _state
|
||||
|
||||
private val _state = MutableStateFlow(
|
||||
value = NFTAssetTraitsUM(
|
||||
traits = params.nftAsset.transform(),
|
||||
onBackClick = ::navigateBack,
|
||||
onBackClick = { params.onBackClick() },
|
||||
),
|
||||
)
|
||||
|
||||
val state: StateFlow<NFTAssetTraitsUM> get() = _state
|
||||
|
||||
private fun NFTAsset.transform(): ImmutableList<NFTAssetTraitUM> = this
|
||||
.traits
|
||||
.mapIndexed { index, trait ->
|
||||
|
|
@ -41,8 +39,4 @@ internal class NFTAssetTraitsModel @Inject constructor(
|
|||
value = trait.value,
|
||||
)
|
||||
}.toPersistentList()
|
||||
|
||||
private fun navigateBack() {
|
||||
router.pop()
|
||||
}
|
||||
}
|
||||
|
|
@ -240,6 +240,6 @@ internal class WalletContentClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onNFTClick(userWalletId: UserWalletId) {
|
||||
router.openNFTCollectionsScreen(userWalletId)
|
||||
router.openNFT(userWalletId)
|
||||
}
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
@ -58,5 +58,5 @@ internal interface InnerWalletRouter {
|
|||
fun openScanFailedDialog(onTryAgain: () -> Unit)
|
||||
|
||||
/** Open NFT collections screen */
|
||||
fun openNFTCollectionsScreen(userWalletId: UserWalletId)
|
||||
fun openNFT(userWalletId: UserWalletId)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue