Updated on 2026-08-14

This commit is contained in:
Tangem 2025-05-28 23:16:24 +03:00
parent b43686177a
commit 083fececa2
7 changed files with 27 additions and 39 deletions

View file

@ -22,8 +22,6 @@ 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
@ -35,7 +33,6 @@ 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
@ -50,7 +47,7 @@ internal class DefaultCurrenciesRepository(
private val appPreferencesStore: AppPreferencesStore,
private val expressServiceLoader: ExpressServiceLoader,
private val dispatchers: CoroutineDispatcherProvider,
private val excludedBlockchains: ExcludedBlockchains,
excludedBlockchains: ExcludedBlockchains,
) : CurrenciesRepository {
private val demoConfig = DemoConfig()
@ -490,14 +487,12 @@ internal class DefaultCurrenciesRepository(
@OptIn(ExperimentalCoroutinesApi::class)
override fun getAllWalletsCryptoCurrencies(
currencyRawId: CryptoCurrency.RawID,
needFilterByAvailable: Boolean,
): Flow<Map<UserWallet, List<CryptoCurrency>>> {
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 ->
@ -522,8 +517,7 @@ internal class DefaultCurrenciesRepository(
emit(currencies)
}
}
.map { userWallet to it }
}.map { userWallet to it }
}
combine(userWalletsWithCurrencies) { it.toMap() }
@ -531,15 +525,6 @@ 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

View file

