Updated on 2026-08-14
This commit is contained in:
parent
296df28f0a
commit
bc70ed5327
8 changed files with 57 additions and 41 deletions
|
|
@ -9,7 +9,6 @@ import com.tangem.domain.nft.models.NFTSalePrice
|
|||
import com.tangem.domain.tokens.model.Network
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
internal class DefaultNFTRuntimeStore(
|
||||
|
|
@ -25,9 +24,7 @@ internal class DefaultNFTRuntimeStore(
|
|||
|
||||
override fun getCollections(): Flow<NFTCollections> = collectionsRuntimeStore
|
||||
.get()
|
||||
.combine(pricesRuntimeStore.get(), ::Pair)
|
||||
.map {
|
||||
val (collectionsData, prices) = it
|
||||
.combine(pricesRuntimeStore.get()) { collectionsData, prices ->
|
||||
collectionsData.mergeWithPrices(prices)
|
||||
}
|
||||
|
||||
|
|
@ -48,9 +45,7 @@ internal class DefaultNFTRuntimeStore(
|
|||
override fun getAsset(collectionId: NFTCollection.Identifier, assetId: NFTAsset.Identifier): Flow<NFTAsset> =
|
||||
collectionsRuntimeStore
|
||||
.get()
|
||||
.combine(getSalePrice(assetId), ::Pair)
|
||||
.map {
|
||||
val (collectionsData, price) = it
|
||||
.combine(getSalePrice(assetId)) { collectionsData, price ->
|
||||
collectionsData
|
||||
.getCollection(collectionId)
|
||||
?.getAsset(assetId)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,17 @@ class NFTPersistenceStoreFactory @Inject constructor(
|
|||
) {
|
||||
|
||||
fun provide(network: Network): NFTPersistenceStore {
|
||||
val networkStringIdentifier = listOfNotNull(
|
||||
network.id.value,
|
||||
network.derivationPath.value,
|
||||
).joinToString("_") {
|
||||
// remove all non-alphanumeric characters
|
||||
it
|
||||
.toCharArray()
|
||||
.filter(Char::isLetterOrDigit)
|
||||
.joinToString("")
|
||||
.lowercase()
|
||||
}
|
||||
return DefaultNFTPersistenceStore(
|
||||
collectionsPersistenceStore = DataStoreFactory.create(
|
||||
serializer = MoshiDataStoreSerializer(
|
||||
|
|
@ -34,7 +45,7 @@ class NFTPersistenceStoreFactory @Inject constructor(
|
|||
defaultValue = emptyList(),
|
||||
),
|
||||
produceFile = {
|
||||
context.dataStoreFile(fileName = "nft_${network.name}_${network.derivationPath}_collections")
|
||||
context.dataStoreFile(fileName = "nft_${networkStringIdentifier}_collections")
|
||||
},
|
||||
scope = CoroutineScope(context = dispatchers.io + SupervisorJob()),
|
||||
),
|
||||
|
|
@ -45,7 +56,7 @@ class NFTPersistenceStoreFactory @Inject constructor(
|
|||
defaultValue = emptyMap(),
|
||||
),
|
||||
produceFile = {
|
||||
context.dataStoreFile(fileName = "nft_${network.name}_${network.derivationPath}_prices")
|
||||
context.dataStoreFile(fileName = "nft_${networkStringIdentifier}_prices")
|
||||
},
|
||||
scope = CoroutineScope(context = dispatchers.io + SupervisorJob()),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import com.tangem.domain.nft.models.NFTAsset
|
|||
import com.tangem.utils.converter.TwoWayConverter
|
||||
import com.tangem.blockchain.nft.models.NFTAsset as SdkNFTAsset
|
||||
|
||||
class NFTSdkAssetIdentifierConverter : TwoWayConverter<SdkNFTAsset.Identifier, NFTAsset.Identifier> {
|
||||
object NFTSdkAssetIdentifierConverter : TwoWayConverter<SdkNFTAsset.Identifier, NFTAsset.Identifier> {
|
||||
override fun convert(value: SdkNFTAsset.Identifier): NFTAsset.Identifier = when (value) {
|
||||
is SdkNFTAsset.Identifier.EVM -> NFTAsset.Identifier.EVM(
|
||||
tokenId = value.tokenId,
|
||||
|
|
@ -13,7 +13,7 @@ class NFTSdkAssetIdentifierConverter : TwoWayConverter<SdkNFTAsset.Identifier, N
|
|||
is SdkNFTAsset.Identifier.TON -> NFTAsset.Identifier.TON(
|
||||
tokenAddress = value.tokenAddress,
|
||||
)
|
||||
is SdkNFTAsset.Identifier.Unknown -> error("unknown asset id")
|
||||
is SdkNFTAsset.Identifier.Unknown -> NFTAsset.Identifier.Unknown
|
||||
}
|
||||
|
||||
override fun convertBack(value: NFTAsset.Identifier): SdkNFTAsset.Identifier = when (value) {
|
||||
|
|
@ -24,5 +24,6 @@ class NFTSdkAssetIdentifierConverter : TwoWayConverter<SdkNFTAsset.Identifier, N
|
|||
is NFTAsset.Identifier.TON -> SdkNFTAsset.Identifier.TON(
|
||||
tokenAddress = value.tokenAddress,
|
||||
)
|
||||
is NFTAsset.Identifier.Unknown -> SdkNFTAsset.Identifier.Unknown
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.datasource.local.nft.converter
|
||||
|
||||
import com.tangem.domain.nft.models.NFTAsset
|
||||
import com.tangem.domain.nft.models.NFTCollection
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
|
@ -19,9 +20,13 @@ class NFTSdkCollectionConverter(
|
|||
description = collection.description,
|
||||
logoUrl = collection.logoUrl,
|
||||
count = collection.count,
|
||||
assets = collection.assets.map { asset ->
|
||||
nftSdkAssetConverter.convert(network to asset)
|
||||
},
|
||||
assets = collection.assets
|
||||
.map { asset ->
|
||||
nftSdkAssetConverter.convert(network to asset)
|
||||
}
|
||||
.filter {
|
||||
it.id !is NFTAsset.Identifier.Unknown
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import com.tangem.domain.nft.models.NFTCollection
|
|||
import com.tangem.utils.converter.TwoWayConverter
|
||||
import com.tangem.blockchain.nft.models.NFTCollection as SdkNFTCollection
|
||||
|
||||
class NFTSdkCollectionIdentifierConverter : TwoWayConverter<SdkNFTCollection.Identifier, NFTCollection.Identifier> {
|
||||
object NFTSdkCollectionIdentifierConverter : TwoWayConverter<SdkNFTCollection.Identifier, NFTCollection.Identifier> {
|
||||
override fun convert(value: SdkNFTCollection.Identifier): NFTCollection.Identifier = when (value) {
|
||||
is SdkNFTCollection.Identifier.EVM -> NFTCollection.Identifier.EVM(
|
||||
tokenAddress = value.tokenAddress,
|
||||
|
|
@ -12,7 +12,7 @@ class NFTSdkCollectionIdentifierConverter : TwoWayConverter<SdkNFTCollection.Ide
|
|||
is SdkNFTCollection.Identifier.TON -> NFTCollection.Identifier.TON(
|
||||
contractAddress = value.contractAddress,
|
||||
)
|
||||
is SdkNFTCollection.Identifier.Unknown -> error("unknown collection id")
|
||||
is SdkNFTCollection.Identifier.Unknown -> NFTCollection.Identifier.Unknown
|
||||
}
|
||||
|
||||
override fun convertBack(value: NFTCollection.Identifier): SdkNFTCollection.Identifier = when (value) {
|
||||
|
|
@ -22,5 +22,6 @@ class NFTSdkCollectionIdentifierConverter : TwoWayConverter<SdkNFTCollection.Ide
|
|||
is NFTCollection.Identifier.TON -> SdkNFTCollection.Identifier.TON(
|
||||
contractAddress = value.contractAddress,
|
||||
)
|
||||
is NFTCollection.Identifier.Unknown -> SdkNFTCollection.Identifier.Unknown
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.data.nft
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.blockchain.nft.models.NFTCollection
|
||||
import com.tangem.datasource.local.nft.NFTPersistenceStore
|
||||
import com.tangem.datasource.local.nft.NFTPersistenceStoreFactory
|
||||
import com.tangem.datasource.local.nft.NFTRuntimeStore
|
||||
|
|
@ -11,6 +10,7 @@ import com.tangem.datasource.local.nft.converter.NFTSdkAssetIdentifierConverter
|
|||
import com.tangem.datasource.local.nft.converter.NFTSdkCollectionConverter
|
||||
import com.tangem.datasource.local.nft.converter.NFTSdkCollectionIdentifierConverter
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.nft.models.NFTCollection
|
||||
import com.tangem.domain.nft.models.NFTCollections
|
||||
import com.tangem.domain.nft.models.NFTSalePrice
|
||||
import com.tangem.domain.nft.repository.NFTRepository
|
||||
|
|
@ -20,11 +20,8 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.joinAll
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import com.tangem.blockchain.nft.models.NFTCollection as SdkNFTCollection
|
||||
|
||||
|
|
@ -32,24 +29,20 @@ internal class DefaultNFTRepository @Inject constructor(
|
|||
private val nftPersistenceStoreFactory: NFTPersistenceStoreFactory,
|
||||
private val nftRuntimeStoreFactory: NFTRuntimeStoreFactory,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : NFTRepository {
|
||||
|
||||
private val scope = CoroutineScope(dispatchers.io + SupervisorJob())
|
||||
|
||||
private val jobs = mutableMapOf<Network, JobHolder>()
|
||||
|
||||
private val nftRuntimeStores = mutableMapOf<Network, NFTRuntimeStore>()
|
||||
private val nftPersistenceStores = mutableMapOf<Network, NFTPersistenceStore>()
|
||||
|
||||
private val nftSdkAssetIdentifierConverter = NFTSdkAssetIdentifierConverter()
|
||||
private val nftSdkCollectionIdentifierConverter = NFTSdkCollectionIdentifierConverter()
|
||||
private val nftSdkAssetConverter = NFTSdkAssetConverter(
|
||||
nftSdkAssetIdentifierConverter = nftSdkAssetIdentifierConverter,
|
||||
nftSdkCollectionIdentifierConverter = nftSdkCollectionIdentifierConverter,
|
||||
nftSdkAssetIdentifierConverter = NFTSdkAssetIdentifierConverter,
|
||||
nftSdkCollectionIdentifierConverter = NFTSdkCollectionIdentifierConverter,
|
||||
)
|
||||
private val collectionConverter = NFTSdkCollectionConverter(
|
||||
nftSdkCollectionIdentifierConverter = nftSdkCollectionIdentifierConverter,
|
||||
nftSdkCollectionIdentifierConverter = NFTSdkCollectionIdentifierConverter,
|
||||
nftSdkAssetConverter = nftSdkAssetConverter,
|
||||
)
|
||||
|
||||
|
|
@ -64,12 +57,11 @@ internal class DefaultNFTRepository @Inject constructor(
|
|||
refreshCollections(userWalletId, networks)
|
||||
}
|
||||
|
||||
override suspend fun refreshCollections(userWalletId: UserWalletId, networks: List<Network>) {
|
||||
override suspend fun refreshCollections(userWalletId: UserWalletId, networks: List<Network>) = coroutineScope {
|
||||
networks.map { network ->
|
||||
scope.launch {
|
||||
expireCollections(network)
|
||||
|
||||
launch(dispatchers.io) {
|
||||
Either.catch {
|
||||
expireCollections(network)
|
||||
walletManagersFacade.getNFTCollections(userWalletId, network)
|
||||
}.onLeft {
|
||||
saveFailedStateInRuntime(
|
||||
|
|
@ -115,9 +107,13 @@ internal class DefaultNFTRepository @Inject constructor(
|
|||
NFTCollections(
|
||||
network = network,
|
||||
content = NFTCollections.Content.Collections(
|
||||
collections = collections.map { collection ->
|
||||
collectionConverter.convert(network to collection)
|
||||
},
|
||||
collections = collections
|
||||
.map { collection ->
|
||||
collectionConverter.convert(network to collection)
|
||||
}
|
||||
.filter {
|
||||
it.id !is NFTCollection.Identifier.Unknown
|
||||
},
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
),
|
||||
|
|
@ -169,9 +165,13 @@ internal class DefaultNFTRepository @Inject constructor(
|
|||
NFTCollections(
|
||||
network = network,
|
||||
content = NFTCollections.Content.Collections(
|
||||
collections = it?.map { collection ->
|
||||
collectionConverter.convert(network to collection)
|
||||
},
|
||||
collections = it
|
||||
?.map { collection ->
|
||||
collectionConverter.convert(network to collection)
|
||||
}
|
||||
?.filter {
|
||||
it.id !is NFTCollection.Identifier.Unknown
|
||||
},
|
||||
source = StatusSource.CACHE,
|
||||
),
|
||||
)
|
||||
|
|
@ -184,7 +184,7 @@ internal class DefaultNFTRepository @Inject constructor(
|
|||
prices
|
||||
.mapKeys {
|
||||
val (assetId, _) = it
|
||||
nftSdkAssetIdentifierConverter.convert(assetId)
|
||||
NFTSdkAssetIdentifierConverter.convert(assetId)
|
||||
}
|
||||
.mapValues {
|
||||
val (assetId, price) = it
|
||||
|
|
@ -202,7 +202,7 @@ internal class DefaultNFTRepository @Inject constructor(
|
|||
getNFTPersistenceStore(network)
|
||||
.getCollectionsSync()
|
||||
.orEmpty()
|
||||
.associateBy(NFTCollection::identifier)
|
||||
.associateBy(SdkNFTCollection::identifier)
|
||||
|
||||
return this.map { updatedCollection ->
|
||||
if (!storedCollections.containsKey(updatedCollection.identifier)) {
|
||||
|
|
|
|||
|
|
@ -48,5 +48,7 @@ sealed class NFTAsset {
|
|||
) : Identifier()
|
||||
|
||||
data class TON(val tokenAddress: String) : Identifier()
|
||||
|
||||
data object Unknown : Identifier()
|
||||
}
|
||||
}
|
||||
|
|
@ -14,5 +14,6 @@ data class NFTCollection(
|
|||
sealed class Identifier {
|
||||
data class EVM(val tokenAddress: String) : Identifier()
|
||||
data class TON(val contractAddress: String?) : Identifier()
|
||||
data object Unknown : Identifier()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue