From 6a5a8300cf698ecb702ec8f739c685c536043bac Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 19 Feb 2025 16:23:03 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/di/domain/MarketsDomainModule.kt | 14 +++++++ .../java/com/tangem/utils/extensions/List.kt | 8 ++++ .../repository/DefaultCurrenciesRepository.kt | 16 +++++++- domain/markets/build.gradle.kts | 9 +++++ ...FilterAvailableNetworksForWalletUseCase.kt | 38 +++++++++++++++++++ ...AllWalletsCryptoCurrencyStatusesUseCase.kt | 4 +- .../tokens/repository/CurrenciesRepository.kt | 5 ++- .../repository/MockCurrenciesRepository.kt | 1 + .../impl/loader/PortfolioDataLoader.kt | 29 +++++++------- .../impl/model/MarketsPortfolioModel.kt | 10 ++++- 10 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 domain/markets/src/main/java/com/tangem/domain/markets/FilterAvailableNetworksForWalletUseCase.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/MarketsDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/MarketsDomainModule.kt index 8adbb68381..4498836964 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/MarketsDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/MarketsDomainModule.kt @@ -1,11 +1,13 @@ package com.tangem.tap.di.domain +import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.domain.card.repository.DerivationsRepository import com.tangem.domain.markets.* import com.tangem.domain.markets.repositories.MarketsTokenRepository import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.NetworksRepository import com.tangem.domain.tokens.repository.QuotesRepository +import com.tangem.domain.wallets.legacy.UserWalletsListManager import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -64,6 +66,18 @@ object MarketsDomainModule { ) } + @Provides + @Singleton + fun provideFilterNetworksUseCase( + userWalletsListManager: UserWalletsListManager, + excludedBlockchains: ExcludedBlockchains, + ): FilterAvailableNetworksForWalletUseCase { + return FilterAvailableNetworksForWalletUseCase( + userWalletsListManager = userWalletsListManager, + excludedBlockchains = excludedBlockchains, + ) + } + @Provides @Singleton fun provideGetTokenExchangesUseCase(marketsTokenRepository: MarketsTokenRepository): GetTokenExchangesUseCase { diff --git a/core/utils/src/main/java/com/tangem/utils/extensions/List.kt b/core/utils/src/main/java/com/tangem/utils/extensions/List.kt index 86bdfe2e6e..cad9f1fada 100644 --- a/core/utils/src/main/java/com/tangem/utils/extensions/List.kt +++ b/core/utils/src/main/java/com/tangem/utils/extensions/List.kt @@ -64,4 +64,12 @@ inline fun MutableList.addOrReplace(item: T, predicate: (T) -> Boolean) { if (!isReplaced) { add(item) } +} + +fun List.filterIf(condition: Boolean, predicate: (T) -> Boolean): List { + return if (condition) { + this.filter(predicate) + } else { + this + } } \ No newline at end of file diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt index b5aa2cd7fc..d6d0caaf7d 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt @@ -22,6 +22,8 @@ import com.tangem.datasource.local.preferences.utils.getObject import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull import com.tangem.datasource.local.preferences.utils.storeObject import com.tangem.datasource.local.userwallet.UserWalletsStore +import com.tangem.domain.common.extensions.canHandleBlockchain +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.core.error.DataError import com.tangem.domain.demo.DemoConfig import com.tangem.domain.tokens.model.CryptoCurrency @@ -33,6 +35,7 @@ import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.extensions.filterIf import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import timber.log.Timber @@ -47,7 +50,7 @@ internal class DefaultCurrenciesRepository( private val appPreferencesStore: AppPreferencesStore, private val expressServiceLoader: ExpressServiceLoader, private val dispatchers: CoroutineDispatcherProvider, - excludedBlockchains: ExcludedBlockchains, + private val excludedBlockchains: ExcludedBlockchains, ) : CurrenciesRepository { private val demoConfig = DemoConfig() @@ -486,12 +489,14 @@ internal class DefaultCurrenciesRepository( @OptIn(ExperimentalCoroutinesApi::class) override fun getAllWalletsCryptoCurrencies( currencyRawId: CryptoCurrency.RawID, + needFilterByAvailable: Boolean, ): Flow>> { return userWalletsStore.userWallets.flatMapLatest { userWallets -> userWallets.forEach { fetchTokensIfCacheExpired(userWallet = it, refresh = false) } val userWalletsWithCurrencies = userWallets .filterNot(UserWallet::isLocked) + .filterIf(needFilterByAvailable) { it.filterWalletByAvailableBlockchain(currencyRawId) } .map { userWallet -> if (userWallet.isMultiCurrency) { getSavedUserTokensResponse(userWallet.walletId).map { storedTokens -> @@ -525,6 +530,15 @@ internal class DefaultCurrenciesRepository( } } + private fun UserWallet.filterWalletByAvailableBlockchain(currencyRawId: CryptoCurrency.RawID): Boolean { + val blockchain = Blockchain.fromNetworkId(currencyRawId.value) ?: return true + return this.scanResponse.card.canHandleBlockchain( + blockchain = blockchain, + cardTypesResolver = this.cardTypesResolver, + excludedBlockchains = excludedBlockchains, + ) + } + override fun isNetworkFeeZero(userWalletId: UserWalletId, network: Network): Boolean { val blockchain = Blockchain.fromNetworkId(network.backendId) return blockchain?.isNetworkFeeZero() ?: false diff --git a/domain/markets/build.gradle.kts b/domain/markets/build.gradle.kts index 430f975fa5..b3d59216c4 100644 --- a/domain/markets/build.gradle.kts +++ b/domain/markets/build.gradle.kts @@ -17,12 +17,21 @@ dependencies { api(projects.domain.core) api(projects.domain.markets.models) api(projects.domain.wallets.models) + api(projects.domain.models) + api(projects.domain.legacy) + api(projects.domain.wallets) implementation(projects.domain.tokens.models) implementation(projects.domain.tokens) api(projects.core.pagination) + /* Libs */ + api(projects.libs.blockchainSdk) + + /* SDK */ + implementation(tangemDeps.blockchain) + /* Utils */ implementation(deps.kotlin.serialization) implementation(projects.core.utils) diff --git a/domain/markets/src/main/java/com/tangem/domain/markets/FilterAvailableNetworksForWalletUseCase.kt b/domain/markets/src/main/java/com/tangem/domain/markets/FilterAvailableNetworksForWalletUseCase.kt new file mode 100644 index 0000000000..1b645a2d53 --- /dev/null +++ b/domain/markets/src/main/java/com/tangem/domain/markets/FilterAvailableNetworksForWalletUseCase.kt @@ -0,0 +1,38 @@ +package com.tangem.domain.markets + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchainsdk.utils.ExcludedBlockchains +import com.tangem.blockchainsdk.utils.fromNetworkId +import com.tangem.domain.common.extensions.supportedBlockchains +import com.tangem.domain.common.util.cardTypesResolver +import com.tangem.domain.wallets.legacy.UserWalletsListManager +import com.tangem.domain.wallets.models.UserWalletId + +class FilterAvailableNetworksForWalletUseCase( + private val userWalletsListManager: UserWalletsListManager, + private val excludedBlockchains: ExcludedBlockchains, +) { + + /** + * Filters [networks] list according supported blockchains for this card + * If [userWalletId] not found then returns the same list + */ + operator fun invoke( + userWalletId: UserWalletId, + networks: Set, + ): Set { + val userWallet = userWalletsListManager.userWalletsSync.firstOrNull { + it.walletId == userWalletId + } ?: return networks.toSet() + + val supportedBlockchains = userWallet.scanResponse.card.supportedBlockchains( + cardTypesResolver = userWallet.scanResponse.cardTypesResolver, + excludedBlockchains = excludedBlockchains, + ) + + return networks.filter { + val blockchain = Blockchain.fromNetworkId(it.networkId) + supportedBlockchains.contains(blockchain) + }.toSet() + } +} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetAllWalletsCryptoCurrencyStatusesUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetAllWalletsCryptoCurrencyStatusesUseCase.kt index 0dfb01856e..5a77f4953e 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetAllWalletsCryptoCurrencyStatusesUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetAllWalletsCryptoCurrencyStatusesUseCase.kt @@ -42,8 +42,9 @@ class GetAllWalletsCryptoCurrencyStatusesUseCase( @OptIn(ExperimentalCoroutinesApi::class) operator fun invoke( currencyRawId: CryptoCurrency.RawID, + needFilterByAvailable: Boolean = false, ): Flow>>> { - return currenciesRepository.getAllWalletsCryptoCurrencies(currencyRawId) + return currenciesRepository.getAllWalletsCryptoCurrencies(currencyRawId, needFilterByAvailable) .flatMapLatest { userWalletsWithCurrencies: Map> -> val walletStatusFlows = userWalletsWithCurrencies.map { (userWallet, cryptoCurrencies) -> val operations = CurrenciesStatusesOperations( @@ -64,6 +65,7 @@ class GetAllWalletsCryptoCurrencyStatusesUseCase( } combine(walletStatusFlows) { it.toMap() } + .onEmpty { emit(emptyMap()) } } .flowOn(dispatchers.io) } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt index 04fa86295f..d48d0a63f4 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrenciesRepository.kt @@ -248,7 +248,10 @@ interface CurrenciesRepository { ): CryptoCurrency.Token /** Get crypto currencies by [currencyRawId] from all user wallets */ - fun getAllWalletsCryptoCurrencies(currencyRawId: CryptoCurrency.RawID): Flow>> + fun getAllWalletsCryptoCurrencies( + currencyRawId: CryptoCurrency.RawID, + needFilterByAvailable: Boolean, + ): Flow>> fun isNetworkFeeZero(userWalletId: UserWalletId, network: Network): Boolean } \ No newline at end of file diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt index a94add56b4..233a8a3796 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/repository/MockCurrenciesRepository.kt @@ -155,6 +155,7 @@ internal class MockCurrenciesRepository( override fun getAllWalletsCryptoCurrencies( currencyRawId: CryptoCurrency.RawID, + needFilterByAvailable: Boolean, ): Flow>> { return emptyFlow() } diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/loader/PortfolioDataLoader.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/loader/PortfolioDataLoader.kt index f4e8c0aad9..d48bdba0c6 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/loader/PortfolioDataLoader.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/loader/PortfolioDataLoader.kt @@ -65,7 +65,7 @@ internal class PortfolioDataLoader @Inject constructor( private fun getAllWalletsCryptoCurrenciesData( currencyRawId: CryptoCurrency.RawID, ): Flow>> { - return getAllWalletsCryptoCurrencyStatusesUseCase(currencyRawId) + return getAllWalletsCryptoCurrencyStatusesUseCase(currencyRawId, true) .distinctUntilChanged() .map { walletsWithMaybeStatuses -> walletsWithMaybeStatuses.mapValues { entry -> @@ -94,20 +94,21 @@ internal class PortfolioDataLoader @Inject constructor( } } } + }.onEmpty { + emit( + walletsWithStatuses.mapValues { (wallet, statuses) -> + statuses.map { + PortfolioData.CryptoCurrencyData( + userWallet = wallet, + status = it, + actions = emptyList(), + ) + } + }, + ) } - .onEmpty { - emit( - walletsWithStatuses.mapValues { (wallet, statuses) -> - statuses.map { - PortfolioData.CryptoCurrencyData( - userWallet = wallet, - status = it, - actions = emptyList(), - ) - } - }, - ) - } + }.onEmpty { + emit(emptyMap()) } .distinctUntilChanged() } diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt index 68b432f633..b28d495ac2 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/MarketsPortfolioModel.kt @@ -18,6 +18,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.card.HasMissedDerivationsUseCase import com.tangem.domain.managetokens.CheckCurrencyUnsupportedUseCase import com.tangem.domain.managetokens.model.CurrencyUnsupportedState +import com.tangem.domain.markets.FilterAvailableNetworksForWalletUseCase import com.tangem.domain.markets.SaveMarketTokensUseCase import com.tangem.domain.markets.TokenMarketInfo import com.tangem.domain.wallets.models.UserWalletId @@ -49,6 +50,7 @@ internal class MarketsPortfolioModel @Inject constructor( private val portfolioDataLoader: PortfolioDataLoader, private val hasMissedDerivationsUseCase: HasMissedDerivationsUseCase, private val saveMarketTokensUseCase: SaveMarketTokensUseCase, + private val filterAvailableNetworks: FilterAvailableNetworksForWalletUseCase, private val addToPortfolioManager: AddToPortfolioManager, private val analyticsEventHandler: AnalyticsEventHandler, ) : Model() { @@ -175,10 +177,16 @@ internal class MarketsPortfolioModel @Inject constructor( flow2 = selectedMultiWalletIdFlow, flow3 = addToPortfolioManager.getAddToPortfolioData(), transform = { portfolioBSVisibilityModel, selectedWalletId, addToPortfolioData -> + val filteredNetworks = selectedWalletId?.let { + filterAvailableNetworks(selectedWalletId, addToPortfolioData.availableNetworks ?: emptySet()) + } ?: emptySet() + PortfolioUIData( portfolioBSVisibilityModel = portfolioBSVisibilityModel, selectedWalletId = selectedWalletId, - addToPortfolioData = addToPortfolioData, + addToPortfolioData = addToPortfolioData.copy( + availableNetworks = filteredNetworks, + ), hasMissedDerivations = hasMissedDerivations(selectedWalletId, addToPortfolioData), ) },