Updated on 2026-08-14
This commit is contained in:
parent
afe5ec2c57
commit
625277f518
7 changed files with 152 additions and 30 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.data.tokens.repository
|
||||
|
||||
import arrow.core.raise.catch
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.data.common.api.safeApiCall
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
|
|
@ -20,6 +21,9 @@ import com.tangem.domain.common.extensions.toNetworkId
|
|||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.hasDerivation
|
||||
import com.tangem.domain.core.error.DataError
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.core.lce.lceFlow
|
||||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
|
|
@ -55,6 +59,10 @@ internal class DefaultCurrenciesRepository(
|
|||
private val userTokensBackwardCompatibility = UserTokensBackwardCompatibility()
|
||||
private val customTokensMerger = CustomTokensMerger(tangemTechApi, dispatchers)
|
||||
|
||||
private val isMultiCurrencyWalletCurrenciesFetching = MutableStateFlow(
|
||||
value = emptyMap<UserWalletId, Boolean>(),
|
||||
)
|
||||
|
||||
override suspend fun saveTokens(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: List<CryptoCurrency>,
|
||||
|
|
@ -215,6 +223,30 @@ internal class DefaultCurrenciesRepository(
|
|||
.cancellable()
|
||||
}
|
||||
|
||||
override fun getMultiCurrencyWalletCurrenciesUpdatesLce(
|
||||
userWalletId: UserWalletId,
|
||||
): LceFlow<Throwable, List<CryptoCurrency>> = lceFlow {
|
||||
val userWallet = getUserWallet(userWalletId)
|
||||
catch({ ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = true) }) {
|
||||
raise(it.lceError())
|
||||
}
|
||||
|
||||
launch(dispatchers.io) {
|
||||
combine(
|
||||
getMultiCurrencyWalletCurrencies(userWallet),
|
||||
isMultiCurrencyWalletCurrenciesFetching.map { it.getOrElse(userWallet.walletId) { false } },
|
||||
) { currencies, isFetching ->
|
||||
send(currencies, isStillLoading = isFetching)
|
||||
}.collect()
|
||||
}
|
||||
|
||||
withContext(dispatchers.io) {
|
||||
catch({ fetchTokensIfCacheExpired(userWallet, refresh = false) }) {
|
||||
raise(it.lceError())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getMultiCurrencyWalletCurrenciesSync(
|
||||
userWalletId: UserWalletId,
|
||||
refresh: Boolean,
|
||||
|
|
@ -369,11 +401,21 @@ internal class DefaultCurrenciesRepository(
|
|||
}
|
||||
|
||||
private suspend fun fetchTokensIfCacheExpired(userWallet: UserWallet, refresh: Boolean) {
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getTokensCacheKey(userWallet.walletId),
|
||||
skipCache = refresh,
|
||||
block = { fetchTokens(userWallet) },
|
||||
)
|
||||
try {
|
||||
isMultiCurrencyWalletCurrenciesFetching.update {
|
||||
it + (userWallet.walletId to true)
|
||||
}
|
||||
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getTokensCacheKey(userWallet.walletId),
|
||||
skipCache = refresh,
|
||||
block = { fetchTokens(userWallet) },
|
||||
)
|
||||
} finally {
|
||||
isMultiCurrencyWalletCurrenciesFetching.update {
|
||||
it - userWallet.walletId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchTokens(userWallet: UserWallet) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.data.tokens.repository
|
||||
|
||||
import arrow.core.raise.catch
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.tokens.utils.CardCryptoCurrenciesFactory
|
||||
|
|
@ -10,6 +11,9 @@ import com.tangem.datasource.local.token.UserTokensStore
|
|||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.core.lce.lceFlow
|
||||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
|
|
@ -20,10 +24,7 @@ import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult
|
|||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.cancellable
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.*
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultNetworksRepository(
|
||||
|
|
@ -40,6 +41,10 @@ internal class DefaultNetworksRepository(
|
|||
private val responseCurrenciesFactory by lazy { ResponseCryptoCurrenciesFactory() }
|
||||
private val networkStatusFactory by lazy { NetworkStatusFactory() }
|
||||
|
||||
private val isNetworkStatusesFetching = MutableStateFlow(
|
||||
value = emptyMap<UserWalletId, Boolean>(),
|
||||
)
|
||||
|
||||
override fun getNetworkStatusesUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
|
|
@ -55,6 +60,26 @@ internal class DefaultNetworksRepository(
|
|||
}
|
||||
.cancellable()
|
||||
|
||||
override fun getNetworkStatusesUpdatesLce(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
): LceFlow<Throwable, Set<NetworkStatus>> = lceFlow {
|
||||
launch(dispatchers.io) {
|
||||
combine(
|
||||
networksStatusesStore.get(userWalletId),
|
||||
isNetworkStatusesFetching.map { it.getOrElse(userWalletId) { false } },
|
||||
) { statuses, isFetching ->
|
||||
send(statuses, isStillLoading = isFetching)
|
||||
}.collect()
|
||||
}
|
||||
|
||||
withContext(dispatchers.io) {
|
||||
catch({ fetchNetworksStatusesIfCacheExpired(userWalletId, networks, refresh = false) }) {
|
||||
raise(it.lceError())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun fetchNetworkPendingTransactions(userWalletId: UserWalletId, networks: Set<Network>) {
|
||||
val currencies = getCurrencies(userWalletId, networks)
|
||||
withContext(dispatchers.io) {
|
||||
|
|
@ -81,15 +106,25 @@ internal class DefaultNetworksRepository(
|
|||
networks: Set<Network>,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
val currencies = getCurrencies(userWalletId, networks)
|
||||
coroutineScope {
|
||||
networks
|
||||
.map { network ->
|
||||
async {
|
||||
fetchNetworkStatusIfCacheExpired(userWalletId, network, currencies, refresh)
|
||||
try {
|
||||
isNetworkStatusesFetching.update {
|
||||
it + (userWalletId to true)
|
||||
}
|
||||
|
||||
val currencies = getCurrencies(userWalletId, networks)
|
||||
coroutineScope {
|
||||
networks
|
||||
.map { network ->
|
||||
async {
|
||||
fetchNetworkStatusIfCacheExpired(userWalletId, network, currencies, refresh)
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.awaitAll()
|
||||
}
|
||||
} finally {
|
||||
isNetworkStatusesFetching.update {
|
||||
it - userWalletId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ android {
|
|||
dependencies {
|
||||
|
||||
/** Project - Domain */
|
||||
implementation(projects.domain.core)
|
||||
api(projects.domain.core)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.tokens.models)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.domain.tokens.repository
|
||||
|
||||
import com.tangem.domain.core.error.DataError
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.FeePaidCurrency
|
||||
|
|
@ -20,7 +22,7 @@ interface CurrenciesRepository {
|
|||
* @param currencies The list of cryptocurrencies to be saved.
|
||||
* @param isGroupedByNetwork A boolean flag indicating whether the tokens should be grouped by network.
|
||||
* @param isSortedByBalance A boolean flag indicating whether the tokens should be sorted by balance.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
suspend fun saveTokens(
|
||||
|
|
@ -35,7 +37,7 @@ interface CurrenciesRepository {
|
|||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param currencies The currencies which must be added.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
suspend fun addCurrencies(userWalletId: UserWalletId, currencies: List<CryptoCurrency>)
|
||||
|
|
@ -45,7 +47,7 @@ interface CurrenciesRepository {
|
|||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param currency The currency which must be removed.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If multi-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If multi-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
suspend fun removeCurrency(userWalletId: UserWalletId, currency: CryptoCurrency)
|
||||
|
|
@ -55,7 +57,7 @@ interface CurrenciesRepository {
|
|||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param currencies The currencies which must be removed.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
suspend fun removeCurrencies(userWalletId: UserWalletId, currencies: List<CryptoCurrency>)
|
||||
|
|
@ -65,7 +67,7 @@ interface CurrenciesRepository {
|
|||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @return The primary cryptocurrency associated with the user wallet.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If multi-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If multi-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
suspend fun getSingleCurrencyWalletPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency
|
||||
|
|
@ -75,7 +77,7 @@ interface CurrenciesRepository {
|
|||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @return The primary cryptocurrency associated with the user wallet.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If multi-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If multi-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
suspend fun getSingleCurrencyWalletWithCardCurrencies(userWalletId: UserWalletId): List<CryptoCurrency>
|
||||
|
|
@ -87,7 +89,7 @@ interface CurrenciesRepository {
|
|||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param id The unique identifier of the cryptocurrency to be retrieved.
|
||||
* @return The cryptocurrency associated with the user wallet and ID.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
suspend fun getSingleCurrencyWalletWithCardCurrency(
|
||||
|
|
@ -102,11 +104,22 @@ interface CurrenciesRepository {
|
|||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @return A [Flow] emitting the set of cryptocurrencies associated with the user wallet.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
fun getMultiCurrencyWalletCurrenciesUpdates(userWalletId: UserWalletId): Flow<List<CryptoCurrency>>
|
||||
|
||||
/**
|
||||
* Retrieves updates of the list of cryptocurrencies within a multi-currency wallet.
|
||||
*
|
||||
* Loads remote cryptocurrencies if they have expired.
|
||||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @return A [LceFlow] emitting the set of cryptocurrencies associated with the user wallet. May emit an
|
||||
* [DataError.UserWalletError.WrongUserWallet] if single-currency user wallet ID provided.
|
||||
*/
|
||||
fun getMultiCurrencyWalletCurrenciesUpdatesLce(userWalletId: UserWalletId): LceFlow<Throwable, List<CryptoCurrency>>
|
||||
|
||||
/**
|
||||
* Retrieves the list of cryptocurrencies within a multi-currency wallet.
|
||||
*
|
||||
|
|
@ -115,7 +128,7 @@ interface CurrenciesRepository {
|
|||
* @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 com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
suspend fun getMultiCurrencyWalletCurrenciesSync(
|
||||
|
|
@ -129,7 +142,7 @@ interface CurrenciesRepository {
|
|||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param id The unique identifier of the cryptocurrency to be retrieved.
|
||||
* @return The cryptocurrency associated with the user wallet and ID.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
suspend fun getMultiCurrencyWalletCurrency(userWalletId: UserWalletId, id: CryptoCurrency.ID): CryptoCurrency
|
||||
|
|
@ -152,7 +165,7 @@ interface CurrenciesRepository {
|
|||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @return A [Flow] emitting a boolean value indicating whether the tokens are grouped.
|
||||
* @throws com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
fun isTokensGrouped(userWalletId: UserWalletId): Flow<Boolean>
|
||||
|
|
@ -162,7 +175,7 @@ interface CurrenciesRepository {
|
|||
*
|
||||
* @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 com.tangem.domain.core.error.DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
|
||||
* ID provided.
|
||||
*/
|
||||
fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow<Boolean>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.domain.tokens.repository
|
||||
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -20,6 +21,20 @@ interface NetworksRepository {
|
|||
*/
|
||||
fun getNetworkStatusesUpdates(userWalletId: UserWalletId, networks: Set<Network>): Flow<Set<NetworkStatus>>
|
||||
|
||||
/**
|
||||
* Retrieves updates of network statuses of specified blockchain networks for a specific user wallet.
|
||||
*
|
||||
* Loads remote network statuses if they have expired.
|
||||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param networks A set of network which statuses are to be retrieved.
|
||||
* @return A [LceFlow] emitting a set of [NetworkStatus] objects corresponding to the specified networks.
|
||||
*/
|
||||
fun getNetworkStatusesUpdatesLce(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
): LceFlow<Throwable, Set<NetworkStatus>>
|
||||
|
||||
/**
|
||||
* Fetches pending transactions for given network
|
||||
*
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.tangem.domain.tokens.repository
|
|||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.core.error.DataError
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.core.utils.toLce
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.FeePaidCurrency
|
||||
|
|
@ -78,6 +80,12 @@ internal class MockCurrenciesRepository(
|
|||
return tokens.map { it.getOrElse { e -> throw e } }
|
||||
}
|
||||
|
||||
override fun getMultiCurrencyWalletCurrenciesUpdatesLce(
|
||||
userWalletId: UserWalletId,
|
||||
): LceFlow<Throwable, List<CryptoCurrency>> {
|
||||
return tokens.map { it.toLce() }
|
||||
}
|
||||
|
||||
override suspend fun getMultiCurrencyWalletCurrency(
|
||||
userWalletId: UserWalletId,
|
||||
id: CryptoCurrency.ID,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.tangem.domain.tokens.repository
|
|||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.core.error.DataError
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.core.utils.toLce
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -21,6 +23,13 @@ internal class MockNetworksRepository(
|
|||
return statuses.map { it.getOrElse { e -> throw e } }
|
||||
}
|
||||
|
||||
override fun getNetworkStatusesUpdatesLce(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
): LceFlow<Throwable, Set<NetworkStatus>> {
|
||||
return statuses.map { it.toLce() }
|
||||
}
|
||||
|
||||
override suspend fun fetchNetworkPendingTransactions(userWalletId: UserWalletId, networks: Set<Network>) {
|
||||
// no-op
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue