Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-19 13:46:47 +07:00
parent 04ce95d61a
commit 1d374e5d07
3 changed files with 25 additions and 14 deletions

View file

@ -38,6 +38,8 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.joinAll import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -63,6 +65,7 @@ internal class DefaultNFTRepository @Inject constructor(
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains) private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
private val nftRuntimeStores = ConcurrentHashMap<String, NFTRuntimeStore>() private val nftRuntimeStores = ConcurrentHashMap<String, NFTRuntimeStore>()
private val nftRuntimeStoresMutex = Mutex()
private val nftPersistenceStores = ConcurrentHashMap<String, NFTPersistenceStore>() private val nftPersistenceStores = ConcurrentHashMap<String, NFTPersistenceStore>()
private val collectionIdConverter = NFTSdkCollectionIdentifierConverter private val collectionIdConverter = NFTSdkCollectionIdentifierConverter
@ -426,16 +429,17 @@ internal class DefaultNFTRepository @Inject constructor(
private suspend fun getNFTRuntimeStore(userWalletId: UserWalletId, network: Network): NFTRuntimeStore { private suspend fun getNFTRuntimeStore(userWalletId: UserWalletId, network: Network): NFTRuntimeStore {
val storeId = (userWalletId to network).formatted() val storeId = (userWalletId to network).formatted()
return nftRuntimeStores.getOrPut(storeId) { return nftRuntimeStoresMutex.withLock {
nftRuntimeStoreFactory.provide(network).also { nftRuntimeStores[storeId]?.let { return it }
nftRuntimeStores[storeId] = it val store = nftRuntimeStoreFactory.provide(network)
val storedCollections = getStoredCollections(userWalletId, network) val storedCollections = getStoredCollections(userWalletId, network)
val storedPrices = getStoredPrices(userWalletId, network) val storedPrices = getStoredPrices(userWalletId, network)
it.initialize( store.initialize(
collections = storedCollections, collections = storedCollections,
prices = storedPrices, prices = storedPrices,
) )
} nftRuntimeStores[storeId] = store
store
} }
} }

View file

@ -34,15 +34,15 @@ class GetNFTCollectionsUseCase(
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
fun invokeForAccounts(userWalletId: UserWalletId): Flow<WalletNFTCollections> { fun invokeForAccounts(userWalletId: UserWalletId): Flow<WalletNFTCollections> {
fun Account.flowOfNFTCollections(): Flow<Pair<Account, List<NFTCollections>>> { fun Account.flowOfNFTCollections(): Flow<Pair<Account, List<NFTCollections>>>? {
val currencies = (this as? Account.CryptoPortfolio)?.cryptoCurrencies.orEmpty() val currencies = (this as? Account.CryptoPortfolio)?.cryptoCurrencies.orEmpty()
if (currencies.isEmpty()) return null
return nftCollections(userWalletId = userWalletId, cryptoCurrencies = currencies.toList()) return nftCollections(userWalletId = userWalletId, cryptoCurrencies = currencies.toList())
.map { nfts -> this to nfts } .map { nfts -> this to nfts }
} }
return singleAccountListSupplier(userWalletId) return singleAccountListSupplier(userWalletId)
.mapLatest { statusList -> statusList.accounts.map { it.flowOfNFTCollections() } } .mapLatest { statusList -> statusList.accounts.mapNotNull { it.flowOfNFTCollections() } }
.flatMapLatest { flows -> combine(flows) { WalletNFTCollections(it.toMap()) } } .flatMapLatest { flows -> combine(flows) { WalletNFTCollections(it.toMap()) } }
} }
@ -53,6 +53,7 @@ class GetNFTCollectionsUseCase(
val networks = cryptoCurrencies val networks = cryptoCurrencies
.map { cryptoCurrency -> cryptoCurrency.network } .map { cryptoCurrency -> cryptoCurrency.network }
.distinct() .distinct()
if (networks.isEmpty()) return flowOf(emptyList())
return nftRepository.observeCollections(userWalletId, networks) return nftRepository.observeCollections(userWalletId, networks)
} }
} }

View file

@ -84,7 +84,7 @@ internal class UpdateDataStateTransformer(
if (isAccountMode) { if (isAccountMode) {
val result = mutableListOf<NFTCollectionItem>() val result = mutableListOf<NFTCollectionItem>()
walletNFTCollections.collections.forEach { (account, nfts) -> walletNFTCollections.collections.forEach { (account, nfts) ->
if (nfts.isEmpty()) return@forEach if (nfts.hasNoContentCollections()) return@forEach
result.add(account.toAccountPortfolioUM()) result.add(account.toAccountPortfolioUM())
result.addAll(createNFTsUM(nfts)) result.addAll(createNFTsUM(nfts))
} }
@ -105,6 +105,12 @@ internal class UpdateDataStateTransformer(
), ),
) )
private fun List<NFTCollections>.hasNoContentCollections() = this
.all { it.contentCollections().isEmpty() }
private fun NFTCollections.contentCollections() = (this.content as? NFTCollections.Content.Collections)
?.collections.orEmpty()
private fun NFTCollectionsStateUM.createNFTsUM(nftCollections: List<NFTCollections>): Sequence<NFTCollectionUM> = private fun NFTCollectionsStateUM.createNFTsUM(nftCollections: List<NFTCollections>): Sequence<NFTCollectionUM> =
nftCollections nftCollections
.map { it.content } .map { it.content }