Updated on 2026-08-14
This commit is contained in:
parent
dd186d6fbc
commit
3f5f3ef68b
23 changed files with 351 additions and 128 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
package com.tangem.tap.di.domain
|
package com.tangem.tap.di.domain
|
||||||
|
|
||||||
import com.tangem.domain.tokens.*
|
import com.tangem.domain.tokens.*
|
||||||
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||||
import com.tangem.domain.tokens.repository.TokensRepository
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -18,23 +18,23 @@ internal object TokensDomainModule {
|
||||||
@Provides
|
@Provides
|
||||||
@ViewModelScoped
|
@ViewModelScoped
|
||||||
fun provideGetTokenListUseCase(
|
fun provideGetTokenListUseCase(
|
||||||
tokensRepository: TokensRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): GetTokenListUseCase {
|
): GetTokenListUseCase {
|
||||||
return GetTokenListUseCase(tokensRepository, quotesRepository, networksRepository, dispatchers)
|
return GetTokenListUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@ViewModelScoped
|
@ViewModelScoped
|
||||||
fun provideGetPrimaryCurrencyUseCase(
|
fun provideGetPrimaryCurrencyUseCase(
|
||||||
tokensRepository: TokensRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
quotesRepository: QuotesRepository,
|
quotesRepository: QuotesRepository,
|
||||||
networksRepository: NetworksRepository,
|
networksRepository: NetworksRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): GetPrimaryCurrencyUseCase {
|
): GetCurrencyUseCase {
|
||||||
return GetPrimaryCurrencyUseCase(tokensRepository, quotesRepository, networksRepository, dispatchers)
|
return GetCurrencyUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
@ -55,9 +55,9 @@ internal object TokensDomainModule {
|
||||||
@Provides
|
@Provides
|
||||||
@ViewModelScoped
|
@ViewModelScoped
|
||||||
fun provideApplyTokenListSortingUseCase(
|
fun provideApplyTokenListSortingUseCase(
|
||||||
tokensRepository: TokensRepository,
|
currenciesRepository: CurrenciesRepository,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): ApplyTokenListSortingUseCase {
|
): ApplyTokenListSortingUseCase {
|
||||||
return ApplyTokenListSortingUseCase(tokensRepository, dispatchers)
|
return ApplyTokenListSortingUseCase(currenciesRepository, dispatchers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
package com.tangem.data.tokens.di
|
package com.tangem.data.tokens.di
|
||||||
|
|
||||||
import com.tangem.data.common.cache.CacheRegistry
|
import com.tangem.data.common.cache.CacheRegistry
|
||||||
|
import com.tangem.data.tokens.repository.DefaultCurrenciesRepository
|
||||||
import com.tangem.data.tokens.repository.DefaultNetworksRepository
|
import com.tangem.data.tokens.repository.DefaultNetworksRepository
|
||||||
import com.tangem.data.tokens.repository.DefaultTokensRepository
|
|
||||||
import com.tangem.data.tokens.repository.MockQuotesRepository
|
import com.tangem.data.tokens.repository.MockQuotesRepository
|
||||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||||
import com.tangem.datasource.local.token.UserTokensStore
|
import com.tangem.datasource.local.token.UserTokensStore
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||||
import com.tangem.domain.tokens.repository.TokensRepository
|
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
|
|
@ -24,14 +24,14 @@ internal object TokensDataModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideTokensRepository(
|
fun provideCurrenciesRepository(
|
||||||
tangemTechApi: TangemTechApi,
|
tangemTechApi: TangemTechApi,
|
||||||
userTokensStore: UserTokensStore,
|
userTokensStore: UserTokensStore,
|
||||||
userWalletsStore: UserWalletsStore,
|
userWalletsStore: UserWalletsStore,
|
||||||
cacheRegistry: CacheRegistry,
|
cacheRegistry: CacheRegistry,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
): TokensRepository {
|
): CurrenciesRepository {
|
||||||
return DefaultTokensRepository(tangemTechApi, userTokensStore, userWalletsStore, cacheRegistry, dispatchers)
|
return DefaultCurrenciesRepository(tangemTechApi, userTokensStore, userWalletsStore, cacheRegistry, dispatchers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
||||||
|
|
@ -8,23 +8,27 @@ import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||||
import com.tangem.datasource.local.token.UserTokensStore
|
import com.tangem.datasource.local.token.UserTokensStore
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
|
import com.tangem.domain.core.error.DataError
|
||||||
import com.tangem.domain.demo.DemoConfig
|
import com.tangem.domain.demo.DemoConfig
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
import com.tangem.domain.tokens.repository.TokensRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.wallets.models.UserWallet
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
internal class DefaultTokensRepository(
|
internal class DefaultCurrenciesRepository(
|
||||||
private val tangemTechApi: TangemTechApi,
|
private val tangemTechApi: TangemTechApi,
|
||||||
private val userTokensStore: UserTokensStore,
|
private val userTokensStore: UserTokensStore,
|
||||||
private val userWalletsStore: UserWalletsStore,
|
private val userWalletsStore: UserWalletsStore,
|
||||||
private val cacheRegistry: CacheRegistry,
|
private val cacheRegistry: CacheRegistry,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
) : TokensRepository {
|
) : CurrenciesRepository {
|
||||||
|
|
||||||
private val demoConfig = DemoConfig()
|
private val demoConfig = DemoConfig()
|
||||||
private val responseCurrenciesFactory = ResponseCurrenciesFactory(demoConfig)
|
private val responseCurrenciesFactory = ResponseCurrenciesFactory(demoConfig)
|
||||||
|
|
@ -37,6 +41,8 @@ internal class DefaultTokensRepository(
|
||||||
isGroupedByNetwork: Boolean,
|
isGroupedByNetwork: Boolean,
|
||||||
isSortedByBalance: Boolean,
|
isSortedByBalance: Boolean,
|
||||||
) = withContext(dispatchers.io) {
|
) = withContext(dispatchers.io) {
|
||||||
|
ensureIsCorrectUserWallet(userWalletId, isMultiCurrencyWalletExpected = true)
|
||||||
|
|
||||||
val response = userTokensResponseFactory.createUserTokensResponse(
|
val response = userTokensResponseFactory.createUserTokensResponse(
|
||||||
currencies = currencies,
|
currencies = currencies,
|
||||||
isGroupedByNetwork = isGroupedByNetwork,
|
isGroupedByNetwork = isGroupedByNetwork,
|
||||||
|
|
@ -46,58 +52,72 @@ internal class DefaultTokensRepository(
|
||||||
storeAndPushTokens(userWalletId, response)
|
storeAndPushTokens(userWalletId, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency {
|
override suspend fun getSingleCurrencyWalletPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency {
|
||||||
val userWallet = withContext(dispatchers.io) {
|
return withContext(dispatchers.io) {
|
||||||
requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
val userWallet = getUserWallet(userWalletId)
|
||||||
"Unable to find a user wallet with provided ID: $userWalletId"
|
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = false)
|
||||||
}
|
|
||||||
}
|
|
||||||
require(!userWallet.isMultiCurrency) {
|
|
||||||
"Single currency wallet excepted, but multi currency wallet was found: $userWalletId"
|
|
||||||
}
|
|
||||||
|
|
||||||
return cardCurrenciesFactory.createPrimaryCurrencyForSingleCurrencyCard(userWallet.scanResponse)
|
cardCurrenciesFactory.createPrimaryCurrencyForSingleCurrencyCard(userWallet.scanResponse)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMultiCurrencyWalletCurrencies(
|
override fun getMultiCurrencyWalletCurrencies(
|
||||||
userWalletId: UserWalletId,
|
userWalletId: UserWalletId,
|
||||||
refresh: Boolean,
|
refresh: Boolean,
|
||||||
): Flow<Set<CryptoCurrency>> {
|
): Flow<Set<CryptoCurrency>> = channelFlow {
|
||||||
|
val userWallet = getUserWallet(userWalletId)
|
||||||
|
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = true)
|
||||||
|
|
||||||
|
launch(dispatchers.io) {
|
||||||
|
getMultiCurrencyWalletCurrencies(userWallet).collect(::send)
|
||||||
|
}
|
||||||
|
|
||||||
|
launch(dispatchers.io) {
|
||||||
|
fetchTokensIfCacheExpired(userWallet, refresh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getMultiCurrencyWalletCurrency(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
id: CryptoCurrency.ID,
|
||||||
|
): CryptoCurrency = withContext(dispatchers.io) {
|
||||||
|
val userWallet = getUserWallet(userWalletId)
|
||||||
|
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = true)
|
||||||
|
|
||||||
|
val response = requireNotNull(userTokensStore.getSyncOrNull(userWalletId)) {
|
||||||
|
"Unable to find tokens response for user wallet with provided ID: $userWalletId"
|
||||||
|
}
|
||||||
|
|
||||||
|
responseCurrenciesFactory.createCurrency(id, response, userWallet.scanResponse.card)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isTokensGrouped(userWalletId: UserWalletId): Flow<Boolean> {
|
||||||
return channelFlow {
|
return channelFlow {
|
||||||
val userWallet = withContext(dispatchers.io) {
|
ensureIsCorrectUserWallet(userWalletId, isMultiCurrencyWalletExpected = true)
|
||||||
requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
|
||||||
"Unable to find a user wallet with provided ID: $userWalletId"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
require(userWallet.isMultiCurrency) {
|
|
||||||
"Multi currency wallet excepted, but single currency wallet was found: $userWalletId"
|
|
||||||
}
|
|
||||||
|
|
||||||
launch(dispatchers.io) {
|
launch(dispatchers.io) {
|
||||||
getMultiCurrencyWalletCurrencies(userWallet).collectLatest(::send)
|
userTokensStore.get(userWalletId)
|
||||||
}
|
.map { it.group == UserTokensResponse.GroupType.NETWORK }
|
||||||
|
.collect(::send)
|
||||||
launch(dispatchers.io) {
|
|
||||||
fetchTokensIfCacheExpired(userWallet, refresh)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isTokensGrouped(userWalletId: UserWalletId): Flow<Boolean> {
|
|
||||||
return userTokensStore.get(userWalletId)
|
|
||||||
.map { it.group == UserTokensResponse.GroupType.NETWORK }
|
|
||||||
.flowOn(dispatchers.io)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow<Boolean> {
|
override fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow<Boolean> {
|
||||||
return userTokensStore.get(userWalletId)
|
return channelFlow {
|
||||||
.map { it.sort == UserTokensResponse.SortType.BALANCE }
|
ensureIsCorrectUserWallet(userWalletId, isMultiCurrencyWalletExpected = true)
|
||||||
.flowOn(dispatchers.io)
|
|
||||||
|
launch(dispatchers.io) {
|
||||||
|
userTokensStore.get(userWalletId)
|
||||||
|
.map { it.sort == UserTokensResponse.SortType.BALANCE }
|
||||||
|
.collect(::send)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMultiCurrencyWalletCurrencies(userWallet: UserWallet): Flow<Set<CryptoCurrency>> {
|
private fun getMultiCurrencyWalletCurrencies(userWallet: UserWallet): Flow<Set<CryptoCurrency>> {
|
||||||
return userTokensStore.get(userWallet.walletId).map { storedTokens ->
|
return userTokensStore.get(userWallet.walletId).map { storedTokens ->
|
||||||
responseCurrenciesFactory.createTokens(
|
responseCurrenciesFactory.createCurrencies(
|
||||||
response = storedTokens,
|
response = storedTokens,
|
||||||
card = userWallet.scanResponse.card,
|
card = userWallet.scanResponse.card,
|
||||||
)
|
)
|
||||||
|
|
@ -146,6 +166,39 @@ internal class DefaultTokensRepository(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun getUserWallet(userWalletId: UserWalletId): UserWallet {
|
||||||
|
return requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
||||||
|
"Unable to find a user wallet with provided ID: $userWalletId"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun ensureIsCorrectUserWallet(userWalletId: UserWalletId, isMultiCurrencyWalletExpected: Boolean) {
|
||||||
|
val userWallet = getUserWallet(userWalletId)
|
||||||
|
|
||||||
|
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ensureIsCorrectUserWallet(userWallet: UserWallet, isMultiCurrencyWalletExpected: Boolean) {
|
||||||
|
val userWalletId = userWallet.walletId
|
||||||
|
|
||||||
|
val message = when {
|
||||||
|
!userWallet.isMultiCurrency && isMultiCurrencyWalletExpected -> {
|
||||||
|
"Multi currency wallet expected, but single currency wallet was found: $userWalletId"
|
||||||
|
}
|
||||||
|
userWallet.isMultiCurrency && !isMultiCurrencyWalletExpected -> {
|
||||||
|
"Single currency wallet expected, but multi currency wallet was found: $userWalletId"
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message != null) {
|
||||||
|
val error = DataError.UserWalletError.WrongUserWallet(message)
|
||||||
|
|
||||||
|
Timber.e(error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getTokensCacheKey(userWalletId: UserWalletId): String = "tokens_cache_key_${userWalletId.stringValue}"
|
private fun getTokensCacheKey(userWalletId: UserWalletId): String = "tokens_cache_key_${userWalletId.stringValue}"
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
|
@ -18,7 +18,10 @@ import com.tangem.utils.extensions.addOrReplace
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
internal class DefaultNetworksRepository(
|
internal class DefaultNetworksRepository(
|
||||||
|
|
@ -44,7 +47,9 @@ internal class DefaultNetworksRepository(
|
||||||
networks: Set<Network.ID>,
|
networks: Set<Network.ID>,
|
||||||
refresh: Boolean,
|
refresh: Boolean,
|
||||||
): Flow<Set<NetworkStatus>> = channelFlow {
|
): Flow<Set<NetworkStatus>> = channelFlow {
|
||||||
networksStatuses.collectLatest(::send)
|
launch(dispatchers.io) {
|
||||||
|
networksStatuses.collect(::send)
|
||||||
|
}
|
||||||
|
|
||||||
launch(dispatchers.io) {
|
launch(dispatchers.io) {
|
||||||
fetchNetworksStatusesIfCacheExpired(userWalletId, networks, refresh)
|
fetchNetworksStatusesIfCacheExpired(userWalletId, networks, refresh)
|
||||||
|
|
@ -99,7 +104,7 @@ internal class DefaultNetworksRepository(
|
||||||
"Unable to find tokens response for user wallet with provided ID: $userWalletId"
|
"Unable to find tokens response for user wallet with provided ID: $userWalletId"
|
||||||
}
|
}
|
||||||
|
|
||||||
return responseCurrenciesFactory.createTokens(response, userWallet.scanResponse.card)
|
return responseCurrenciesFactory.createCurrencies(response, userWallet.scanResponse.card)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNetworksStatusesCacheKey(userWalletId: UserWalletId): String = "network_status_$userWalletId"
|
private fun getNetworksStatusesCacheKey(userWalletId: UserWalletId): String = "network_status_$userWalletId"
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ internal class NetworkStatusFactory {
|
||||||
is CryptoCurrency.Coin -> amounts.singleOrNull { it is CryptoCurrencyAmount.Coin }
|
is CryptoCurrency.Coin -> amounts.singleOrNull { it is CryptoCurrencyAmount.Coin }
|
||||||
is CryptoCurrency.Token -> amounts.singleOrNull {
|
is CryptoCurrency.Token -> amounts.singleOrNull {
|
||||||
it is CryptoCurrencyAmount.Token &&
|
it is CryptoCurrencyAmount.Token &&
|
||||||
it.id == getTokenIdString(currency) &&
|
it.id == getTokenIdString(currency.id) &&
|
||||||
it.tokenContractAddress == currency.contractAddress
|
it.tokenContractAddress == currency.contractAddress
|
||||||
}
|
}
|
||||||
}?.value
|
}?.value
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,23 @@ import com.tangem.blockchain.common.Token as SdkToken
|
||||||
|
|
||||||
internal class ResponseCurrenciesFactory(private val demoConfig: DemoConfig) {
|
internal class ResponseCurrenciesFactory(private val demoConfig: DemoConfig) {
|
||||||
|
|
||||||
fun createTokens(response: UserTokensResponse, card: CardDTO): Set<CryptoCurrency> {
|
fun createCurrency(currencyId: CryptoCurrency.ID, response: UserTokensResponse, card: CardDTO): CryptoCurrency {
|
||||||
return response.tokens.mapNotNull { createToken(it, card) }.toSet()
|
val responseTokenId = getTokenIdString(currencyId)
|
||||||
|
|
||||||
|
val token = requireNotNull(response.tokens.firstOrNull { it.id == responseTokenId }) {
|
||||||
|
"Unable find a token with provided ID: $responseTokenId"
|
||||||
|
}
|
||||||
|
|
||||||
|
return requireNotNull(createCurrency(token, card)) {
|
||||||
|
"Unable to create a currency with provided ID: $currencyId"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createToken(responseToken: UserTokensResponse.Token, card: CardDTO): CryptoCurrency? {
|
fun createCurrencies(response: UserTokensResponse, card: CardDTO): Set<CryptoCurrency> {
|
||||||
|
return response.tokens.mapNotNull { createCurrency(it, card) }.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCurrency(responseToken: UserTokensResponse.Token, card: CardDTO): CryptoCurrency? {
|
||||||
var blockchain = Blockchain.fromNetworkId(responseToken.networkId)
|
var blockchain = Blockchain.fromNetworkId(responseToken.networkId)
|
||||||
if (blockchain == null || blockchain == Blockchain.Unknown) {
|
if (blockchain == null || blockchain == Blockchain.Unknown) {
|
||||||
Timber.e("Unable to find a blockchain with the network ID: ${responseToken.networkId}")
|
Timber.e("Unable to find a blockchain with the network ID: ${responseToken.networkId}")
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,14 @@ internal fun getTokenId(blockchain: Blockchain, token: SdkToken): CryptoCurrency
|
||||||
return getTokenOrCoinId(blockchain, token)
|
return getTokenOrCoinId(blockchain, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun getTokenIdString(currency: CryptoCurrency): String? {
|
internal fun getTokenIdString(currencyId: CryptoCurrency.ID): String? {
|
||||||
return currency.id.value.substringAfter(TOKEN_ID_DELIMITER)
|
val idValue = currencyId.value
|
||||||
.takeUnless { currency is CryptoCurrency.Token && currency.isCustom }
|
|
||||||
|
return if (idValue.startsWith(CUSTOM_TOKEN_ID_PREFIX)) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
idValue.substringAfter(TOKEN_ID_DELIMITER)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun getTokenIconUrl(blockchain: Blockchain, token: SdkToken): String? {
|
internal fun getTokenIconUrl(blockchain: Blockchain, token: SdkToken): String? {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ internal class UserTokensResponseFactory {
|
||||||
val blockchain = getBlockchain(currency.networkId)
|
val blockchain = getBlockchain(currency.networkId)
|
||||||
|
|
||||||
return UserTokensResponse.Token(
|
return UserTokensResponse.Token(
|
||||||
id = getTokenIdString(currency),
|
id = getTokenIdString(currency.id),
|
||||||
networkId = blockchain.toNetworkId(),
|
networkId = blockchain.toNetworkId(),
|
||||||
derivationPath = currency.derivationPath,
|
derivationPath = currency.derivationPath,
|
||||||
name = currency.name,
|
name = currency.name,
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,9 @@ sealed class DataError : Exception() {
|
||||||
|
|
||||||
object NoInternetConnection : NetworkError()
|
object NoInternetConnection : NetworkError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class UserWalletError : DataError() {
|
||||||
|
|
||||||
|
data class WrongUserWallet(override val message: String) : UserWalletError()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,14 +9,14 @@ import arrow.core.toNonEmptySetOrNull
|
||||||
import com.tangem.domain.tokens.error.TokenListSortingError
|
import com.tangem.domain.tokens.error.TokenListSortingError
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
import com.tangem.domain.tokens.models.Network
|
import com.tangem.domain.tokens.models.Network
|
||||||
import com.tangem.domain.tokens.repository.TokensRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class ApplyTokenListSortingUseCase(
|
class ApplyTokenListSortingUseCase(
|
||||||
private val tokensRepository: TokensRepository,
|
private val currenciesRepository: CurrenciesRepository,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
@ -67,7 +67,9 @@ class ApplyTokenListSortingUseCase(
|
||||||
|
|
||||||
private suspend fun Raise<TokenListSortingError>.getCurrencies(userWalletId: UserWalletId): Set<CryptoCurrency> {
|
private suspend fun Raise<TokenListSortingError>.getCurrencies(userWalletId: UserWalletId): Set<CryptoCurrency> {
|
||||||
val tokens = catch(
|
val tokens = catch(
|
||||||
block = { tokensRepository.getMultiCurrencyWalletCurrencies(userWalletId, refresh = false).firstOrNull() },
|
block = {
|
||||||
|
currenciesRepository.getMultiCurrencyWalletCurrencies(userWalletId, refresh = false).firstOrNull()
|
||||||
|
},
|
||||||
catch = { raise(TokenListSortingError.DataError(it)) },
|
catch = { raise(TokenListSortingError.DataError(it)) },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -83,7 +85,7 @@ class ApplyTokenListSortingUseCase(
|
||||||
isSortedByBalance: Boolean,
|
isSortedByBalance: Boolean,
|
||||||
) = withContext(dispatchers.io) {
|
) = withContext(dispatchers.io) {
|
||||||
catch(
|
catch(
|
||||||
block = { tokensRepository.saveTokens(userWalletId, tokens, isGrouped, isSortedByBalance) },
|
block = { currenciesRepository.saveTokens(userWalletId, tokens, isGrouped, isSortedByBalance) },
|
||||||
catch = { raise(TokenListSortingError.DataError(it)) },
|
catch = { raise(TokenListSortingError.DataError(it)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package com.tangem.domain.tokens
|
||||||
|
|
||||||
|
import arrow.core.Either
|
||||||
|
import arrow.core.left
|
||||||
|
import arrow.core.raise.Raise
|
||||||
|
import arrow.core.raise.recover
|
||||||
|
import arrow.core.right
|
||||||
|
import com.tangem.domain.tokens.error.CurrencyError
|
||||||
|
import com.tangem.domain.tokens.error.mapper.mapToTokenError
|
||||||
|
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
|
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||||
|
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||||
|
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.models.UserWalletId
|
||||||
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use case for fetching the status of a specific cryptocurrency associated with a user wallet.
|
||||||
|
*
|
||||||
|
* @property currenciesRepository Repository for managing and fetching cryptocurrencies.
|
||||||
|
* @property quotesRepository Repository for managing and fetching cryptocurrency quotes.
|
||||||
|
* @property networksRepository Repository for managing and fetching information related to blockchain networks.
|
||||||
|
* @property dispatchers Provides coroutine dispatchers.
|
||||||
|
*/
|
||||||
|
class GetCurrencyUseCase(
|
||||||
|
private val currenciesRepository: CurrenciesRepository,
|
||||||
|
private val quotesRepository: QuotesRepository,
|
||||||
|
private val networksRepository: NetworksRepository,
|
||||||
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the use case.
|
||||||
|
*
|
||||||
|
* @param userWalletId The unique identifier of the user's wallet.
|
||||||
|
* @param currencyId The unique identifier of the cryptocurrency.
|
||||||
|
* @param refresh A boolean flag indicating whether the data should be refreshed.
|
||||||
|
* @return A [Flow] emitting either a [CurrencyError] or a [CryptoCurrencyStatus], indicating the result of the fetch operation.
|
||||||
|
*/
|
||||||
|
operator fun invoke(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
currencyId: CryptoCurrency.ID,
|
||||||
|
refresh: Boolean = false,
|
||||||
|
): Flow<Either<CurrencyError, CryptoCurrencyStatus>> {
|
||||||
|
return channelFlow {
|
||||||
|
recover(
|
||||||
|
block = {
|
||||||
|
getCurrency(userWalletId, currencyId, refresh).collectLatest { currencyStatus ->
|
||||||
|
send(currencyStatus.right())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
recover = { error ->
|
||||||
|
send(error.left())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun Raise<CurrencyError>.getCurrency(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
currencyId: CryptoCurrency.ID,
|
||||||
|
refresh: Boolean,
|
||||||
|
): Flow<CryptoCurrencyStatus> {
|
||||||
|
val operations = CurrenciesStatusesOperations(
|
||||||
|
currenciesRepository = currenciesRepository,
|
||||||
|
quotesRepository = quotesRepository,
|
||||||
|
networksRepository = networksRepository,
|
||||||
|
userWalletId = userWalletId,
|
||||||
|
refresh = refresh,
|
||||||
|
dispatchers = dispatchers,
|
||||||
|
raise = this,
|
||||||
|
transformError = CurrenciesStatusesOperations.Error::mapToTokenError,
|
||||||
|
)
|
||||||
|
|
||||||
|
return operations.getCurrencyStatusFlow(currencyId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,35 +5,50 @@ import arrow.core.left
|
||||||
import arrow.core.raise.Raise
|
import arrow.core.raise.Raise
|
||||||
import arrow.core.raise.recover
|
import arrow.core.raise.recover
|
||||||
import arrow.core.right
|
import arrow.core.right
|
||||||
import com.tangem.domain.tokens.error.TokenError
|
import com.tangem.domain.tokens.error.CurrencyError
|
||||||
import com.tangem.domain.tokens.error.mapper.mapToTokenError
|
import com.tangem.domain.tokens.error.mapper.mapToTokenError
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||||
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||||
import com.tangem.domain.tokens.repository.TokensRepository
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.channelFlow
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use case for fetching the status of the primary cryptocurrency associated with a user wallet.
|
||||||
|
*
|
||||||
|
* @property currenciesRepository Repository for managing and fetching cryptocurrencies.
|
||||||
|
* @property quotesRepository Repository for managing and fetching cryptocurrency quotes.
|
||||||
|
* @property networksRepository Repository for managing and fetching information related to blockchain networks.
|
||||||
|
* @property dispatchers Provides coroutine dispatchers.
|
||||||
|
*/
|
||||||
class GetPrimaryCurrencyUseCase(
|
class GetPrimaryCurrencyUseCase(
|
||||||
private val tokensRepository: TokensRepository,
|
private val currenciesRepository: CurrenciesRepository,
|
||||||
private val quotesRepository: QuotesRepository,
|
private val quotesRepository: QuotesRepository,
|
||||||
private val networksRepository: NetworksRepository,
|
private val networksRepository: NetworksRepository,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the use case.
|
||||||
|
*
|
||||||
|
* @param userWalletId The unique identifier of the user's wallet.
|
||||||
|
* @param refresh A boolean flag indicating whether the data should be refreshed.
|
||||||
|
* @return A [Flow] emitting either a [CurrencyError] or a [CryptoCurrencyStatus], indicating the result of the fetch operation.
|
||||||
|
*/
|
||||||
operator fun invoke(
|
operator fun invoke(
|
||||||
userWalletId: UserWalletId,
|
userWalletId: UserWalletId,
|
||||||
refresh: Boolean = false,
|
refresh: Boolean = false,
|
||||||
): Flow<Either<TokenError, CryptoCurrencyStatus>> {
|
): Flow<Either<CurrencyError, CryptoCurrencyStatus>> {
|
||||||
return channelFlow {
|
return channelFlow {
|
||||||
recover(
|
recover(
|
||||||
block = {
|
block = {
|
||||||
getToken(userWalletId, refresh).collectLatest { token ->
|
getCurrency(userWalletId, refresh).collectLatest { currencyStatus ->
|
||||||
send(token.right())
|
send(currencyStatus.right())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
recover = { error ->
|
recover = { error ->
|
||||||
|
|
@ -43,12 +58,12 @@ class GetPrimaryCurrencyUseCase(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun Raise<TokenError>.getToken(
|
private suspend fun Raise<CurrencyError>.getCurrency(
|
||||||
userWalletId: UserWalletId,
|
userWalletId: UserWalletId,
|
||||||
refresh: Boolean,
|
refresh: Boolean,
|
||||||
): Flow<CryptoCurrencyStatus> {
|
): Flow<CryptoCurrencyStatus> {
|
||||||
val operations = CurrenciesStatusesOperations(
|
val operations = CurrenciesStatusesOperations(
|
||||||
tokensRepository = tokensRepository,
|
currenciesRepository = currenciesRepository,
|
||||||
quotesRepository = quotesRepository,
|
quotesRepository = quotesRepository,
|
||||||
networksRepository = networksRepository,
|
networksRepository = networksRepository,
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||||
import com.tangem.domain.tokens.model.TokenList
|
import com.tangem.domain.tokens.model.TokenList
|
||||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||||
import com.tangem.domain.tokens.operations.TokenListOperations
|
import com.tangem.domain.tokens.operations.TokenListOperations
|
||||||
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||||
import com.tangem.domain.tokens.repository.TokensRepository
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
@ -22,7 +22,7 @@ import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.flatMapConcat
|
import kotlinx.coroutines.flow.flatMapConcat
|
||||||
|
|
||||||
class GetTokenListUseCase(
|
class GetTokenListUseCase(
|
||||||
internal val tokensRepository: TokensRepository,
|
internal val currenciesRepository: CurrenciesRepository,
|
||||||
internal val quotesRepository: QuotesRepository,
|
internal val quotesRepository: QuotesRepository,
|
||||||
internal val networksRepository: NetworksRepository,
|
internal val networksRepository: NetworksRepository,
|
||||||
internal val dispatchers: CoroutineDispatcherProvider,
|
internal val dispatchers: CoroutineDispatcherProvider,
|
||||||
|
|
@ -60,7 +60,7 @@ class GetTokenListUseCase(
|
||||||
transformError = CurrenciesStatusesOperations.Error::mapToTokenListError,
|
transformError = CurrenciesStatusesOperations.Error::mapToTokenListError,
|
||||||
)
|
)
|
||||||
|
|
||||||
return operations.getMultiCurrencyWalletStatusesFlow()
|
return operations.getCurrenciesStatusesFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Raise<TokenListError>.createTokenList(
|
private fun Raise<TokenListError>.createTokenList(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.tangem.domain.tokens.error
|
||||||
|
|
||||||
|
sealed class CurrencyError {
|
||||||
|
|
||||||
|
object UnableToCreateCurrency : CurrencyError()
|
||||||
|
|
||||||
|
data class DataError(val cause: Throwable) : CurrencyError()
|
||||||
|
}
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package com.tangem.domain.tokens.error
|
|
||||||
|
|
||||||
sealed class TokenError {
|
|
||||||
|
|
||||||
object UnableToCreateToken : TokenError()
|
|
||||||
|
|
||||||
data class DataError(val cause: Throwable) : TokenError()
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
package com.tangem.domain.tokens.error.mapper
|
package com.tangem.domain.tokens.error.mapper
|
||||||
|
|
||||||
import com.tangem.domain.tokens.error.TokenError
|
import com.tangem.domain.tokens.error.CurrencyError
|
||||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||||
|
|
||||||
internal fun CurrenciesStatusesOperations.Error.mapToTokenError(): TokenError {
|
internal fun CurrenciesStatusesOperations.Error.mapToTokenError(): CurrencyError {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is CurrenciesStatusesOperations.Error.DataError -> TokenError.DataError(this.cause)
|
is CurrenciesStatusesOperations.Error.DataError -> CurrencyError.DataError(this.cause)
|
||||||
is CurrenciesStatusesOperations.Error.EmptyNetworksStatuses,
|
is CurrenciesStatusesOperations.Error.EmptyNetworksStatuses,
|
||||||
is CurrenciesStatusesOperations.Error.EmptyQuotes,
|
is CurrenciesStatusesOperations.Error.EmptyQuotes,
|
||||||
is CurrenciesStatusesOperations.Error.EmptyCurrencies,
|
is CurrenciesStatusesOperations.Error.EmptyCurrencies,
|
||||||
is CurrenciesStatusesOperations.Error.UnableToCreateCurrencyStatus,
|
is CurrenciesStatusesOperations.Error.UnableToCreateCurrencyStatus,
|
||||||
-> TokenError.UnableToCreateToken
|
-> CurrencyError.UnableToCreateCurrency
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,9 +7,9 @@ import com.tangem.domain.core.raise.DelegatedRaise
|
||||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||||
import com.tangem.domain.tokens.model.*
|
import com.tangem.domain.tokens.model.*
|
||||||
import com.tangem.domain.tokens.models.Network
|
import com.tangem.domain.tokens.models.Network
|
||||||
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||||
import com.tangem.domain.tokens.repository.TokensRepository
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
@ -17,7 +17,7 @@ import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
internal class CurrenciesStatusesOperations<E>(
|
internal class CurrenciesStatusesOperations<E>(
|
||||||
private val tokensRepository: TokensRepository,
|
private val currenciesRepository: CurrenciesRepository,
|
||||||
private val quotesRepository: QuotesRepository,
|
private val quotesRepository: QuotesRepository,
|
||||||
private val networksRepository: NetworksRepository,
|
private val networksRepository: NetworksRepository,
|
||||||
private val userWalletId: UserWalletId,
|
private val userWalletId: UserWalletId,
|
||||||
|
|
@ -34,7 +34,7 @@ internal class CurrenciesStatusesOperations<E>(
|
||||||
raise: Raise<E>,
|
raise: Raise<E>,
|
||||||
transformError: (Error) -> E,
|
transformError: (Error) -> E,
|
||||||
) : this(
|
) : this(
|
||||||
tokensRepository = useCase.tokensRepository,
|
currenciesRepository = useCase.currenciesRepository,
|
||||||
quotesRepository = useCase.quotesRepository,
|
quotesRepository = useCase.quotesRepository,
|
||||||
networksRepository = useCase.networksRepository,
|
networksRepository = useCase.networksRepository,
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
|
|
@ -44,7 +44,7 @@ internal class CurrenciesStatusesOperations<E>(
|
||||||
transformError = transformError,
|
transformError = transformError,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getMultiCurrencyWalletStatusesFlow(): Flow<Set<CryptoCurrencyStatus>> {
|
fun getCurrenciesStatusesFlow(): Flow<Set<CryptoCurrencyStatus>> {
|
||||||
return getMultiCurrencyWalletCurrencies().flatMapConcat {
|
return getMultiCurrencyWalletCurrencies().flatMapConcat {
|
||||||
val currencies = it.toNonEmptySetOrNull()
|
val currencies = it.toNonEmptySetOrNull()
|
||||||
|
|
||||||
|
|
@ -68,9 +68,19 @@ internal class CurrenciesStatusesOperations<E>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getCurrencyStatusFlow(currencyId: CryptoCurrency.ID): Flow<CryptoCurrencyStatus> {
|
||||||
|
val currency = getMultiCurrencyWalletCurrency(currencyId)
|
||||||
|
|
||||||
|
return getCurrencyStatusFlow(currency)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun getPrimaryCurrencyStatusFlow(): Flow<CryptoCurrencyStatus> {
|
suspend fun getPrimaryCurrencyStatusFlow(): Flow<CryptoCurrencyStatus> {
|
||||||
val currency = getPrimaryCurrency()
|
val currency = getPrimaryCurrency()
|
||||||
|
|
||||||
|
return getCurrencyStatusFlow(currency)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCurrencyStatusFlow(currency: CryptoCurrency): Flow<CryptoCurrencyStatus> {
|
||||||
val quoteFlow = getQuotes(nonEmptySetOf(currency.id))
|
val quoteFlow = getQuotes(nonEmptySetOf(currency.id))
|
||||||
.map { quotes ->
|
.map { quotes ->
|
||||||
quotes.singleOrNull { it.currencyId == currency.id }
|
quotes.singleOrNull { it.currencyId == currency.id }
|
||||||
|
|
@ -116,34 +126,36 @@ internal class CurrenciesStatusesOperations<E>(
|
||||||
return currencyStatusOperations.createTokenStatus()
|
return currencyStatusOperations.createTokenStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun getMultiCurrencyWalletCurrency(currencyId: CryptoCurrency.ID): CryptoCurrency {
|
||||||
|
return catch(
|
||||||
|
block = { currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, currencyId) },
|
||||||
|
catch = { raise(Error.DataError(it)) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getMultiCurrencyWalletCurrencies(): Flow<Set<CryptoCurrency>> {
|
private fun getMultiCurrencyWalletCurrencies(): Flow<Set<CryptoCurrency>> {
|
||||||
return tokensRepository.getMultiCurrencyWalletCurrencies(userWalletId, refresh)
|
return currenciesRepository.getMultiCurrencyWalletCurrencies(userWalletId, refresh)
|
||||||
.catch { raise(Error.DataError(it)) }
|
.catch { raise(Error.DataError(it)) }
|
||||||
.onEmpty { raise(Error.EmptyCurrencies) }
|
.onEmpty { raise(Error.EmptyCurrencies) }
|
||||||
.flowOn(dispatchers.io)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getPrimaryCurrency(): CryptoCurrency {
|
private suspend fun getPrimaryCurrency(): CryptoCurrency {
|
||||||
return withContext(dispatchers.io) {
|
return catch(
|
||||||
catch(
|
block = { currenciesRepository.getSingleCurrencyWalletPrimaryCurrency(userWalletId) },
|
||||||
block = { tokensRepository.getPrimaryCurrency(userWalletId) },
|
catch = { raise(Error.DataError(it)) },
|
||||||
catch = { raise(Error.DataError(it)) },
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getQuotes(tokensIds: NonEmptySet<CryptoCurrency.ID>): Flow<Set<Quote>> {
|
private fun getQuotes(tokensIds: NonEmptySet<CryptoCurrency.ID>): Flow<Set<Quote>> {
|
||||||
return quotesRepository.getQuotes(tokensIds, refresh)
|
return quotesRepository.getQuotes(tokensIds, refresh)
|
||||||
.catch { raise(Error.DataError(it)) }
|
.catch { raise(Error.DataError(it)) }
|
||||||
.onEmpty { raise(Error.EmptyQuotes) }
|
.onEmpty { raise(Error.EmptyQuotes) }
|
||||||
.flowOn(dispatchers.io)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNetworksStatues(networks: NonEmptySet<Network.ID>): Flow<Set<NetworkStatus>> {
|
private fun getNetworksStatues(networks: NonEmptySet<Network.ID>): Flow<Set<NetworkStatus>> {
|
||||||
return networksRepository.getNetworkStatuses(userWalletId, networks, refresh)
|
return networksRepository.getNetworkStatuses(userWalletId, networks, refresh)
|
||||||
.catch { raise(Error.DataError(it)) }
|
.catch { raise(Error.DataError(it)) }
|
||||||
.onEmpty { raise(Error.EmptyNetworksStatuses) }
|
.onEmpty { raise(Error.EmptyNetworksStatuses) }
|
||||||
.flowOn(dispatchers.io)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class Error {
|
sealed class Error {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import com.tangem.domain.tokens.GetTokenListUseCase
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||||
import com.tangem.domain.tokens.model.TokenList
|
import com.tangem.domain.tokens.model.TokenList
|
||||||
import com.tangem.domain.tokens.models.Network
|
import com.tangem.domain.tokens.models.Network
|
||||||
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||||
import com.tangem.domain.tokens.repository.TokensRepository
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
@ -19,7 +19,7 @@ import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
internal class TokenListOperations<E>(
|
internal class TokenListOperations<E>(
|
||||||
private val tokensRepository: TokensRepository,
|
private val currenciesRepository: CurrenciesRepository,
|
||||||
private val networksRepository: NetworksRepository,
|
private val networksRepository: NetworksRepository,
|
||||||
private val userWalletId: UserWalletId,
|
private val userWalletId: UserWalletId,
|
||||||
private val tokens: Set<CryptoCurrencyStatus>,
|
private val tokens: Set<CryptoCurrencyStatus>,
|
||||||
|
|
@ -35,7 +35,7 @@ internal class TokenListOperations<E>(
|
||||||
raise: Raise<E>,
|
raise: Raise<E>,
|
||||||
transform: (Error) -> E,
|
transform: (Error) -> E,
|
||||||
) : this(
|
) : this(
|
||||||
tokensRepository = useCase.tokensRepository,
|
currenciesRepository = useCase.currenciesRepository,
|
||||||
networksRepository = useCase.networksRepository,
|
networksRepository = useCase.networksRepository,
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
tokens = tokens,
|
tokens = tokens,
|
||||||
|
|
@ -149,14 +149,14 @@ internal class TokenListOperations<E>(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getIsGrouped(): Flow<Boolean> {
|
private fun getIsGrouped(): Flow<Boolean> {
|
||||||
return tokensRepository.isTokensGrouped(userWalletId)
|
return currenciesRepository.isTokensGrouped(userWalletId)
|
||||||
.catch { raise(Error.DataError(it)) }
|
.catch { raise(Error.DataError(it)) }
|
||||||
.onEmpty { emit(value = false) }
|
.onEmpty { emit(value = false) }
|
||||||
.flowOn(dispatchers.io)
|
.flowOn(dispatchers.io)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getIsSortedByBalance(): Flow<Boolean> {
|
private fun getIsSortedByBalance(): Flow<Boolean> {
|
||||||
return tokensRepository.isTokensSortedByBalance(userWalletId)
|
return currenciesRepository.isTokensSortedByBalance(userWalletId)
|
||||||
.catch { raise(Error.DataError(it)) }
|
.catch { raise(Error.DataError(it)) }
|
||||||
.onEmpty { emit(value = false) }
|
.onEmpty { emit(value = false) }
|
||||||
.flowOn(dispatchers.io)
|
.flowOn(dispatchers.io)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow
|
||||||
/**
|
/**
|
||||||
* Repository for everything related to the tokens of user wallet
|
* Repository for everything related to the tokens of user wallet
|
||||||
* */
|
* */
|
||||||
interface TokensRepository {
|
interface CurrenciesRepository {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the given set of cryptocurrencies, along with the preferences for grouping and sorting, for a specific
|
* Saves the given set of cryptocurrencies, along with the preferences for grouping and sorting, for a specific
|
||||||
|
|
@ -17,6 +17,8 @@ interface TokensRepository {
|
||||||
* @param currencies The set of cryptocurrencies to be saved.
|
* @param currencies The set of cryptocurrencies to be saved.
|
||||||
* @param isGroupedByNetwork A boolean flag indicating whether the tokens should be grouped by network.
|
* @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.
|
* @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
|
||||||
|
* ID provided.
|
||||||
*/
|
*/
|
||||||
suspend fun saveTokens(
|
suspend fun saveTokens(
|
||||||
userWalletId: UserWalletId,
|
userWalletId: UserWalletId,
|
||||||
|
|
@ -30,8 +32,10 @@ interface TokensRepository {
|
||||||
*
|
*
|
||||||
* @param userWalletId The unique identifier of the user wallet.
|
* @param userWalletId The unique identifier of the user wallet.
|
||||||
* @return The primary cryptocurrency associated with 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
|
||||||
|
* ID provided.
|
||||||
*/
|
*/
|
||||||
suspend fun getPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency
|
suspend fun getSingleCurrencyWalletPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the set of cryptocurrencies within a multi-currency wallet.
|
* Retrieves the set of cryptocurrencies within a multi-currency wallet.
|
||||||
|
|
@ -39,14 +43,29 @@ interface TokensRepository {
|
||||||
* @param userWalletId The unique identifier of the user wallet.
|
* @param userWalletId The unique identifier of the user wallet.
|
||||||
* @param refresh A boolean flag indicating whether the data should be refreshed.
|
* @param refresh A boolean flag indicating whether the data should be refreshed.
|
||||||
* @return A [Flow] emitting the set of cryptocurrencies associated with 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
|
||||||
|
* ID provided.
|
||||||
*/
|
*/
|
||||||
fun getMultiCurrencyWalletCurrencies(userWalletId: UserWalletId, refresh: Boolean): Flow<Set<CryptoCurrency>>
|
fun getMultiCurrencyWalletCurrencies(userWalletId: UserWalletId, refresh: Boolean): Flow<Set<CryptoCurrency>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the cryptocurrency for a specific multi-currency user wallet.
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* ID provided.
|
||||||
|
*/
|
||||||
|
suspend fun getMultiCurrencyWalletCurrency(userWalletId: UserWalletId, id: CryptoCurrency.ID): CryptoCurrency
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the tokens within a specific multi-currency user wallet are grouped.
|
* Determines whether the tokens within a specific multi-currency user wallet are grouped.
|
||||||
*
|
*
|
||||||
* @param userWalletId The unique identifier of the user wallet.
|
* @param userWalletId The unique identifier of the user wallet.
|
||||||
* @return A [Flow] emitting a boolean value indicating whether the tokens are grouped.
|
* @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
|
||||||
|
* ID provided.
|
||||||
*/
|
*/
|
||||||
fun isTokensGrouped(userWalletId: UserWalletId): Flow<Boolean>
|
fun isTokensGrouped(userWalletId: UserWalletId): Flow<Boolean>
|
||||||
|
|
||||||
|
|
@ -55,6 +74,8 @@ interface TokensRepository {
|
||||||
*
|
*
|
||||||
* @param userWalletId The unique identifier of the user wallet.
|
* @param userWalletId The unique identifier of the user wallet.
|
||||||
* @return A [Flow] emitting a boolean value indicating whether the tokens are sorted by balance.
|
* @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
|
||||||
|
* ID provided.
|
||||||
*/
|
*/
|
||||||
fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow<Boolean>
|
fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow<Boolean>
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ import com.tangem.domain.core.error.DataError
|
||||||
import com.tangem.domain.tokens.error.TokenListSortingError
|
import com.tangem.domain.tokens.error.TokenListSortingError
|
||||||
import com.tangem.domain.tokens.mock.MockTokens
|
import com.tangem.domain.tokens.mock.MockTokens
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
import com.tangem.domain.tokens.repository.MockTokensRepository
|
import com.tangem.domain.tokens.repository.MockCurrenciesRepository
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||||
import junit.framework.TestCase.assertEquals
|
import junit.framework.TestCase.assertEquals
|
||||||
|
|
@ -183,16 +183,16 @@ internal class ApplyTokenListSortingUseCaseTest {
|
||||||
.sortedBy { Random.nextInt(0, MockTokens.tokens.size) }
|
.sortedBy { Random.nextInt(0, MockTokens.tokens.size) }
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
private fun getUseCase(tokensRepository: MockTokensRepository = getTokensRepository()) =
|
private fun getUseCase(tokensRepository: MockCurrenciesRepository = getTokensRepository()) =
|
||||||
ApplyTokenListSortingUseCase(
|
ApplyTokenListSortingUseCase(
|
||||||
tokensRepository = tokensRepository,
|
currenciesRepository = tokensRepository,
|
||||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getTokensRepository(
|
private fun getTokensRepository(
|
||||||
sortTokensResult: Either<DataError, Unit> = Unit.right(),
|
sortTokensResult: Either<DataError, Unit> = Unit.right(),
|
||||||
tokens: Flow<Either<DataError, Set<CryptoCurrency>>> = flowOf(MockTokens.tokens.right()),
|
tokens: Flow<Either<DataError, Set<CryptoCurrency>>> = flowOf(MockTokens.tokens.right()),
|
||||||
): MockTokensRepository {
|
): MockCurrenciesRepository {
|
||||||
return MockTokensRepository(sortTokensResult, MockTokens.token1.right(), tokens, emptyFlow(), emptyFlow())
|
return MockCurrenciesRepository(sortTokensResult, MockTokens.token1.right(), tokens, emptyFlow(), emptyFlow())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ import arrow.core.Either
|
||||||
import arrow.core.left
|
import arrow.core.left
|
||||||
import arrow.core.right
|
import arrow.core.right
|
||||||
import com.tangem.domain.core.error.DataError
|
import com.tangem.domain.core.error.DataError
|
||||||
import com.tangem.domain.tokens.error.TokenError
|
import com.tangem.domain.tokens.error.CurrencyError
|
||||||
import com.tangem.domain.tokens.mock.MockNetworks
|
import com.tangem.domain.tokens.mock.MockNetworks
|
||||||
import com.tangem.domain.tokens.mock.MockQuotes
|
import com.tangem.domain.tokens.mock.MockQuotes
|
||||||
import com.tangem.domain.tokens.mock.MockTokens
|
import com.tangem.domain.tokens.mock.MockTokens
|
||||||
|
|
@ -13,9 +13,9 @@ import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||||
import com.tangem.domain.tokens.model.NetworkStatus
|
import com.tangem.domain.tokens.model.NetworkStatus
|
||||||
import com.tangem.domain.tokens.model.Quote
|
import com.tangem.domain.tokens.model.Quote
|
||||||
|
import com.tangem.domain.tokens.repository.MockCurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.MockNetworksRepository
|
import com.tangem.domain.tokens.repository.MockNetworksRepository
|
||||||
import com.tangem.domain.tokens.repository.MockQuotesRepository
|
import com.tangem.domain.tokens.repository.MockQuotesRepository
|
||||||
import com.tangem.domain.tokens.repository.MockTokensRepository
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||||
import junit.framework.TestCase.assertEquals
|
import junit.framework.TestCase.assertEquals
|
||||||
|
|
@ -47,7 +47,7 @@ internal class GetPrimaryCurrencyUseCaseTest {
|
||||||
@Test
|
@Test
|
||||||
fun `when token getting failed then error should be received`() = runTest {
|
fun `when token getting failed then error should be received`() = runTest {
|
||||||
// Given
|
// Given
|
||||||
val expectedResult = TokenError.DataError(DataError.NetworkError.NoInternetConnection).left()
|
val expectedResult = CurrencyError.DataError(DataError.NetworkError.NoInternetConnection).left()
|
||||||
|
|
||||||
val useCase = getUseCase(token = DataError.NetworkError.NoInternetConnection.left())
|
val useCase = getUseCase(token = DataError.NetworkError.NoInternetConnection.left())
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ internal class GetPrimaryCurrencyUseCaseTest {
|
||||||
@Test
|
@Test
|
||||||
fun `when quotes getting failed then error should be received`() = runTest {
|
fun `when quotes getting failed then error should be received`() = runTest {
|
||||||
// Given
|
// Given
|
||||||
val expectedResult = TokenError.DataError(DataError.NetworkError.NoInternetConnection).left()
|
val expectedResult = CurrencyError.DataError(DataError.NetworkError.NoInternetConnection).left()
|
||||||
|
|
||||||
val useCase = getUseCase(quotes = flowOf(DataError.NetworkError.NoInternetConnection.left()))
|
val useCase = getUseCase(quotes = flowOf(DataError.NetworkError.NoInternetConnection.left()))
|
||||||
|
|
||||||
|
|
@ -75,7 +75,7 @@ internal class GetPrimaryCurrencyUseCaseTest {
|
||||||
@Test
|
@Test
|
||||||
fun `when networks statuses getting failed then error should be received`() = runTest {
|
fun `when networks statuses getting failed then error should be received`() = runTest {
|
||||||
// Given
|
// Given
|
||||||
val expectedResult = TokenError.DataError(DataError.NetworkError.NoInternetConnection).left()
|
val expectedResult = CurrencyError.DataError(DataError.NetworkError.NoInternetConnection).left()
|
||||||
|
|
||||||
val useCase = getUseCase(statuses = flowOf(DataError.NetworkError.NoInternetConnection.left()))
|
val useCase = getUseCase(statuses = flowOf(DataError.NetworkError.NoInternetConnection.left()))
|
||||||
|
|
||||||
|
|
@ -88,7 +88,7 @@ internal class GetPrimaryCurrencyUseCaseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when networks statuses flow is empty then error should be received`() = runTest {
|
fun `when networks statuses flow is empty then error should be received`() = runTest {
|
||||||
val expectedResult = TokenError.UnableToCreateToken.left()
|
val expectedResult = CurrencyError.UnableToCreateCurrency.left()
|
||||||
|
|
||||||
val useCase = getUseCase(statuses = flowOf())
|
val useCase = getUseCase(statuses = flowOf())
|
||||||
|
|
||||||
|
|
@ -101,7 +101,7 @@ internal class GetPrimaryCurrencyUseCaseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when quotes flow is empty then error should be received`() = runTest {
|
fun `when quotes flow is empty then error should be received`() = runTest {
|
||||||
val expectedResult = TokenError.UnableToCreateToken.left()
|
val expectedResult = CurrencyError.UnableToCreateCurrency.left()
|
||||||
|
|
||||||
val useCase = getUseCase(quotes = flowOf())
|
val useCase = getUseCase(quotes = flowOf())
|
||||||
|
|
||||||
|
|
@ -154,7 +154,7 @@ internal class GetPrimaryCurrencyUseCaseTest {
|
||||||
statuses: Flow<Either<DataError, Set<NetworkStatus>>> = flowOf(MockNetworks.verifiedNetworksStatuses.right()),
|
statuses: Flow<Either<DataError, Set<NetworkStatus>>> = flowOf(MockNetworks.verifiedNetworksStatuses.right()),
|
||||||
) = GetPrimaryCurrencyUseCase(
|
) = GetPrimaryCurrencyUseCase(
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
tokensRepository = MockTokensRepository(
|
currenciesRepository = MockCurrenciesRepository(
|
||||||
sortTokensResult = Unit.right(),
|
sortTokensResult = Unit.right(),
|
||||||
token = token,
|
token = token,
|
||||||
tokens = flowOf(),
|
tokens = flowOf(),
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ import com.tangem.domain.tokens.model.CryptoCurrency
|
||||||
import com.tangem.domain.tokens.model.NetworkStatus
|
import com.tangem.domain.tokens.model.NetworkStatus
|
||||||
import com.tangem.domain.tokens.model.Quote
|
import com.tangem.domain.tokens.model.Quote
|
||||||
import com.tangem.domain.tokens.models.Network
|
import com.tangem.domain.tokens.models.Network
|
||||||
|
import com.tangem.domain.tokens.repository.MockCurrenciesRepository
|
||||||
import com.tangem.domain.tokens.repository.MockNetworksRepository
|
import com.tangem.domain.tokens.repository.MockNetworksRepository
|
||||||
import com.tangem.domain.tokens.repository.MockQuotesRepository
|
import com.tangem.domain.tokens.repository.MockQuotesRepository
|
||||||
import com.tangem.domain.tokens.repository.MockTokensRepository
|
|
||||||
import com.tangem.domain.wallets.models.UserWalletId
|
import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||||
import junit.framework.TestCase.assertEquals
|
import junit.framework.TestCase.assertEquals
|
||||||
|
|
@ -326,7 +326,7 @@ internal class GetTokenListUseCaseTest {
|
||||||
isSortedByBalance: Flow<Either<DataError, Boolean>> = flowOf(MockTokenLists.isSortedByBalance.right()),
|
isSortedByBalance: Flow<Either<DataError, Boolean>> = flowOf(MockTokenLists.isSortedByBalance.right()),
|
||||||
) = GetTokenListUseCase(
|
) = GetTokenListUseCase(
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
tokensRepository = MockTokensRepository(
|
currenciesRepository = MockCurrenciesRepository(
|
||||||
sortTokensResult = Unit.right(),
|
sortTokensResult = Unit.right(),
|
||||||
token = MockTokens.token1.right(),
|
token = MockTokens.token1.right(),
|
||||||
tokens = tokens,
|
tokens = tokens,
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ import com.tangem.domain.wallets.models.UserWalletId
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
internal class MockTokensRepository(
|
internal class MockCurrenciesRepository(
|
||||||
private val sortTokensResult: Either<DataError, Unit>,
|
private val sortTokensResult: Either<DataError, Unit>,
|
||||||
private val token: Either<DataError, CryptoCurrency>,
|
private val token: Either<DataError, CryptoCurrency>,
|
||||||
private val tokens: Flow<Either<DataError, Set<CryptoCurrency>>>,
|
private val tokens: Flow<Either<DataError, Set<CryptoCurrency>>>,
|
||||||
private val isGrouped: Flow<Either<DataError, Boolean>>,
|
private val isGrouped: Flow<Either<DataError, Boolean>>,
|
||||||
private val isSortedByBalance: Flow<Either<DataError, Boolean>>,
|
private val isSortedByBalance: Flow<Either<DataError, Boolean>>,
|
||||||
) : TokensRepository {
|
) : CurrenciesRepository {
|
||||||
|
|
||||||
var tokensIdsAfterSortingApply: Set<CryptoCurrency>? = null
|
var tokensIdsAfterSortingApply: Set<CryptoCurrency>? = null
|
||||||
private set
|
private set
|
||||||
|
|
@ -38,7 +38,7 @@ internal class MockTokensRepository(
|
||||||
isTokensSortedByBalanceAfterSortingApply = isSortedByBalance
|
isTokensSortedByBalanceAfterSortingApply = isSortedByBalance
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency {
|
override suspend fun getSingleCurrencyWalletPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency {
|
||||||
return token.getOrElse { e -> throw e }
|
return token.getOrElse { e -> throw e }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,6 +49,17 @@ internal class MockTokensRepository(
|
||||||
return tokens.map { it.getOrElse { e -> throw e } }
|
return tokens.map { it.getOrElse { e -> throw e } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getMultiCurrencyWalletCurrency(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
id: CryptoCurrency.ID,
|
||||||
|
): CryptoCurrency {
|
||||||
|
val token = token.getOrElse { e -> throw e }
|
||||||
|
|
||||||
|
require(token.id == id)
|
||||||
|
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
override fun isTokensGrouped(userWalletId: UserWalletId): Flow<Boolean> {
|
override fun isTokensGrouped(userWalletId: UserWalletId): Flow<Boolean> {
|
||||||
return isGrouped.map { it.getOrElse { e -> throw e } }
|
return isGrouped.map { it.getOrElse { e -> throw e } }
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue