diff --git a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt index 56bf1c96ba..8e58e90e09 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt @@ -20,7 +20,6 @@ import com.tangem.domain.staking.single.SingleStakingBalanceFetcher import com.tangem.domain.staking.single.SingleStakingBalanceSupplier import com.tangem.domain.tokens.* import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations -import com.tangem.domain.tokens.operations.CachedCurrenciesStatusesOperations import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrencyChecksRepository import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository @@ -54,18 +53,6 @@ internal object TokensDomainModule { return DefaultTokensFeatureToggles(featureTogglesManager = featureTogglesManager) } - @Provides - @Singleton - fun provideGetTokenListUseCase( - currenciesRepository: CurrenciesRepository, - currenciesStatusesOperations: BaseCurrencyStatusOperations, - ): GetTokenListUseCase { - return GetTokenListUseCase( - currenciesRepository = currenciesRepository, - currenciesStatusesOperations = currenciesStatusesOperations, - ) - } - @Provides @Singleton fun provideGetCurrencyUseCase( @@ -78,20 +65,6 @@ internal object TokensDomainModule { ) } - @Provides - @Singleton - fun provideGetAllWalletsCryptoCurrencyStatusesUseCase( - currenciesRepository: CurrenciesRepository, - currencyStatusOperations: BaseCurrencyStatusOperations, - dispatchers: CoroutineDispatcherProvider, - ): GetAllWalletsCryptoCurrencyStatusesUseCase { - return GetAllWalletsCryptoCurrencyStatusesUseCase( - currenciesRepository = currenciesRepository, - currencyStatusOperations = currencyStatusOperations, - dispatchers = dispatchers, - ) - } - @Provides @Singleton fun provideGetCurrencyWarningsUseCase( @@ -245,14 +218,6 @@ internal object TokensDomainModule { ) } - @Provides - @Singleton - fun provideGetWalletTotalBalanceUseCase( - currenciesStatusesOperations: BaseCurrencyStatusOperations, - ): GetWalletTotalBalanceUseCase { - return GetWalletTotalBalanceUseCase(currenciesStatusesOperations) - } - @Provides @Singleton fun provideRefreshMultiCurrencyWalletQuotesUseCase( @@ -287,7 +252,7 @@ internal object TokensDomainModule { multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier, stakingIdFactory: StakingIdFactory, ): BaseCurrencyStatusOperations { - return CachedCurrenciesStatusesOperations( + return BaseCurrencyStatusOperations( currenciesRepository = currenciesRepository, quotesRepository = quotesRepository, singleNetworkStatusSupplier = singleNetworkStatusSupplier, @@ -300,12 +265,6 @@ internal object TokensDomainModule { ) } - @Provides - @Singleton - fun provideGetCryptoCurrenciesUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrenciesUseCase { - return GetCryptoCurrenciesUseCase(currenciesRepository) - } - @Provides @Singleton fun provideWalletBalanceFetcher( diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/di/TokensDataModule.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/di/TokensDataModule.kt index 26626eb998..2f577c7b2b 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/di/TokensDataModule.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/di/TokensDataModule.kt @@ -4,7 +4,6 @@ import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.data.common.cache.CacheRegistry import com.tangem.data.common.currency.CardCryptoCurrencyFactory import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory -import com.tangem.data.common.currency.UserTokensSaver import com.tangem.data.tokens.repository.DefaultCurrenciesRepository import com.tangem.data.tokens.repository.DefaultCurrencyChecksRepository import com.tangem.data.tokens.repository.DefaultTokenReceiveWarningsViewedRepository @@ -44,7 +43,6 @@ internal object TokensDataModule { expressServiceFetcher: ExpressServiceFetcher, excludedBlockchains: ExcludedBlockchains, cardCryptoCurrencyFactory: CardCryptoCurrencyFactory, - tokensSaver: UserTokensSaver, responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory, multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier, ): CurrenciesRepository { @@ -58,7 +56,6 @@ internal object TokensDataModule { dispatchers = dispatchers, excludedBlockchains = excludedBlockchains, cardCryptoCurrencyFactory = cardCryptoCurrencyFactory, - userTokensSaver = tokensSaver, responseCryptoCurrenciesFactory = responseCryptoCurrenciesFactory, multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier, ) 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 16b2415e7e..952b4aa680 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 @@ -2,15 +2,14 @@ package com.tangem.data.tokens.repository import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.TransactionStatus -import com.tangem.blockchainsdk.compatibility.getL2CompatibilityTokenComparison import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.blockchainsdk.utils.fromNetworkId import com.tangem.blockchainsdk.utils.toBlockchain -import com.tangem.data.common.api.safeApiCall import com.tangem.data.common.cache.CacheRegistry -import com.tangem.data.common.currency.* -import com.tangem.data.tokens.utils.CustomTokensMerger -import com.tangem.datasource.api.common.response.ApiResponseError +import com.tangem.data.common.currency.CardCryptoCurrencyFactory +import com.tangem.data.common.currency.CryptoCurrencyFactory +import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory +import com.tangem.data.common.currency.getTokenId import com.tangem.datasource.api.common.response.getOrThrow import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.api.tangemTech.models.UserTokensResponse @@ -19,24 +18,28 @@ import com.tangem.domain.card.CardTypesResolver import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.common.wallets.getSyncStrict -import com.tangem.domain.common.wallets.loadAndGet import com.tangem.domain.core.error.DataError -import com.tangem.domain.demo.models.DemoConfig import com.tangem.domain.express.ExpressServiceFetcher import com.tangem.domain.express.models.ExpressAsset import com.tangem.domain.models.account.DerivationIndex import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.network.Network -import com.tangem.domain.models.wallet.* +import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.models.wallet.isMultiCurrency +import com.tangem.domain.models.wallet.requireColdWallet import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesProducer import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier import com.tangem.domain.tokens.model.FeePaidCurrency import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.* +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import kotlinx.coroutines.plus +import kotlinx.coroutines.withContext import timber.log.Timber import com.tangem.blockchain.common.FeePaidCurrency as FeePaidSdkCurrency @@ -49,21 +52,13 @@ internal class DefaultCurrenciesRepository( private val expressServiceFetcher: ExpressServiceFetcher, private val dispatchers: CoroutineDispatcherProvider, private val cardCryptoCurrencyFactory: CardCryptoCurrencyFactory, - private val userTokensSaver: UserTokensSaver, private val userTokensResponseStore: UserTokensResponseStore, private val responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory, private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier, excludedBlockchains: ExcludedBlockchains, ) : CurrenciesRepository { - private val demoConfig = DemoConfig private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains) - private val userTokensResponseFactory = UserTokensResponseFactory() - private val customTokensMerger = CustomTokensMerger( - tangemTechApi = tangemTechApi, - dispatchers = dispatchers, - userTokensSaver = userTokensSaver, - ) override fun getWalletCurrenciesUpdates(userWalletId: UserWalletId): Flow> { return channelFlow { @@ -159,29 +154,6 @@ internal class DefaultCurrenciesRepository( } } - override suspend fun getMultiCurrencyWalletCurrenciesSync( - userWalletId: UserWalletId, - refresh: Boolean, - ): List = withContext(dispatchers.io) { - val userWallet = userWalletsListRepository.getSyncStrict(userWalletId) - ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = true) - - fetchTokensIfCacheExpired(userWallet, refresh) - - val storedTokens = requireNotNull( - value = getSavedUserTokensResponseSync(key = userWallet.walletId), - lazyMessage = { - "Unable to find tokens response for user wallet with provided ID: $userWalletId" - }, - ) - - responseCryptoCurrenciesFactory.createCurrencies( - response = storedTokens, - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } - override suspend fun getNetworkCoin( userWalletId: UserWalletId, networkId: Network.ID, @@ -199,38 +171,6 @@ internal class DefaultCurrenciesRepository( ?: error("Unable to find coin for network ID: $networkId") } - override fun isTokensGrouped(userWalletId: UserWalletId): Flow { - return channelFlow { - val userWallet = userWalletsListRepository.getSyncStrict(userWalletId) - - if (userWallet.isMultiCurrency) { - getSavedUserTokensResponse(userWalletId) - .map { response -> response.group == UserTokensResponse.GroupType.NETWORK } - .distinctUntilChanged() - .onEach { isGrouped -> send(isGrouped) } - .launchIn(scope = this + dispatchers.io) - } else { - send(element = false) - } - } - } - - override fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow { - return channelFlow { - val userWallet = userWalletsListRepository.getSyncStrict(userWalletId) - - if (userWallet.isMultiCurrency) { - getSavedUserTokensResponse(userWalletId) - .map { response -> response.sort == UserTokensResponse.SortType.BALANCE } - .distinctUntilChanged() - .onEach { isSorted -> send(isSorted) } - .launchIn(scope = this + dispatchers.io) - } else { - send(element = false) - } - } - } - override suspend fun isSendBlockedByPendingTransactions( userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus, @@ -332,67 +272,6 @@ internal class DefaultCurrenciesRepository( ) ?: error("Unable to create token") } - @OptIn(ExperimentalCoroutinesApi::class) - override fun getAllWalletsCryptoCurrencies( - currencyRawId: CryptoCurrency.RawID, - ): Flow>> { - return userWalletsListRepository.loadAndGet().flatMapLatest { userWallets -> - - userWallets.filter { it.isMultiCurrency } - .forEach { fetchTokensIfCacheExpired(userWallet = it, refresh = false) } - - val userWalletsWithCurrencies = userWallets - .filterNot(UserWallet::isLocked) - .map { userWallet -> - getCurrenciesForWallet(userWallet, currencyRawId).map { userWallet to it } - } - - combine(userWalletsWithCurrencies) { it.toMap() } - .onEmpty { emit(value = emptyMap()) } - } - } - - @Suppress("SuspendFunWithFlowReturnType") - private suspend fun getCurrenciesForWallet( - userWallet: UserWallet, - currencyRawId: CryptoCurrency.RawID, - ): Flow> { - return when { - userWallet.isMultiCurrency -> { - getSavedUserTokensResponse(userWallet.walletId).map { storedTokens -> - val filterResponse = storedTokens.tokens.filter { - getL2CompatibilityTokenComparison(it, currencyRawId.value) - } - - responseCryptoCurrenciesFactory.createCurrencies( - response = storedTokens.copy(tokens = filterResponse), - userWallet = userWallet, - accountIndex = DerivationIndex.Main, - ) - } - } - - else -> { - val currencies = - if (userWallet.requireColdWallet().scanResponse.cardTypesResolver.isSingleWalletWithToken()) { - getSingleCurrencyWalletWithCardCurrencies(userWallet.walletId) - } else { - val currency = - getSingleCurrencyWalletPrimaryCurrency(userWalletId = userWallet.walletId) - - if (currency.id.rawCurrencyId == currencyRawId) { - listOf(currency) - } else { - emptyList() - } - } - flow { - emit(currencies) - } - } - } - } - override fun isNetworkFeeZero(userWalletId: UserWalletId, network: Network): Boolean { val blockchain = Blockchain.fromNetworkId(network.backendId) return blockchain?.isNetworkFeeZero() == true @@ -412,53 +291,6 @@ internal class DefaultCurrenciesRepository( } } - private suspend fun fetchTokensIfCacheExpired(userWallet: UserWallet, refresh: Boolean) { - cacheRegistry.invokeOnExpire( - key = getTokensCacheKey(userWallet.walletId), - skipCache = refresh, - block = { fetchTokens(userWallet) }, - ) - } - - private suspend fun fetchTokens(userWallet: UserWallet) { - val userWalletId = userWallet.walletId - - val response = if (userWallet is UserWallet.Cold && checkIsEmptyDemoWallet(userWallet)) { - createDefaultUserTokensResponse(userWallet) - } else { - safeApiCall({ tangemTechApi.getUserTokens(userWalletId.stringValue).bind() }) { - handleFetchTokensError(userWallet, it) - } - } - - val compatibleUserTokensResponse = response - .let { it.copy(tokens = it.tokens.distinct()) } - .let { customTokensMerger.mergeIfPresented(userWalletId, it) } - - userTokensSaver.store(userWalletId, compatibleUserTokensResponse) - - fetchExpressAssetsByNetworkIds(userWallet, compatibleUserTokensResponse) - } - - private suspend fun checkIsEmptyDemoWallet(userWallet: UserWallet.Cold): Boolean { - val response = getSavedUserTokensResponseSync(key = userWallet.walletId) - - return demoConfig.isDemoCardId(userWallet.cardId) && response == null - } - - private suspend fun fetchExpressAssetsByNetworkIds(userWallet: UserWallet, userTokens: UserTokensResponse) { - val tokens = userTokens.tokens.mapTo(hashSetOf()) { token -> - ExpressAsset.ID( - networkId = token.networkId, - contractAddress = token.contractAddress, - ) - } - - coroutineScope { - launch { expressServiceFetcher.fetch(userWallet, tokens) } - } - } - private suspend fun fetchExpressAssetsByNetworkIds( userWallet: UserWallet, cryptoCurrencies: List, @@ -484,35 +316,6 @@ internal class DefaultCurrenciesRepository( private fun getAssetsCacheKey(userWalletId: UserWalletId): String = "assets_cache_key_${userWalletId.stringValue}" - private suspend fun handleFetchTokensError(userWallet: UserWallet, e: ApiResponseError): UserTokensResponse { - val userWalletId = userWallet.walletId - val response = userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId) - ?: createDefaultUserTokensResponse(userWallet = userWallet) - - if (e is ApiResponseError.HttpException && e.code == ApiResponseError.HttpException.Code.NOT_FOUND) { - Timber.w( - e, - "Requested currencies could not be found in the remote store for: $userWalletId", - ) - - userTokensSaver.push(userWalletId, response) - } else { - cacheRegistry.invalidate(getTokensCacheKey(userWalletId)) - } - - return response - } - - private fun createDefaultUserTokensResponse(userWallet: UserWallet) = - userTokensResponseFactory.createUserTokensResponse( - currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet( - userWallet = userWallet, - ), - isGroupedByNetwork = false, - isSortedByBalance = false, - accountId = null, - ) - private fun ensureIsCorrectUserWallet(userWallet: UserWallet, isMultiCurrencyWalletExpected: Boolean) { val userWalletId = userWallet.walletId @@ -536,13 +339,7 @@ internal class DefaultCurrenciesRepository( } } - private fun getTokensCacheKey(userWalletId: UserWalletId): String = "tokens_cache_key_${userWalletId.stringValue}" - private fun getSavedUserTokensResponse(key: UserWalletId): Flow { return userTokensResponseStore.get(userWalletId = key).filterNotNull() } - - private suspend fun getSavedUserTokensResponseSync(key: UserWalletId): UserTokensResponse? { - return userTokensResponseStore.getSyncOrNull(userWalletId = key) - } } \ 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 deleted file mode 100644 index 9bba447d40..0000000000 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetAllWalletsCryptoCurrencyStatusesUseCase.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.tangem.domain.tokens - -import arrow.core.Either -import com.tangem.domain.models.currency.CryptoCurrency -import com.tangem.domain.models.currency.CryptoCurrencyStatus -import com.tangem.domain.models.wallet.UserWallet -import com.tangem.domain.tokens.error.CurrencyStatusError -import com.tangem.domain.tokens.error.mapper.mapToCurrencyError -import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations -import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations -import com.tangem.domain.tokens.repository.CurrenciesRepository -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.* - -/** - * Get crypto currency statuses by raw ID for all wallets - * - * @property currenciesRepository currencies repository - * @property dispatchers dispatchers - * -[REDACTED_AUTHOR] - */ -class GetAllWalletsCryptoCurrencyStatusesUseCase( - private val currenciesRepository: CurrenciesRepository, - private val dispatchers: CoroutineDispatcherProvider, - private val currencyStatusOperations: BaseCurrencyStatusOperations, -) { - - /** - * Get crypto currency statuses by [currencyRawId] for all wallets - * - * @param currencyRawId currency raw ID - */ - @OptIn(ExperimentalCoroutinesApi::class) - operator fun invoke( - currencyRawId: CryptoCurrency.RawID, - ): Flow>>> { - return currenciesRepository.getAllWalletsCryptoCurrencies(currencyRawId) - .flatMapLatest { userWalletsWithCurrencies: Map> -> - val walletStatusFlows = userWalletsWithCurrencies.map { (userWallet, cryptoCurrencies) -> - val currencyStatusFlows = cryptoCurrencies.map { cryptoCurrency -> - currencyStatusOperations.getCurrencyStatusFlow(userWallet.walletId, cryptoCurrency) - .map { it.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError) } - } - - combine(currencyStatusFlows) { statuses -> userWallet to statuses.toList() } - .onEmpty { emit(userWallet to emptyList()) } - } - - combine(walletStatusFlows) { it.toMap() } - .onEmpty { emit(emptyMap()) } - } - .flowOn(dispatchers.io) - } -} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrenciesUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrenciesUseCase.kt deleted file mode 100644 index 839334727f..0000000000 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrenciesUseCase.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.tangem.domain.tokens - -import arrow.core.Either -import com.tangem.domain.models.currency.CryptoCurrency -import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.tokens.error.CurrencyStatusError -import com.tangem.domain.tokens.repository.CurrenciesRepository - -@Deprecated("Use MultiWalletCryptoCurrenciesSupplier") -class GetCryptoCurrenciesUseCase( - private val currenciesRepository: CurrenciesRepository, -) { - - /** - * Retrieves the list of cryptocurrencies within a multi-currency wallet. - * - * @param userWalletId The unique identifier of the user wallet. - * - * @return An [Either] representing success (Right) or an error (Left) in fetching the status. - */ - suspend operator fun invoke(userWalletId: UserWalletId): Either> { - return Either.catch { - currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId) - }.mapLeft(CurrencyStatusError::DataError) - } -} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetTokenListUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetTokenListUseCase.kt deleted file mode 100644 index 042f4d257f..0000000000 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetTokenListUseCase.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.tangem.domain.tokens - -import com.tangem.domain.core.lce.LceFlow -import com.tangem.domain.core.utils.lceError -import com.tangem.domain.core.utils.lceLoading -import com.tangem.domain.core.utils.toLce -import com.tangem.domain.models.currency.CryptoCurrencyStatus -import com.tangem.domain.models.tokenlist.TokenList -import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.tokens.error.TokenListError -import com.tangem.domain.tokens.error.mapper.mapToTokenListError -import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations -import com.tangem.domain.tokens.operations.TokenListOperations -import com.tangem.domain.tokens.repository.CurrenciesRepository -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.emitAll -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.transformLatest - -class GetTokenListUseCase( - private val currenciesRepository: CurrenciesRepository, - private val currenciesStatusesOperations: BaseCurrencyStatusOperations, -) { - - @OptIn(ExperimentalCoroutinesApi::class) - fun launch(userWalletId: UserWalletId): LceFlow { - return currenciesStatusesOperations.getCurrenciesStatuses(userWalletId) - .transformLatest { maybeCurrencies -> - maybeCurrencies.fold( - ifLoading = { maybeContent -> - if (maybeContent != null) { - emitAll(createTokenListLce(userWalletId, maybeContent, isCurrenciesLoading = true)) - } else { - emit(lceLoading()) - } - }, - ifContent = { content -> - emitAll(createTokenListLce(userWalletId, content, isCurrenciesLoading = false)) - }, - ifError = { error -> emit(error.lceError()) }, - ) - } - } - - private fun createTokenListLce( - userWalletId: UserWalletId, - currencies: List, - isCurrenciesLoading: Boolean, - ): LceFlow { - val operations = TokenListOperations( - userWalletId = userWalletId, - tokens = currencies, - currenciesRepository = currenciesRepository, - ) - - return operations.getTokenListFlow().map { maybeTokenList -> - maybeTokenList - .mapLeft(TokenListOperations.Error::mapToTokenListError) - .toLce(isCurrenciesLoading) - } - } -} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt deleted file mode 100644 index 11760b5e2f..0000000000 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.tangem.domain.tokens - -import arrow.atomic.update -import arrow.core.raise.ensureNotNull -import arrow.core.toNonEmptyListOrNull -import com.tangem.domain.core.lce.Lce -import com.tangem.domain.core.lce.LceFlow -import com.tangem.domain.core.lce.lce -import com.tangem.domain.core.utils.lceContent -import com.tangem.domain.core.utils.lceLoading -import com.tangem.domain.models.TotalFiatBalance -import com.tangem.domain.models.currency.CryptoCurrencyStatus -import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.tokens.error.TokenListError -import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations -import com.tangem.domain.tokens.operations.TotalFiatBalanceCalculator -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.* -import timber.log.Timber -import java.util.concurrent.ConcurrentHashMap - -class GetWalletTotalBalanceUseCase( - private val currenciesStatusesOperations: BaseCurrencyStatusOperations, -) { - - private val walletBalanceCache = ConcurrentHashMap() - - operator fun invoke( - userWalletsIds: Collection, - ): LceFlow> { - val flows = userWalletsIds.distinct() - .map { userWalletId -> - invoke(userWalletId).map { maybeBalance -> - userWalletId to maybeBalance - } - } - - return combine(flows) { balances -> - lce { - balances.fold(mutableMapOf()) { acc, (userWalletId, maybeBalance) -> - val balance = maybeBalance.fold( - ifLoading = { TotalFiatBalance.Loading }, - ifContent = { it }, - ifError = { - Timber.e("failed to load balances with error: $it") - TotalFiatBalance.Failed - }, - ) - - isLoading.update { it || balance is TotalFiatBalance.Loading } - - acc[userWalletId] = balance - acc - } - } - } - } - - @OptIn(ExperimentalCoroutinesApi::class) - operator fun invoke(userWalletId: UserWalletId): LceFlow { - return currenciesStatusesOperations.getCurrenciesStatuses(userWalletId).map(::createBalance) - .distinctUntilChanged() - .onStart { - val cachedBalance = walletBalanceCache[userWalletId] - - if (cachedBalance != null) { - emit(cachedBalance.lceContent()) - } - } - .mapLatest { lceBalance -> - val cachedBalance = walletBalanceCache[userWalletId] - - if (cachedBalance == null) { - lceBalance.onContent { content -> - if (content is TotalFiatBalance.Loaded) { - walletBalanceCache.put(userWalletId, content) - } - } - - lceBalance - } else { - val content = lceBalance.getOrNull(isPartialContentAccepted = false) - - if (content is TotalFiatBalance.Loaded && content != cachedBalance) { - walletBalanceCache.put(userWalletId, content) - - lceBalance - } else { - cachedBalance.lceContent() - } - } - } - .distinctUntilChanged() - } - - private fun createBalance( - maybeStatuses: Lce>, - ): Lce = lce { - val statuses = when (maybeStatuses) { - is Lce.Content -> maybeStatuses.content - is Lce.Error -> raise(maybeStatuses) - is Lce.Loading -> { - val content = maybeStatuses.partialContent - - if (content == null) { - isLoading.set(true) - - raise(lceLoading()) - } else { - content - } - } - } - - TotalFiatBalanceCalculator.calculate( - statuses = ensureNotNull(statuses.toNonEmptyListOrNull()) { lceLoading() }, - ) - } -} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/TokenListErrorMappers.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/TokenListErrorMappers.kt index 081d02f18f..51e08ac450 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/TokenListErrorMappers.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/error/mapper/TokenListErrorMappers.kt @@ -2,7 +2,6 @@ package com.tangem.domain.tokens.error.mapper import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations -import com.tangem.domain.tokens.operations.TokenListOperations internal fun CurrenciesStatusesOperations.Error.mapToTokenListError(): TokenListError { return when (this) { @@ -15,12 +14,4 @@ internal fun CurrenciesStatusesOperations.Error.mapToTokenListError(): TokenList is CurrenciesStatusesOperations.Error.EmptyStakingBalances, -> TokenListError.EmptyTokens } -} - -internal fun TokenListOperations.Error.mapToTokenListError(): TokenListError { - return when (this) { - is TokenListOperations.Error.DataError -> TokenListError.DataError(this.cause) - is TokenListOperations.Error.UnableToSortTokenList -> - TokenListError.UnableToSortTokenList(this.unsortedTokenList) - } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/BaseCurrencyStatusOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/BaseCurrencyStatusOperations.kt index 10043d51ca..117b907f78 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/BaseCurrencyStatusOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/BaseCurrencyStatusOperations.kt @@ -3,7 +3,6 @@ package com.tangem.domain.tokens.operations import arrow.core.* import arrow.core.raise.* import com.tangem.blockchainsdk.utils.toBlockchain -import com.tangem.domain.core.lce.LceFlow import com.tangem.domain.core.utils.EitherFlow import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus @@ -28,7 +27,6 @@ import com.tangem.domain.staking.single.SingleStakingBalanceProducer import com.tangem.domain.staking.single.SingleStakingBalanceSupplier import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesProducer import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier -import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.utils.CurrencyStatusProxyCreator @@ -42,7 +40,7 @@ import kotlinx.coroutines.flow.* [REDACTED_AUTHOR] */ @Suppress("LargeClass", "LongParameterList") -abstract class BaseCurrencyStatusOperations( +class BaseCurrencyStatusOperations( private val currenciesRepository: CurrenciesRepository, private val quotesRepository: QuotesRepository, private val multiNetworkStatusSupplier: MultiNetworkStatusSupplier, @@ -56,10 +54,6 @@ abstract class BaseCurrencyStatusOperations( private val currencyStatusProxyCreator = CurrencyStatusProxyCreator() - abstract fun getCurrenciesStatuses(userWalletId: UserWalletId): LceFlow> - - protected abstract fun getQuotes(id: CryptoCurrency.RawID): Flow>> - suspend fun getCurrencyStatusFlow( userWalletId: UserWalletId, currencyId: CryptoCurrency.ID, @@ -389,6 +383,14 @@ abstract class BaseCurrencyStatusOperations( .bind() } + private fun getQuotes(id: CryptoCurrency.RawID): Flow>> { + return singleQuoteStatusSupplier( + params = SingleQuoteStatusProducer.Params(rawCurrencyId = id), + ) + .map>> { setOf(it).right() } + .distinctUntilChanged() + } + private suspend fun getStakingBalancesSync( userWalletId: UserWalletId, cryptoCurrencies: List, @@ -439,7 +441,7 @@ abstract class BaseCurrencyStatusOperations( ) } - protected fun getIds(currencies: List): Pair, NonEmptySet> { + private fun getIds(currencies: List): Pair, NonEmptySet> { val currencyIdToNetworkId = currencies.associate { currency -> currency.id to currency.network } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt deleted file mode 100644 index a1561d6d2e..0000000000 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CachedCurrenciesStatusesOperations.kt +++ /dev/null @@ -1,340 +0,0 @@ -package com.tangem.domain.tokens.operations - -import arrow.core.* -import arrow.core.raise.recover -import com.tangem.domain.core.lce.Lce -import com.tangem.domain.core.lce.LceFlow -import com.tangem.domain.core.lce.lce -import com.tangem.domain.core.lce.lceFlow -import com.tangem.domain.core.utils.EitherFlow -import com.tangem.domain.core.utils.lceContent -import com.tangem.domain.core.utils.lceError -import com.tangem.domain.models.currency.CryptoCurrency -import com.tangem.domain.models.currency.CryptoCurrencyStatus -import com.tangem.domain.models.network.Network -import com.tangem.domain.models.network.NetworkStatus -import com.tangem.domain.models.network.getAddress -import com.tangem.domain.models.quote.QuoteStatus -import com.tangem.domain.models.staking.StakingID -import com.tangem.domain.models.staking.StakingBalance -import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.networks.multi.MultiNetworkStatusSupplier -import com.tangem.domain.networks.single.SingleNetworkStatusProducer -import com.tangem.domain.networks.single.SingleNetworkStatusSupplier -import com.tangem.domain.quotes.QuotesRepository -import com.tangem.domain.quotes.single.SingleQuoteStatusProducer -import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier -import com.tangem.domain.staking.StakingIdFactory -import com.tangem.domain.staking.model.StakingIntegrationID -import com.tangem.domain.staking.multi.MultiStakingBalanceSupplier -import com.tangem.domain.staking.single.SingleStakingBalanceProducer -import com.tangem.domain.staking.single.SingleStakingBalanceSupplier -import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier -import com.tangem.domain.tokens.error.TokenListError -import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error -import com.tangem.domain.tokens.repository.CurrenciesRepository -import com.tangem.utils.extensions.addOrReplace -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.flow.* -import kotlinx.coroutines.launch - -@Suppress("LongParameterList", "LargeClass") -class CachedCurrenciesStatusesOperations( - private val currenciesRepository: CurrenciesRepository, - quotesRepository: QuotesRepository, - private val singleNetworkStatusSupplier: SingleNetworkStatusSupplier, - multiNetworkStatusSupplier: MultiNetworkStatusSupplier, - private val singleQuoteStatusSupplier: SingleQuoteStatusSupplier, - private val singleStakingBalanceSupplier: SingleStakingBalanceSupplier, - multiStakingBalanceSupplier: MultiStakingBalanceSupplier, - multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier, - private val stakingIdFactory: StakingIdFactory, -) : BaseCurrencyStatusOperations( - currenciesRepository = currenciesRepository, - quotesRepository = quotesRepository, - multiNetworkStatusSupplier = multiNetworkStatusSupplier, - singleNetworkStatusSupplier = singleNetworkStatusSupplier, - singleQuoteStatusSupplier = singleQuoteStatusSupplier, - singleStakingBalanceSupplier = singleStakingBalanceSupplier, - multiStakingBalanceSupplier = multiStakingBalanceSupplier, - multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier, - stakingIdFactory = stakingIdFactory, -) { - - override fun getCurrenciesStatuses( - userWalletId: UserWalletId, - ): LceFlow> { - return transformToCurrenciesStatuses( - userWalletId = userWalletId, - currenciesFlow = getCurrencies(userWalletId), - ) - } - - @Suppress("LongMethod") - @OptIn(ExperimentalCoroutinesApi::class) - private fun transformToCurrenciesStatuses( - userWalletId: UserWalletId, - currenciesFlow: EitherFlow>, - ): LceFlow> = lceFlow { - val prevStatuses = MutableStateFlow(value = emptyList()) - - currenciesFlow.flatMapLatest { maybeCurrencies -> - val currencies = maybeCurrencies - .getOrElse { return@flatMapLatest flowOf(it.lceError()) } - .toNonEmptyListOrNull() - - if (currencies.isNullOrEmpty()) { - prevStatuses.value = emptyList() - return@flatMapLatest flowOf(TokenListError.EmptyTokens.lceError()) - } - - // This is only 'true' when the flow here is empty, such as during initial loading - if (isLoading.get()) { - val loadingCurrencies = createCurrenciesStatuses( - currencies = currencies, - maybeNetworkStatuses = null, - maybeQuotes = null, - maybeStakingBalances = null, - isUpdating = true, - ) - - loadingCurrencies.getOrNull()?.let { prevStatuses.value = it } - - send(loadingCurrencies) - } - - val (networks, currenciesIds) = getIds(currencies) - - fun createCurrenciesStatuses( - maybeQuotes: Either>, - maybeNetworkStatuses: Either>, - maybeStakingBalances: Either>, - isUpdating: Boolean, - ) = createCurrenciesStatuses( - currencies = currencies, - maybeQuotes = maybeQuotes, - maybeNetworkStatuses = maybeNetworkStatuses, - maybeStakingBalances = maybeStakingBalances, - isUpdating = isUpdating, - ) - - // removing token - val prevStatusesValue = prevStatuses.value - if (prevStatusesValue.size - currencies.size == 1) { - val removed = prevStatusesValue.map { it.currency } - currencies - - return@flatMapLatest flowOf( - prevStatusesValue.filter { it.currency !in removed }.lceContent(), - ) - } - - val networksStatusesUpdates = getNetworkStatusesUpdates(userWalletId, networks) - - combine( - flow = getQuotes(currenciesIds), - flow2 = networksStatusesUpdates, - flow3 = networksStatusesUpdates.flatMapLatest { maybeNetworksStatuses -> - val networksStatuses = maybeNetworksStatuses.getOrNull() - - val currenciesAddresses = if (networksStatuses == null) { - emptyMap() - } else { - currencies.associate { currency -> - val networkStatus = networksStatuses.firstOrNull { it.network == currency.network } - - currency.id to networkStatus.getAddress() - } - } - - getYieldsBalancesUpdates(userWalletId, currenciesAddresses) - }, - flow4 = flowOf(value = false), - transform = ::createCurrenciesStatuses, - ) - .distinctUntilChanged() - } - .onEach { statusesLce -> - statusesLce.getOrNull()?.let { prevStatuses.value = it } - - send(statusesLce) - } - .launchIn(scope = this) - } - - private fun createCurrenciesStatuses( - currencies: NonEmptyList, - maybeQuotes: Either>?, - maybeNetworkStatuses: Either>?, - maybeStakingBalances: Either>?, - isUpdating: Boolean, - ): Lce> = lce { - isLoading.set(isUpdating) - - val networksStatuses = maybeNetworkStatuses?.bindEither()?.toNonEmptySetOrNull() - val stakingBalances = maybeStakingBalances?.bindEither() - val quotes = recover({ maybeQuotes?.bind()?.toNonEmptySetOrNull() }) { - null - } - - currencies.map { currency -> - val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId } - val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network } - val stakingBalance = findStakingBalanceOrNull(stakingBalances, currency, networkStatus) - - val currencyStatus = CryptoCurrencyStatusFactory.create( - currency = currency, - maybeNetworkStatus = networkStatus.toOption(), - maybeQuoteStatus = quote.toOption(), - maybeStakingBalance = stakingBalance.toOption(), - ) - - currencyStatus - } - } - - private fun findStakingBalanceOrNull( - stakingBalances: List?, - currency: CryptoCurrency, - networkStatus: NetworkStatus?, - ): StakingBalance? { - if (stakingBalances.isNullOrEmpty()) return null - - val supportedIntegration = StakingIntegrationID.create(currencyId = currency.id)?.value - val address = networkStatus.getAddress() - - return if (supportedIntegration != null && address != null) { - val stakingId = StakingID(integrationId = supportedIntegration, address = address) - - stakingBalances.firstOrNull { it.stakingId == stakingId } - ?: StakingBalance.Error(stakingId = stakingId) - } else { - null - } - } - - private fun getCurrencies(userWalletId: UserWalletId): EitherFlow> { - return currenciesRepository.getWalletCurrenciesUpdates(userWalletId) - .map, Either>> { it.right() } - .catch { emit(TokenListError.DataError(it).left()) } - .distinctUntilChanged() - } - - private fun getQuotes(tokensIds: NonEmptySet): Flow>> { - return getQuotesUpdates( - rawCurrencyIds = tokensIds.mapNotNullTo( - destination = hashSetOf(), - transform = CryptoCurrency.ID::rawCurrencyId, - ), - ) - } - - override fun getQuotes(id: CryptoCurrency.RawID): Flow>> { - return singleQuoteStatusSupplier( - params = SingleQuoteStatusProducer.Params(rawCurrencyId = id), - ) - .map>> { setOf(it).right() } - .distinctUntilChanged() - } - - // temporary code because token list is built using networks list - @OptIn(FlowPreview::class) - private fun getNetworkStatusesUpdates( - userWalletId: UserWalletId, - networks: NonEmptySet, - ): EitherFlow> { - return channelFlow { - val state = MutableStateFlow(emptySet()) - - networks.onEach { - launch { - singleNetworkStatusSupplier( - params = SingleNetworkStatusProducer.Params(userWalletId = userWalletId, network = it), - ) - .onEach { status -> - state.update { loadedStatuses -> - loadedStatuses.addOrReplace(status) { it.network == status.network } - } - } - .launchIn(scope = this) - } - } - - state - .onEach(::send) - .launchIn(scope = this) - } - .debounce(timeoutMillis = 500) - .map, Either>> { it.right() } - .distinctUntilChanged() - } - - // temporary code because token list is built using networks list - private fun getQuotesUpdates( - rawCurrencyIds: Set, - ): EitherFlow> { - return channelFlow { - val state = MutableStateFlow(emptySet()) - - rawCurrencyIds.onEach { - launch { - singleQuoteStatusSupplier( - params = SingleQuoteStatusProducer.Params(rawCurrencyId = it), - ) - .onEach { quote -> - state.update { loadedStatuses -> - loadedStatuses.addOrReplace(quote) { it.rawCurrencyId == quote.rawCurrencyId } - } - } - .launchIn(scope = this) - } - } - - state - .onEach(::send) - .launchIn(scope = this) - } - .map, Either>> { it.right() } - .distinctUntilChanged() - } - - // temporary code because token list is built using networks list - private fun getYieldsBalancesUpdates( - userWalletId: UserWalletId, - cryptoCurrencies: Map, - ): EitherFlow> { - return channelFlow { - val state = MutableStateFlow(emptyList()) - - val stakingIds = cryptoCurrencies.mapNotNullTo(hashSetOf()) { currencyWithAddress -> - stakingIdFactory.create( - currencyId = currencyWithAddress.key, - defaultAddress = currencyWithAddress.value, - ) - .getOrNull() - } - - stakingIds.onEach { stakingId -> - launch { - singleStakingBalanceSupplier( - params = SingleStakingBalanceProducer.Params( - userWalletId = userWalletId, - stakingId = stakingId, - ), - ) - .onEach { balance -> - state.update { loadedBalances -> - loadedBalances.addOrReplace(balance) { balance.stakingId == it.stakingId } - } - } - .launchIn(scope = this) - } - } - - state - .onEach { send(it.right()) } - .launchIn(scope = this) - } - .distinctUntilChanged() - } -} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListOperations.kt deleted file mode 100644 index e42588514f..0000000000 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListOperations.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.tangem.domain.tokens.operations - -import arrow.core.Either -import arrow.core.left -import arrow.core.raise.either -import arrow.core.right -import arrow.core.toNonEmptyListOrNull -import com.tangem.domain.models.TokensGroupType -import com.tangem.domain.models.TokensSortType -import com.tangem.domain.models.currency.CryptoCurrencyStatus -import com.tangem.domain.models.tokenlist.TokenList -import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.tokens.repository.CurrenciesRepository -import kotlinx.coroutines.flow.* - -@Suppress("LongParameterList") -internal class TokenListOperations( - private val currenciesRepository: CurrenciesRepository, - private val userWalletId: UserWalletId, - private val tokens: List, -) { - - fun getTokenListFlow(): Flow> { - return combine( - flow = getIsGrouped(), - flow2 = getIsSortedByBalance(), - ) { isGrouped, isSortedByBalance -> - either { - createTokenList(isGrouped = isGrouped.bind(), isSortedByBalance = isSortedByBalance.bind()) - } - } - } - - private fun createTokenList(isGrouped: Boolean, isSortedByBalance: Boolean): TokenList { - val nonEmptyCurrencies = tokens.toNonEmptyListOrNull() ?: return TokenList.Empty - - return TokenListFactory.create( - statuses = nonEmptyCurrencies, - groupType = if (isGrouped) TokensGroupType.NETWORK else TokensGroupType.NONE, - sortType = if (isSortedByBalance) TokensSortType.BALANCE else TokensSortType.NONE, - ) - } - - private fun getIsGrouped(): Flow> { - return currenciesRepository.isTokensGrouped(userWalletId) - .map> { it.right() } - .catch { emit(Error.DataError(it).left()) } - .onEmpty { emit(value = false.right()) } - .cancellable() - } - - private fun getIsSortedByBalance(): Flow> { - return currenciesRepository.isTokensSortedByBalance(userWalletId) - .map> { it.right() } - .catch { emit(Error.DataError(it).left()) } - .onEmpty { emit(value = false.right()) } - .cancellable() - } - - sealed class Error { - - data class UnableToSortTokenList(val unsortedTokenList: TokenList.Ungrouped) : Error() - - data class DataError(val cause: Throwable) : Error() - } -} \ No newline at end of file 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 779e36f447..c830032607 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 @@ -5,7 +5,6 @@ import com.tangem.domain.core.error.DataError import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.network.Network -import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.tokens.model.FeePaidCurrency import kotlinx.coroutines.flow.Flow @@ -71,23 +70,6 @@ interface CurrenciesRepository { id: CryptoCurrency.ID, ): CryptoCurrency - /** - * Retrieves the list of cryptocurrencies within a multi-currency wallet. - * - * Loads cryptocurrencies if they have expired or if [refresh] is `true`. - * - * @param userWalletId The unique identifier of the user wallet. - * @param refresh A boolean flag indicating whether the data should be refreshed. - * @return A list of [CryptoCurrency]. - * @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet - * ID provided. - */ - @Deprecated("Use MultiWalletCryptoCurrenciesSupplier") - suspend fun getMultiCurrencyWalletCurrenciesSync( - userWalletId: UserWalletId, - refresh: Boolean = false, - ): List - /** * Get the coin for a specific network. * @@ -101,28 +83,6 @@ interface CurrenciesRepository { derivationPath: Network.DerivationPath, ): CryptoCurrency.Coin - /** - * Determines whether the tokens within a specific multi-currency user wallet are grouped. - * - * @param userWalletId The unique identifier of the user wallet. - * @return A [Flow] emitting a boolean value indicating whether the tokens are grouped. - * @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet - * ID provided. - */ - @Deprecated("Use SingleAccountListSupplier instead") - fun isTokensGrouped(userWalletId: UserWalletId): Flow - - /** - * Determines whether the tokens within a specific multi-currency user wallet are sorted by balance. - * - * @param userWalletId The unique identifier of the user wallet. - * @return A [Flow] emitting a boolean value indicating whether the tokens are sorted by balance. - * @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet - * ID provided. - */ - @Deprecated("Use SingleAccountListSupplier instead") - fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow - /** * Determines whether the currency sending is blocked by network pending transaction * @@ -153,10 +113,6 @@ interface CurrenciesRepository { networkId: String, ): CryptoCurrency.Token - /** Get crypto currencies by [currencyRawId] from all user wallets */ - @Deprecated("Use MultiAccountListSupplier instead") - fun getAllWalletsCryptoCurrencies(currencyRawId: CryptoCurrency.RawID): Flow>> - fun isNetworkFeeZero(userWalletId: UserWalletId, network: Network): Boolean @Throws diff --git a/features/walletconnect/impl/build.gradle.kts b/features/walletconnect/impl/build.gradle.kts index fd948afd0b..48f84373fe 100644 --- a/features/walletconnect/impl/build.gradle.kts +++ b/features/walletconnect/impl/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { /** Domain models */ implementation(projects.domain.account) + implementation(projects.domain.account.status) implementation(projects.domain.appCurrency.models) implementation(projects.domain.balanceHiding.models) implementation(projects.domain.blockaid.models) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectWalletModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectWalletModel.kt index e9f6c92a3b..04132e0692 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectWalletModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectWalletModel.kt @@ -6,7 +6,7 @@ import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender -import com.tangem.domain.tokens.GetTokenListUseCase +import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.models.wallet.UserWalletId import com.tangem.features.wallet.utils.UserWalletsFetcher import com.tangem.features.walletconnect.connections.components.WcSelectWalletComponent.WcSelectWalletParams @@ -24,7 +24,7 @@ internal class WcSelectWalletModel @Inject constructor( paramsContainer: ParamsContainer, messageSender: UiMessageSender, userWalletsFetcherFactory: UserWalletsFetcher.Factory, - getTokenListUseCase: GetTokenListUseCase, + private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier, private val router: Router, override val dispatchers: CoroutineDispatcherProvider, ) : Model() { @@ -41,7 +41,7 @@ internal class WcSelectWalletModel @Inject constructor( private val userWalletsFetcher = WcUserWalletsFetcher( userWalletsFetcherFactory = userWalletsFetcherFactory, - getTokenListUseCase = getTokenListUseCase, + singleAccountStatusListSupplier = singleAccountStatusListSupplier, messageSender = messageSender, onWalletSelected = ::onWalletSelected, ) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcUserWalletsFetcher.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcUserWalletsFetcher.kt index 742a0205bd..e5d1e47801 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcUserWalletsFetcher.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcUserWalletsFetcher.kt @@ -6,8 +6,9 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.wrappedList +import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier +import com.tangem.domain.models.TotalFiatBalance import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.features.wallet.utils.UserWalletsFetcher import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -17,12 +18,11 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map -@Suppress("LongParameterList") @ModelScoped internal class WcUserWalletsFetcher( userWalletsFetcherFactory: UserWalletsFetcher.Factory, messageSender: UiMessageSender, - private val getTokenListUseCase: GetTokenListUseCase, + private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier, private val onWalletSelected: (UserWalletId) -> Unit, ) { @@ -42,12 +42,13 @@ internal class WcUserWalletsFetcher( } private fun getTokenListFlow(walletItem: UserWalletItemUM): Flow { - return getTokenListUseCase.launch(UserWalletId(walletItem.id)).map { lce -> - val information = lce.fold( - ifLoading = { UserWalletItemUM.Information.Loading }, - ifError = { UserWalletItemUM.Information.Failed }, - ifContent = { tokenList -> tokenCountInfo(tokenList.flattenCurrencies().size) }, - ) + return singleAccountStatusListSupplier(userWalletId = UserWalletId(walletItem.id)).map { accountStatusList -> + val information = when (accountStatusList.totalFiatBalance) { + is TotalFiatBalance.Failed -> UserWalletItemUM.Information.Failed + is TotalFiatBalance.Loading -> UserWalletItemUM.Information.Loading + is TotalFiatBalance.Loaded -> tokenCountInfo(accountStatusList.flattenCurrencies().size) + } + walletItem.copy(information = information) } }