@ -35,9 +35,8 @@ class GetAllWalletsCryptoCurrencyStatusesUseCase(
@OptIn(ExperimentalCoroutinesApi::class)
operator fun invoke(
currencyRawId: CryptoCurrency.RawID,
needFilterByAvailable: Boolean = false,
): Flow<Map<UserWallet, List<Either<CurrencyStatusError, CryptoCurrencyStatus>>>> {
return currenciesRepository.getAllWalletsCryptoCurrencies(currencyRawId, needFilterByAvailable)
return currenciesRepository.getAllWalletsCryptoCurrencies(currencyRawId)
.flatMapLatest { userWalletsWithCurrencies: Map<UserWallet, List<CryptoCurrency>> ->
val walletStatusFlows = userWalletsWithCurrencies.map { (userWallet, cryptoCurrencies) ->
val currencyStatusFlows = cryptoCurrencies.map { cryptoCurrency ->

View file

@ -248,10 +248,7 @@ interface CurrenciesRepository {
): CryptoCurrency.Token
/** Get crypto currencies by [currencyRawId] from all user wallets */
fun getAllWalletsCryptoCurrencies(
currencyRawId: CryptoCurrency.RawID,
needFilterByAvailable: Boolean,
): Flow<Map<UserWallet, List<CryptoCurrency>>>
fun getAllWalletsCryptoCurrencies(currencyRawId: CryptoCurrency.RawID): Flow<Map<UserWallet, List<CryptoCurrency>>>
fun isNetworkFeeZero(userWalletId: UserWalletId, network: Network): Boolean
}

View file

@ -155,7 +155,6 @@ internal class MockCurrenciesRepository(
override fun getAllWalletsCryptoCurrencies(
currencyRawId: CryptoCurrency.RawID,
needFilterByAvailable: Boolean,
): Flow<Map<UserWallet, List<CryptoCurrency>>> {
return emptyFlow()
}

View file

@ -5,6 +5,8 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.markets.FilterAvailableNetworksForWalletUseCase
import com.tangem.domain.markets.TokenMarketInfo
import com.tangem.domain.tokens.GetAllWalletsCryptoCurrencyStatusesUseCase
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase
@ -29,6 +31,7 @@ import javax.inject.Inject
[REDACTED_AUTHOR]
*/
internal class PortfolioDataLoader @Inject constructor(
private val filterAvailableNetworksForWallet: FilterAvailableNetworksForWalletUseCase,
private val getAllWalletsCryptoCurrencyStatusesUseCase: GetAllWalletsCryptoCurrencyStatusesUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
@ -38,14 +41,18 @@ internal class PortfolioDataLoader @Inject constructor(
/** Load data by [currencyRawId] */
@OptIn(ExperimentalCoroutinesApi::class)
fun load(currencyRawId: CryptoCurrency.RawID): Flow<PortfolioData> {
fun load(
currencyRawId: CryptoCurrency.RawID,
availableNetworksFlow: Flow<Set<TokenMarketInfo.Network>?>,
): Flow<PortfolioData> {
return combine(
flow = getAllWalletsCryptoCurrenciesData(currencyRawId = currencyRawId),
flow2 = getSelectedAppCurrencyFlow(),
flow3 = getBalanceHidingSettingsFlow(),
) { walletsWithCurrencies, appCurrency, isBalanceHidden ->
flow4 = availableNetworksFlow.filterNotNull().distinctUntilChanged(),
) { walletsWithCurrencies, appCurrency, isBalanceHidden, availableNetworks ->
PortfolioData(
walletsWithCurrencies = walletsWithCurrencies,
walletsWithCurrencies = walletsWithCurrencies.filterWalletsByAvailableNetworks(availableNetworks),
appCurrency = appCurrency,
isBalanceHidden = isBalanceHidden,
walletsWithBalance = emptyMap(),
@ -65,7 +72,7 @@ internal class PortfolioDataLoader @Inject constructor(
private fun getAllWalletsCryptoCurrenciesData(
currencyRawId: CryptoCurrency.RawID,
): Flow<Map<UserWallet, List<PortfolioData.CryptoCurrencyData>>> {
return getAllWalletsCryptoCurrencyStatusesUseCase(currencyRawId, true)
return getAllWalletsCryptoCurrencyStatusesUseCase(currencyRawId)
.distinctUntilChanged()
.map { walletsWithMaybeStatuses ->
walletsWithMaybeStatuses.mapValues { entry ->
@ -145,4 +152,13 @@ internal class PortfolioDataLoader @Inject constructor(
.distinctUntilChanged()
.onEmpty { ids.associateWith { Lce.Loading<TotalFiatBalance>(partialContent = null) } }
}
private fun Map<UserWallet, List<PortfolioData.CryptoCurrencyData>>.filterWalletsByAvailableNetworks(
availableNetworks: Set<TokenMarketInfo.Network>,
): Map<UserWallet, List<PortfolioData.CryptoCurrencyData>> {
return filter {
val networksSupportedByWallet = filterAvailableNetworksForWallet(it.key.walletId, availableNetworks)
networksSupportedByWallet.isNotEmpty()
}
}
}

View file

@ -18,7 +18,7 @@ internal typealias WalletsWithNetworks = Map<UserWalletId, Set<TokenMarketInfo.N
*/
internal class AddToPortfolioManager @Inject constructor() {
private val availableNetworks = MutableStateFlow<Set<TokenMarketInfo.Network>?>(value = null)
val availableNetworks = MutableStateFlow<Set<TokenMarketInfo.Network>?>(value = null)
private val addedNetworks = MutableStateFlow<WalletsWithNetworks>(value = emptyMap())
private val removedNetworks = MutableStateFlow<WalletsWithNetworks>(value = emptyMap())

View file

@ -18,7 +18,6 @@ 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
@ -50,7 +49,6 @@ 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() {
@ -163,7 +161,7 @@ internal class MarketsPortfolioModel @Inject constructor(
private fun subscribeOnStateUpdates() {
combine(
flow = portfolioDataLoader.load(params.token.id),
flow = portfolioDataLoader.load(params.token.id, addToPortfolioManager.availableNetworks),
flow2 = getPortfolioUIDataFlow(),
transform = factory::create,
)
@ -177,16 +175,10 @@ 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.copy(
availableNetworks = filteredNetworks,
),
addToPortfolioData = addToPortfolioData,
hasMissedDerivations = hasMissedDerivations(selectedWalletId, addToPortfolioData),
)
},