Updated on 2026-08-14
This commit is contained in:
parent
85b000a850
commit
a0ef13e0cf
12 changed files with 278 additions and 60 deletions
|
|
@ -93,13 +93,15 @@ internal object TokensDomainModule {
|
|||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): GetCurrencyStatusUpdatesUseCase {
|
||||
return GetCurrencyStatusUpdatesUseCase(
|
||||
currenciesRepository,
|
||||
quotesRepository,
|
||||
networksRepository,
|
||||
stakingRepository,
|
||||
dispatchers,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
dispatchers = dispatchers,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -131,6 +133,7 @@ internal object TokensDomainModule {
|
|||
currencyChecksRepository: CurrencyChecksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): GetCurrencyWarningsUseCase {
|
||||
return GetCurrencyWarningsUseCase(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
|
|
@ -140,6 +143,7 @@ internal object TokensDomainModule {
|
|||
currencyChecksRepository = currencyChecksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
dispatchers = dispatchers,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -363,12 +367,14 @@ internal object TokensDomainModule {
|
|||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): GetWalletTotalBalanceUseCase {
|
||||
return GetWalletTotalBalanceUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,14 +46,6 @@ internal class DefaultNetworksStatusesStore(
|
|||
|
||||
if (cachedStatuses.isNotEmpty()) {
|
||||
send(cachedStatuses)
|
||||
|
||||
/**
|
||||
* Required for storing cache data.
|
||||
* This will help to recognize networks that are still uploaded.
|
||||
*
|
||||
* @see mergeStatuses
|
||||
*/
|
||||
storeAll(key = key, values = cachedStatuses)
|
||||
}
|
||||
|
||||
runtimeDataStore.get(provideStringKey(key))
|
||||
|
|
@ -118,8 +110,18 @@ internal class DefaultNetworksStatusesStore(
|
|||
return networks.mapNotNullTo(hashSetOf()) { network ->
|
||||
val runtimeStatus = runtimeStatuses.firstOrNull { it.network == network }
|
||||
|
||||
if (runtimeStatus == null || runtimeStatus.value is NetworkStatus.Unreachable) {
|
||||
getCachedStatusIfPossible(cachedStatuses = cachedStatuses, network = network)
|
||||
if (runtimeStatus == null) {
|
||||
getCachedStatusIfPossible(
|
||||
cachedStatuses = cachedStatuses,
|
||||
network = network,
|
||||
source = StatusSource.CACHE,
|
||||
)
|
||||
} else if (runtimeStatus.value is NetworkStatus.Unreachable) {
|
||||
getCachedStatusIfPossible(
|
||||
cachedStatuses = cachedStatuses,
|
||||
network = network,
|
||||
source = StatusSource.ONLY_CACHE,
|
||||
)
|
||||
?: runtimeStatus
|
||||
} else {
|
||||
runtimeStatus
|
||||
|
|
@ -127,12 +129,16 @@ internal class DefaultNetworksStatusesStore(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getCachedStatusIfPossible(cachedStatuses: Set<NetworkStatus>, network: Network): NetworkStatus? {
|
||||
private fun getCachedStatusIfPossible(
|
||||
cachedStatuses: Set<NetworkStatus>,
|
||||
network: Network,
|
||||
source: StatusSource,
|
||||
): NetworkStatus? {
|
||||
val cached = cachedStatuses.firstOrNull { it.network == network } ?: return null
|
||||
|
||||
val updatedCachedStatus = when (val status = cached.value) {
|
||||
is NetworkStatus.NoAccount -> status.copy(source = StatusSource.ONLY_CACHE)
|
||||
is NetworkStatus.Verified -> status.copy(source = StatusSource.ONLY_CACHE)
|
||||
is NetworkStatus.NoAccount -> status.copy(source = source)
|
||||
is NetworkStatus.Verified -> status.copy(source = source)
|
||||
is NetworkStatus.Unreachable,
|
||||
is NetworkStatus.MissedDerivation,
|
||||
-> null
|
||||
|
|
|
|||
|
|
@ -59,4 +59,6 @@ sealed class CryptoCurrencyWarning {
|
|||
) : CryptoCurrencyWarning()
|
||||
|
||||
data object TokensInBetaWarning : CryptoCurrencyWarning()
|
||||
|
||||
data object UsedOutdatedDataWarning : CryptoCurrencyWarning()
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.tokens.error.CurrencyStatusError
|
|||
import com.tangem.domain.tokens.error.mapper.mapToCurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
|
|
@ -27,6 +28,7 @@ class GetCurrencyStatusUpdatesUseCase(
|
|||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
) {
|
||||
|
||||
/**
|
||||
|
|
@ -58,18 +60,27 @@ class GetCurrencyStatusUpdatesUseCase(
|
|||
currencyId: CryptoCurrency.ID,
|
||||
isSingleWalletWithTokens: Boolean,
|
||||
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
|
||||
val currencyFlow = if (isSingleWalletWithTokens) {
|
||||
operations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId)
|
||||
val currencyFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
CurrenciesStatusesCachedOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
).getCurrencyStatusFlow(userWalletId, currencyId)
|
||||
} else {
|
||||
operations.getCurrencyStatusFlow(currencyId)
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
|
||||
if (isSingleWalletWithTokens) {
|
||||
operations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId)
|
||||
} else {
|
||||
operations.getCurrencyStatusFlow(currencyId)
|
||||
}
|
||||
}
|
||||
return currencyFlow.map { maybeCurrency ->
|
||||
maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
||||
import com.tangem.domain.tokens.model.warnings.HederaWarnings
|
||||
import com.tangem.domain.tokens.model.warnings.KaspaWarnings
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
|
|
@ -27,6 +29,7 @@ class GetCurrencyWarningsUseCase(
|
|||
private val stakingRepository: StakingRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val currencyChecksRepository: CurrencyChecksRepository,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
|
|
@ -36,18 +39,11 @@ class GetCurrencyWarningsUseCase(
|
|||
isSingleWalletWithTokens: Boolean,
|
||||
): Flow<Set<CryptoCurrencyWarning>> {
|
||||
val currency = currencyStatus.currency
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
|
||||
// don't add here notifications that require async requests
|
||||
return combine(
|
||||
getCoinRelatedWarnings(
|
||||
userWalletId = userWalletId,
|
||||
operations = operations,
|
||||
networkId = currency.network.id,
|
||||
currencyId = currency.id,
|
||||
derivationPath = derivationPath,
|
||||
|
|
@ -74,22 +70,50 @@ class GetCurrencyWarningsUseCase(
|
|||
@Suppress("LongParameterList")
|
||||
private suspend fun getCoinRelatedWarnings(
|
||||
userWalletId: UserWalletId,
|
||||
operations: CurrenciesStatusesOperations,
|
||||
networkId: Network.ID,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
isSingleWalletWithTokens: Boolean,
|
||||
): Flow<List<CryptoCurrencyWarning>> {
|
||||
val currencyFlow = if (isSingleWalletWithTokens) {
|
||||
operations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId)
|
||||
} else {
|
||||
operations.getCurrencyStatusFlow(currencyId)
|
||||
val cachedOperations by lazy {
|
||||
CurrenciesStatusesCachedOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
}
|
||||
val networkFlow = if (isSingleWalletWithTokens) {
|
||||
operations.getNetworkCoinForSingleWalletWithTokenFlow(networkId)
|
||||
} else {
|
||||
operations.getNetworkCoinFlow(networkId, derivationPath)
|
||||
|
||||
val lceOperations by lazy {
|
||||
CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
}
|
||||
|
||||
val currencyFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
cachedOperations.getCurrencyStatusFlow(userWalletId, currencyId)
|
||||
} else {
|
||||
if (isSingleWalletWithTokens) {
|
||||
lceOperations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId)
|
||||
} else {
|
||||
lceOperations.getCurrencyStatusFlow(currencyId)
|
||||
}
|
||||
}
|
||||
|
||||
val networkFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
cachedOperations.getNetworkCoinFlow(userWalletId, networkId, derivationPath)
|
||||
} else {
|
||||
if (isSingleWalletWithTokens) {
|
||||
lceOperations.getNetworkCoinForSingleWalletWithTokenFlow(networkId)
|
||||
} else {
|
||||
lceOperations.getNetworkCoinFlow(networkId, derivationPath)
|
||||
}
|
||||
}
|
||||
|
||||
return combine(
|
||||
currencyFlow.map { it.getOrNull() },
|
||||
networkFlow.map { it.getOrNull() },
|
||||
|
|
@ -97,6 +121,7 @@ class GetCurrencyWarningsUseCase(
|
|||
when {
|
||||
tokenStatus != null && coinStatus != null -> {
|
||||
buildList {
|
||||
getUsedOutdatedDataWarning(tokenStatus)?.let(::add)
|
||||
getIsBetaTokensWarning(tokenStatus.currency)?.let(::add)
|
||||
getFeeWarning(
|
||||
userWalletId = userWalletId,
|
||||
|
|
@ -144,6 +169,10 @@ class GetCurrencyWarningsUseCase(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getUsedOutdatedDataWarning(status: CryptoCurrencyStatus): CryptoCurrencyWarning? {
|
||||
return CryptoCurrencyWarning.UsedOutdatedDataWarning.takeIf { status.value.source == StatusSource.ONLY_CACHE }
|
||||
}
|
||||
|
||||
private fun getIsBetaTokensWarning(currency: CryptoCurrency): CryptoCurrencyWarning? {
|
||||
val isTokenBetaFunctionality = BlockchainUtils.isTokenBetaFunctionality(currency.network.id.value)
|
||||
return if (currency is CryptoCurrency.Token && isTokenBetaFunctionality) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.staking.repositories.StakingRepository
|
|||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TotalFiatBalance
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesLceOperations
|
||||
import com.tangem.domain.tokens.operations.TokenListFiatBalanceOperations
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
|
|
@ -28,6 +29,7 @@ class GetWalletTotalBalanceUseCase(
|
|||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
) {
|
||||
|
||||
operator fun invoke(
|
||||
|
|
@ -86,13 +88,20 @@ class GetWalletTotalBalanceUseCase(
|
|||
}
|
||||
|
||||
private fun getStatuses(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
|
||||
val operations = CurrenciesStatusesLceOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
|
||||
return operations.getCurrenciesStatuses(userWalletId)
|
||||
return if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
CurrenciesStatusesCachedOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
).getCurrenciesStatuses(userWalletId)
|
||||
} else {
|
||||
CurrenciesStatusesLceOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
).getCurrenciesStatuses(userWalletId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
package com.tangem.domain.tokens.operations
|
||||
|
||||
import arrow.core.*
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.ensureNotNull
|
||||
import arrow.core.raise.recover
|
||||
import arrow.core.raise.*
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.core.lce.lce
|
||||
|
|
@ -15,6 +12,7 @@ import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
|||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
|
|
@ -22,6 +20,7 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
@Suppress("LargeClass")
|
||||
internal class CurrenciesStatusesCachedOperations(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
|
|
@ -36,6 +35,89 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
)
|
||||
}
|
||||
|
||||
suspend fun getCurrencyStatusFlow(
|
||||
userWalletId: UserWalletId,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getMultiCurrencyWalletCurrency(userWalletId = userWalletId, currencyId = currencyId) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(userWalletId = userWalletId, currency = currency, includeQuotes = includeQuotes)
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinFlow(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
|
||||
val currency = recover(
|
||||
block = {
|
||||
with(operations) { getNetworkCoin(networkId, derivationPath) }
|
||||
},
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(userWalletId, currency, includeQuotes)
|
||||
}
|
||||
|
||||
private fun getCurrencyStatusFlow(
|
||||
userWalletId: UserWalletId,
|
||||
currency: CryptoCurrency,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val rawCurrencyId = currency.id.rawCurrencyId
|
||||
|
||||
val quoteFlow = if (includeQuotes && rawCurrencyId != null) {
|
||||
getQuotes(rawCurrencyId)
|
||||
.map { maybeQuotes ->
|
||||
maybeQuotes.flatMap { quotes ->
|
||||
quotes.singleOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }?.right()
|
||||
?: Error.EmptyQuotes.left()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// don't use emptyFlow()
|
||||
flow { emit(Error.EmptyQuotes.left()) }
|
||||
}
|
||||
|
||||
val statusFlow = getNetworksStatuses(userWalletId = userWalletId, network = currency.network)
|
||||
.map { maybeStatuses ->
|
||||
maybeStatuses.flatMap { statuses ->
|
||||
statuses.singleOrNull { it.network == currency.network }?.right()
|
||||
?: Error.EmptyNetworksStatuses.left()
|
||||
}
|
||||
}
|
||||
|
||||
val yieldBalanceFlow = getYieldBalance(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||
|
||||
return combine(quoteFlow, statusFlow, yieldBalanceFlow) { maybeQuote, maybeNetworkStatus, maybeYieldBalance ->
|
||||
createCurrencyStatus(currency, maybeQuote, maybeNetworkStatus, maybeYieldBalance)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getMultiCurrencyWalletCurrency(
|
||||
userWalletId: UserWalletId,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
): CryptoCurrency {
|
||||
return Either.catch {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId = userWalletId, id = currencyId)
|
||||
}
|
||||
.mapLeft { Error.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private fun transformToCurrenciesStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
currenciesFlow: EitherFlow<TokenListError, List<CryptoCurrency>>,
|
||||
|
|
@ -143,6 +225,30 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
}
|
||||
}
|
||||
|
||||
private fun createCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
maybeQuote: Either<Error, Quote?>,
|
||||
maybeNetworkStatus: Either<Error, NetworkStatus?>,
|
||||
maybeYieldBalance: Either<Error, YieldBalance>?,
|
||||
): Either<Error, CryptoCurrencyStatus> = either {
|
||||
var quoteRetrievingFailed = false
|
||||
|
||||
val networkStatus = maybeNetworkStatus.bind()
|
||||
val quote = recover({ maybeQuote.bind() }) {
|
||||
quoteRetrievingFailed = true
|
||||
null
|
||||
}
|
||||
val yieldBalance = maybeYieldBalance?.getOrNull()
|
||||
|
||||
createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = quoteRetrievingFailed,
|
||||
yieldBalance = yieldBalance,
|
||||
)
|
||||
}
|
||||
|
||||
private fun findYieldBalanceOrNull(
|
||||
yieldBalances: YieldBalanceList?,
|
||||
currency: CryptoCurrency,
|
||||
|
|
@ -197,6 +303,18 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<Quote>>> {
|
||||
return quotesRepository.getQuotesUpdates(setOf(id))
|
||||
.map<Set<Quote>, Either<Error, Set<Quote>>> { it.right() }
|
||||
.retryWhen { cause, _ ->
|
||||
emit(Error.DataError(cause).left())
|
||||
// adding delay before retry to avoid spam when flow restarted
|
||||
delay(RETRY_DELAY)
|
||||
true
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
networks: NonEmptySet<Network>,
|
||||
|
|
@ -212,6 +330,21 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): EitherFlow<Error, Set<NetworkStatus>> {
|
||||
return networksRepository.getNetworkStatusesUpdates(userWalletId, setOf(network))
|
||||
.map<Set<NetworkStatus>, Either<Error, Set<NetworkStatus>>> { it.right() }
|
||||
.retryWhen { cause, _ ->
|
||||
emit(Error.DataError(cause).left())
|
||||
// adding delay before retry to avoid spam when flow restarted
|
||||
delay(RETRY_DELAY)
|
||||
true
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getYieldBalances(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
|
|
@ -227,6 +360,18 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): EitherFlow<Error, YieldBalance> {
|
||||
return stakingRepository.getSingleYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).map<YieldBalance, Either<Error, YieldBalance>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
|
||||
private fun getIds(currencies: List<CryptoCurrency>): Pair<NonEmptySet<Network>, NonEmptySet<CryptoCurrency.ID>> {
|
||||
val currencyIdToNetworkId = currencies.associate { currency ->
|
||||
currency.id to currency.network
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ internal class CurrenciesStatusesOperations(
|
|||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getNetworkCoin(
|
||||
suspend fun Raise<Error>.getNetworkCoin(
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
): CryptoCurrency {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ internal class TokenDetailsNotificationsAnalyticsSender(
|
|||
is TokenDetailsNotification.KoinosMana,
|
||||
is TokenDetailsNotification.MigrationMaticToPol,
|
||||
is TokenDetailsNotification.TokensInBeta,
|
||||
is TokenDetailsNotification.UsedOutdatedData,
|
||||
-> null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,4 +234,11 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) {
|
|||
title = resourceReference(id = R.string.beta_mode_warning_title),
|
||||
subtitle = resourceReference(id = R.string.beta_mode_warning_message),
|
||||
)
|
||||
|
||||
data object UsedOutdatedData : TokenDetailsNotification(
|
||||
config = NotificationConfig(
|
||||
subtitle = resourceReference(R.string.warning_some_token_balances_not_updated),
|
||||
iconResId = R.drawable.ic_error_sync_24,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -136,6 +136,7 @@ internal class TokenDetailsNotificationConverter(
|
|||
)
|
||||
is CryptoCurrencyWarning.MigrationMaticToPol -> MigrationMaticToPol
|
||||
is CryptoCurrencyWarning.TokensInBetaWarning -> TokensInBeta
|
||||
is CryptoCurrencyWarning.UsedOutdatedDataWarning -> UsedOutdatedData
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@ import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBot
|
|||
import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlock
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.core.ui.components.transactions.txHistoryItems
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData
|
||||
|
|
@ -96,6 +96,7 @@ internal fun TokenDetailsScreen(state: TokenDetailsState, tokenMarketBlockCompon
|
|||
config = it.config,
|
||||
iconTint = when (it) {
|
||||
is TokenDetailsNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is TokenDetailsNotification.UsedOutdatedData -> TangemTheme.colors.text.attention
|
||||
else -> null
|
||||
},
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue