Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-01 13:10:07 +05:00
parent aea7f5f415
commit c83ce2ada3
53 changed files with 1062 additions and 238 deletions

View file

@ -667,7 +667,7 @@ class DefaultWalletManagersFacade(
return walletManager.getAssets(address, collectionIdentifier)
}
override suspend fun getAsset(
override suspend fun getNFTAsset(
userWalletId: UserWalletId,
network: Network,
collectionIdentifier: NFTCollection.Identifier,
@ -682,6 +682,21 @@ class DefaultWalletManagersFacade(
return walletManager.getAsset(collectionIdentifier, assetIdentifier)
}
override suspend fun getNFTSalePrice(
userWalletId: UserWalletId,
network: Network,
collectionIdentifier: NFTCollection.Identifier,
assetIdentifier: NFTAsset.Identifier,
): NFTAsset.SalePrice? {
val blockchain = Blockchain.fromId(network.id.value)
val walletManager = getOrCreateWalletManager(
userWalletId = userWalletId,
blockchain = blockchain,
derivationPath = network.derivationPath.value,
) ?: return null
return walletManager.getSalePrice(collectionIdentifier, assetIdentifier)
}
override suspend fun isAccountInitialized(userWalletId: UserWalletId, network: Network): Boolean {
val walletManager = getOrCreateWalletManager(userWalletId = userWalletId, network = network)
val initializableAccountWalletManger = walletManager as? InitializableAccount ?: return true

View file

@ -259,13 +259,20 @@ interface WalletManagersFacade {
collectionIdentifier: NFTCollection.Identifier,
): List<NFTAsset>
suspend fun getAsset(
suspend fun getNFTAsset(
userWalletId: UserWalletId,
network: Network,
collectionIdentifier: NFTCollection.Identifier,
assetIdentifier: NFTAsset.Identifier,
): NFTAsset?
suspend fun getNFTSalePrice(
userWalletId: UserWalletId,
network: Network,
collectionIdentifier: NFTCollection.Identifier,
assetIdentifier: NFTAsset.Identifier,
): NFTAsset.SalePrice?
/**
* If wallet manager implements [InitializableAccount] then returns [InitializableAccount.isAccountInitialized]
* value. Otherwise always return true

View file

@ -3,43 +3,35 @@ package com.tangem.domain.nft.models
import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.Network
sealed class NFTAsset {
abstract val id: Identifier
data class NFTAsset(
val id: Identifier,
val collectionId: NFTCollection.Identifier,
val network: Network,
val contractType: String,
val owner: String?,
val name: String?,
val description: String?,
val salePrice: NFTSalePrice,
val rarity: Rarity?,
val media: Media?,
val traits: List<Trait>,
val source: StatusSource,
) {
data class Value(
override val id: Identifier,
val collectionId: NFTCollection.Identifier,
val network: Network,
val contractType: String,
val owner: String?,
val name: String?,
val description: String?,
val salePrice: NFTSalePrice,
val rarity: Rarity?,
val media: Media?,
val traits: List<Trait>,
val source: StatusSource,
) : NFTAsset() {
data class Media(
val mimetype: String?,
val url: String,
)
data class Media(
val mimetype: String,
val url: String,
)
data class Rarity(
val rank: String,
val label: String,
)
data class Rarity(
val rank: String,
val label: String,
)
data class Trait(
val name: String,
val value: String,
)
}
data class Error(
override val id: Identifier,
) : NFTAsset()
data class Trait(
val name: String,
val value: String,
)
sealed class Identifier {
data class EVM(

View file

@ -1,5 +1,6 @@
package com.tangem.domain.nft.models
import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.Network
data class NFTCollection(
@ -9,8 +10,18 @@ data class NFTCollection(
val description: String?,
val logoUrl: String?,
val count: Int,
val assets: List<NFTAsset> = emptyList(),
val assets: Assets,
) {
sealed class Assets {
data object Empty : Assets()
data object Loading : Assets()
data object Failed : Assets()
data class Value(
val items: List<NFTAsset>,
val source: StatusSource,
) : Assets()
}
sealed class Identifier {
data class EVM(val tokenAddress: String) : Identifier()
data class TON(val contractAddress: String?) : Identifier()

View file

@ -27,4 +27,31 @@ data class NFTCollections(
),
)
}
}
fun List<NFTCollections>.allCollectionsFailed() = this.all {
it.content is NFTCollections.Content.Error
}
fun List<NFTCollections>.anyCollectionFailed() = this.any {
it.content is NFTCollections.Content.Error ||
it.content is NFTCollections.Content.Collections &&
it.content.source == StatusSource.ONLY_CACHE
}
fun List<NFTCollections>.allLoadedCollectionsEmpty() = this
.map { it.content }
.filterIsInstance<NFTCollections.Content.Collections>()
.all { it.collections.isNullOrEmpty() }
fun List<NFTCollections>.allCollectionsLoaded() = this.all {
val content = it.content
content is NFTCollections.Content.Collections &&
content.source != StatusSource.CACHE
}
fun List<NFTCollections>.allCollectionsEmpty() = this.all {
val content = it.content
content is NFTCollections.Content.Collections &&
content.collections.isNullOrEmpty()
}

View file

@ -1,6 +1,5 @@
package com.tangem.domain.nft.models
import com.tangem.domain.models.StatusSource
import java.math.BigDecimal
sealed class NFTSalePrice {
@ -10,6 +9,10 @@ sealed class NFTSalePrice {
override val assetId: NFTAsset.Identifier,
) : NFTSalePrice()
data class Loading(
override val assetId: NFTAsset.Identifier,
) : NFTSalePrice()
data class Error(
override val assetId: NFTAsset.Identifier,
) : NFTSalePrice()
@ -18,6 +21,5 @@ sealed class NFTSalePrice {
override val assetId: NFTAsset.Identifier,
val value: BigDecimal,
val symbol: String,
val source: StatusSource,
) : NFTSalePrice()
}

View file

@ -0,0 +1,15 @@
package com.tangem.domain.nft
import com.tangem.domain.nft.models.NFTCollection
import com.tangem.domain.nft.repository.NFTRepository
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.wallets.models.UserWalletId
class FetchNFTCollectionAssetsUseCase(
private val nftRepository: NFTRepository,
) {
suspend operator fun invoke(userWalletId: UserWalletId, network: Network, collectionId: NFTCollection.Identifier) {
nftRepository.refreshAssets(userWalletId, network, collectionId)
}
}

View file

@ -14,7 +14,7 @@ class GetNFTCollectionsUseCase(
) {
@OptIn(ExperimentalCoroutinesApi::class)
fun launch(userWalletId: UserWalletId): Flow<List<NFTCollections>> = currenciesRepository
operator fun invoke(userWalletId: UserWalletId): Flow<List<NFTCollections>> = currenciesRepository
.getWalletCurrenciesUpdates(userWalletId)
.flatMapLatest {
val networks = it

View file

@ -1,5 +1,6 @@
package com.tangem.domain.nft.repository
import com.tangem.domain.nft.models.NFTCollection
import com.tangem.domain.nft.models.NFTCollections
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.wallets.models.UserWalletId
@ -9,4 +10,6 @@ interface NFTRepository {
fun observeCollections(userWalletId: UserWalletId, networks: List<Network>): Flow<List<NFTCollections>>
suspend fun refreshCollections(userWalletId: UserWalletId, networks: List<Network>)
suspend fun refreshAssets(userWalletId: UserWalletId, network: Network, collectionId: NFTCollection.Identifier)
}