Updated on 2026-08-14

This commit is contained in:
Tangem 2025-06-10 11:49:50 +05:00
parent 9cc51216bc
commit 784051ddeb
9 changed files with 78 additions and 73 deletions

View file

@ -119,7 +119,9 @@ internal class DefaultNFTRepository @Inject constructor(
userWalletId: UserWalletId,
networks: List<Network>,
): Flow<List<NFTCollections>> = combine(
networks.map { observeCollectionsInternal(userWalletId, it) },
networks
.sortedBy { it.name }
.map { observeCollectionsInternal(userWalletId, it) },
) { it.asList() }
private suspend fun observeCollectionsInternal(

View file

@ -8,6 +8,7 @@ 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.nft.models.NFTCollection
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.nft.collections.model.NFTCollectionsModel
import com.tangem.features.nft.collections.ui.NFTCollections
@ -31,7 +32,7 @@ internal class NFTCollectionsComponent @AssistedInject constructor(
data class Params(
val userWalletId: UserWalletId,
val onBackClick: () -> Unit,
val onAssetClick: (asset: NFTAsset, collectionName: String) -> Unit,
val onAssetClick: (asset: NFTAsset, collection: NFTCollection) -> Unit,
val onReceiveClick: () -> Unit,
)
}

View file

@ -20,7 +20,7 @@ internal class UpdateDataStateTransformer(
private val onRetryClick: () -> Unit,
private val onExpandCollectionClick: (NFTCollection) -> Unit,
private val onRetryAssetsClick: (NFTCollection) -> Unit,
private val onAssetClick: (NFTAsset, String) -> Unit,
private val onAssetClick: (NFTAsset, NFTCollection) -> Unit,
private val initialSearchBarFactory: () -> SearchBarUM,
private val collectionIdProvider: NFTCollection.() -> String,
) : Transformer<NFTCollectionsStateUM> {
@ -118,12 +118,12 @@ internal class UpdateDataStateTransformer(
is NFTCollection.Assets.Value -> NFTCollectionAssetsListUM.Content(
items = assets
.items
.map { it.transform(name.orEmpty()) }
.map { it.transform(this) }
.toPersistentList(),
)
}
private fun NFTAsset.transform(collectionName: String): NFTCollectionAssetUM {
private fun NFTAsset.transform(collection: NFTCollection): NFTCollectionAssetUM {
return NFTCollectionAssetUM(
id = id.toString(),
name = name ?: DASH_SIGN,
@ -144,7 +144,7 @@ internal class UpdateDataStateTransformer(
)
},
onItemClick = {
onAssetClick(this, collectionName)
onAssetClick(this, collection)
},
)
}

View file

@ -79,8 +79,8 @@ internal class NFTCollectionsModel @Inject constructor(
onRetryClick = ::onRefresh,
onExpandCollectionClick = ::onExpandCollectionClick,
onRetryAssetsClick = ::onRetryAssetsClick,
onAssetClick = { asset, collectionName ->
params.onAssetClick(asset, collectionName)
onAssetClick = { asset, collection ->
params.onAssetClick(asset, collection)
},
initialSearchBarFactory = ::getInitialSearchBar,
collectionIdProvider = collectionIdProvider,

View file

@ -112,12 +112,12 @@ internal class DefaultNFTComponent @AssistedInject constructor(
),
)
},
onAssetClick = { asset, collectionName ->
onAssetClick = { asset, collection ->
innerRouter.push(
NFTRoute.Details(
userWalletId = route.userWalletId,
nftAsset = asset,
collectionName = collectionName,
collection = collection,
),
)
},
@ -144,7 +144,7 @@ internal class DefaultNFTComponent @AssistedInject constructor(
params = NFTDetailsComponent.Params(
userWalletId = route.userWalletId,
nftAsset = route.nftAsset,
nftCollectionName = route.collectionName,
nftCollection = route.collection,
onBackClick = ::onChildBack,
onAllTraitsClick = {
innerRouter.push(

View file

@ -2,6 +2,7 @@ package com.tangem.features.nft.common
import com.tangem.core.decompose.navigation.Route
import com.tangem.domain.nft.models.NFTAsset
import com.tangem.domain.nft.models.NFTCollection
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.serialization.Serializable
@ -21,7 +22,7 @@ internal sealed class NFTRoute : Route {
data class Details(
val userWalletId: UserWalletId,
val nftAsset: NFTAsset,
val collectionName: String,
val collection: NFTCollection,
) : NFTRoute()
@Serializable

View file

@ -14,6 +14,7 @@ import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.nft.models.NFTAsset
import com.tangem.domain.nft.models.NFTCollection
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.nft.details.entity.NFTDetailsBottomSheetConfig
import com.tangem.features.nft.details.info.NFTDetailsInfoComponent
@ -65,7 +66,7 @@ internal class NFTDetailsComponent @AssistedInject constructor(
data class Params(
val userWalletId: UserWalletId,
val nftAsset: NFTAsset,
val nftCollectionName: String,
val nftCollection: NFTCollection,
val onBackClick: () -> Unit,
val onAllTraitsClick: () -> Unit,
)

View file

@ -10,6 +10,7 @@ import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.nft.models.NFTAsset
import com.tangem.domain.nft.models.NFTCollection
import com.tangem.domain.nft.models.NFTSalePrice
import com.tangem.features.nft.details.entity.NFTAssetUM
import com.tangem.features.nft.details.entity.NFTDetailsUM
@ -29,8 +30,8 @@ internal class NFTDetailsUMFactory(
private val onInfoBlockClick: (title: TextReference, text: TextReference) -> Unit,
) {
fun getInitialState(nftAsset: NFTAsset): NFTDetailsUM = NFTDetailsUM(
nftAsset = nftAsset.transform(),
fun getInitialState(nftAsset: NFTAsset, nftCollection: NFTCollection): NFTDetailsUM = NFTDetailsUM(
nftAsset = nftAsset.transform(nftCollection),
pullToRefreshConfig = PullToRefreshConfig(
isRefreshing = false,
onRefresh = { onRefresh() },
@ -42,63 +43,62 @@ internal class NFTDetailsUMFactory(
onSendClick = onSendClick,
)
private fun NFTAsset.transform(): NFTAssetUM = NFTAssetUM(
name = name.orEmpty(),
media = media?.imageUrl?.let {
NFTAssetUM.Media.Content(
url = it,
)
} ?: NFTAssetUM.Media.Empty,
topInfo = when {
!hasSalePrice() && description.isNullOrEmpty() && rarity == null -> {
NFTAssetUM.TopInfo.Empty
}
else -> {
val hasSalePrice = hasSalePrice()
val hasDescription = !description.isNullOrEmpty()
val rarity = rarity
NFTAssetUM.TopInfo.Content(
title = if (hasSalePrice) {
resourceReference(R.string.nft_details_last_sale_price)
} else {
null
},
salePrice = toSalePrice(),
description = description,
rarity = if (rarity != null) {
NFTAssetUM.Rarity.Content(
rank = rarity.rank,
label = rarity.label,
showDivider = hasSalePrice || hasDescription,
onLabelClick = {
onInfoBlockClick(
resourceReference(R.string.nft_details_rarity_label),
resourceReference(R.string.nft_details_info_rarity_label),
)
},
onRankClick = {
onInfoBlockClick(
resourceReference(R.string.nft_details_rarity_rank),
resourceReference(R.string.nft_details_info_rarity_rank),
)
},
)
} else {
NFTAssetUM.Rarity.Empty
},
private fun NFTAsset.transform(nftCollection: NFTCollection): NFTAssetUM {
val description = description?.takeIf { it.isNotEmpty() } ?: nftCollection.description
return NFTAssetUM(
name = name.orEmpty(),
media = media?.imageUrl?.let {
NFTAssetUM.Media.Content(
url = it,
)
}
},
traits = traits.take(MAX_TRAITS_COUNT).map {
NFTAssetUM.BlockItem(
title = stringReference(it.name),
value = it.value,
showInfoButton = false,
)
}.toImmutableList(),
showAllTraitsButton = traits.size > MAX_TRAITS_COUNT,
baseInfoItems = buildBaseInfoItems(),
)
} ?: NFTAssetUM.Media.Empty,
topInfo = when {
!hasSalePrice() && description.isNullOrEmpty() && rarity == null -> {
NFTAssetUM.TopInfo.Empty
}
else -> {
val hasSalePrice = hasSalePrice()
val hasDescription = !description.isNullOrEmpty()
val rarity = rarity
NFTAssetUM.TopInfo.Content(
title = resourceReference(R.string.nft_details_last_sale_price).takeIf { hasSalePrice },
salePrice = toSalePrice(),
description = description,
rarity = if (rarity != null) {
NFTAssetUM.Rarity.Content(
rank = rarity.rank,
label = rarity.label,
showDivider = hasSalePrice || hasDescription,
onLabelClick = {
onInfoBlockClick(
resourceReference(R.string.nft_details_rarity_label),
resourceReference(R.string.nft_details_info_rarity_label),
)
},
onRankClick = {
onInfoBlockClick(
resourceReference(R.string.nft_details_rarity_rank),
resourceReference(R.string.nft_details_info_rarity_rank),
)
},
)
} else {
NFTAssetUM.Rarity.Empty
},
)
}
},
traits = traits.take(MAX_TRAITS_COUNT).map {
NFTAssetUM.BlockItem(
title = stringReference(it.name),
value = it.value,
showInfoButton = false,
)
}.toImmutableList(),
showAllTraitsButton = traits.size > MAX_TRAITS_COUNT,
baseInfoItems = buildBaseInfoItems(),
)
}
private fun NFTAsset.hasSalePrice() = salePrice !is NFTSalePrice.Empty && salePrice !is NFTSalePrice.Error

View file

@ -74,7 +74,7 @@ internal class NFTDetailsModel @Inject constructor(
private val _state by lazy {
MutableStateFlow(
value = stateFactory.getInitialState(params.nftAsset),
value = stateFactory.getInitialState(params.nftAsset, params.nftCollection),
)
}
@ -187,7 +187,7 @@ internal class NFTDetailsModel @Inject constructor(
AppRoute.NFTSend(
userWalletId = params.userWalletId,
nftAsset = params.nftAsset,
nftCollectionName = params.nftCollectionName,
nftCollectionName = params.nftCollection.name.orEmpty(),
),
)
}