Updated on 2026-08-14

This commit is contained in:
Tangem 2025-03-06 21:32:04 +04:00
parent 6901522cf7
commit a61cb65789
13 changed files with 89 additions and 62 deletions

View file

@ -231,7 +231,7 @@ class TokenItemStateConverter(
useAccentColor = true,
).let(::add)
}
if (status.value.getStatusSource() == StatusSource.ONLY_CACHE) {
if (status.value.sources.total == StatusSource.ONLY_CACHE) {
TokenItemState.FiatAmountState.Content.IconUM(
iconRes = R.drawable.ic_error_sync_24,
useAccentColor = false,
@ -274,14 +274,6 @@ class TokenItemStateConverter(
return PriceChangeConverter.fromBigDecimal(value = this)
}
fun CryptoCurrencyStatus.Value.isFlickering(): Boolean = getStatusSource() == StatusSource.CACHE
private fun CryptoCurrencyStatus.Value.getStatusSource(): StatusSource? {
return when (this) {
is CryptoCurrencyStatus.Loaded -> source
is CryptoCurrencyStatus.NoAccount -> source
else -> null
}
}
fun CryptoCurrencyStatus.Value.isFlickering(): Boolean = sources.total == StatusSource.CACHE
}
}

View file

@ -21,6 +21,10 @@ enum class StatusSource {
/** Status is loaded from the cache and can't be updated with actual value */
ONLY_CACHE,
;
fun isActual() = this == ACTUAL
}
/**

View file

@ -1,6 +1,7 @@
package com.tangem.domain.tokens.model
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.getResultStatusSource
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.txhistory.models.TxHistoryItem
import java.math.BigDecimal
@ -51,7 +52,19 @@ data class CryptoCurrencyStatus(
/** Staking yield balance */
open val yieldBalance: YieldBalance? = null
open val source: StatusSource = StatusSource.ACTUAL
/** Sources */
open val sources: Sources = Sources()
}
data class Sources(
val networkSource: StatusSource = StatusSource.ACTUAL,
val quoteSource: StatusSource = StatusSource.ACTUAL,
val yieldBalanceSource: StatusSource = StatusSource.ACTUAL,
) {
val total: StatusSource by lazy {
listOf(networkSource, quoteSource, yieldBalanceSource).getResultStatusSource()
}
}
/** Represents the Loading state of a cryptocurrency, typically while fetching its details. */
@ -86,7 +99,7 @@ data class CryptoCurrencyStatus(
* Represents a state where there is no account associated with the cryptocurrency
*
* @property amountToCreateAccount base reserve amount for account creation
* @property source source of data
* @property sources sources of data
*/
data class NoAccount(
val amountToCreateAccount: BigDecimal,
@ -94,7 +107,7 @@ data class CryptoCurrencyStatus(
override val priceChange: BigDecimal?,
override val fiatRate: BigDecimal?,
override val networkAddress: NetworkAddress,
override val source: StatusSource,
override val sources: Sources,
) : Value(isError = false) {
override val amount: BigDecimal = BigDecimal.ZERO
@ -110,7 +123,7 @@ data class CryptoCurrencyStatus(
* @property hasCurrentNetworkTransactions Indicates if there are any transactions in progress related to the
* cryptocurrency network.
* @property pendingTransactions The current cryptocurrency transactions.
* @property source source of data
* @property sources sources of data
*/
data class Loaded(
override val amount: BigDecimal,
@ -121,7 +134,7 @@ data class CryptoCurrencyStatus(
override val hasCurrentNetworkTransactions: Boolean,
override val pendingTransactions: Set<TxHistoryItem>,
override val networkAddress: NetworkAddress,
override val source: StatusSource,
override val sources: Sources,
) : Value(isError = false)
/**
@ -144,7 +157,7 @@ data class CryptoCurrencyStatus(
override val hasCurrentNetworkTransactions: Boolean,
override val pendingTransactions: Set<TxHistoryItem>,
override val networkAddress: NetworkAddress,
override val source: StatusSource,
override val sources: Sources,
) : Value(isError = false)
/**
@ -161,8 +174,6 @@ data class CryptoCurrencyStatus(
override val hasCurrentNetworkTransactions: Boolean,
override val pendingTransactions: Set<TxHistoryItem>,
override val networkAddress: NetworkAddress,
) : Value(isError = false) {
override val source: StatusSource = StatusSource.CACHE
}
override val sources: Sources,
) : Value(isError = false)
}

View file

@ -122,7 +122,7 @@ class GetCryptoCurrencyActionsUseCase(
return getActionsForUnreachableCurrency(userWallet, cryptoCurrencyStatus, requirements)
}
if (cryptoCurrencyStatus.value.source != StatusSource.ACTUAL) {
if (cryptoCurrencyStatus.value.sources.total != StatusSource.ACTUAL) {
return getActionsForOutdatedData(userWallet, cryptoCurrencyStatus, requirements)
}
@ -289,9 +289,17 @@ class GetCryptoCurrencyActionsUseCase(
}
// swap
val isSwapAvailable = with(cryptoCurrencyStatus.value.sources) {
quoteSource.isActual() && networkSource.isActual()
}
activeList.add(
TokenActionsState.ActionState.Swap(
unavailabilityReason = ScenarioUnavailabilityReason.UsedOutdatedData,
unavailabilityReason = if (isSwapAvailable) {
ScenarioUnavailabilityReason.None
} else {
ScenarioUnavailabilityReason.UsedOutdatedData
},
showBadge = false,
),
)
@ -313,7 +321,17 @@ class GetCryptoCurrencyActionsUseCase(
activeList.add(TokenActionsState.ActionState.Stake(ScenarioUnavailabilityReason.UsedOutdatedData, null))
// send
activeList.add(TokenActionsState.ActionState.Send(ScenarioUnavailabilityReason.UsedOutdatedData))
val isSendAvailable = cryptoCurrencyStatus.value.sources.networkSource.isActual()
activeList.add(
TokenActionsState.ActionState.Send(
unavailabilityReason = if (isSendAvailable) {
ScenarioUnavailabilityReason.None
} else {
ScenarioUnavailabilityReason.UsedOutdatedData
},
),
)
// region sell
activeList.add(TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.UsedOutdatedData))

View file

@ -138,7 +138,9 @@ class GetCurrencyWarningsUseCase(
}
private fun getUsedOutdatedDataWarning(status: CryptoCurrencyStatus): CryptoCurrencyWarning? {
return CryptoCurrencyWarning.UsedOutdatedDataWarning.takeIf { status.value.source == StatusSource.ONLY_CACHE }
return CryptoCurrencyWarning.UsedOutdatedDataWarning.takeIf {
status.value.sources.total == StatusSource.ONLY_CACHE
}
}
private fun getIsBetaTokensWarning(currency: CryptoCurrency): CryptoCurrencyWarning? {

View file

@ -1,7 +1,6 @@
package com.tangem.domain.tokens.operations
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.getResultStatusSource
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.tokens.model.*
import java.math.BigDecimal
@ -56,14 +55,14 @@ internal class CurrencyStatusOperations(
priceChange = quote?.priceChange,
fiatRate = quote?.fiatRate,
networkAddress = status.address,
source = listOf(
status.source,
(quote as? Quote.Value)?.source ?: StatusSource.ACTUAL,
).getResultStatusSource(),
sources = CryptoCurrencyStatus.Sources(
networkSource = status.source,
quoteSource = (quote as? Quote.Value)?.source ?: StatusSource.ACTUAL,
),
)
}
@Suppress("CyclomaticComplexMethod")
@Suppress("CyclomaticComplexMethod", "LongMethod")
private fun createStatus(
networkStatusValue: NetworkStatus.Verified,
yieldBalance: YieldBalance?,
@ -105,11 +104,11 @@ internal class CurrencyStatusOperations(
pendingTransactions = currentTransactions,
networkAddress = networkStatusValue.address,
yieldBalance = currentYieldBalance,
source = listOfNotNull(
networkStatusValue.source,
currentYieldBalance?.source ?: StatusSource.ACTUAL,
(quote as? Quote.Value)?.source ?: StatusSource.ACTUAL,
).getResultStatusSource(),
sources = CryptoCurrencyStatus.Sources(
networkSource = networkStatusValue.source,
quoteSource = (quote as? Quote.Value)?.source ?: StatusSource.ACTUAL,
yieldBalanceSource = currentYieldBalance?.source ?: StatusSource.ACTUAL,
),
)
quote is Quote.Empty || ignoreQuote -> CryptoCurrencyStatus.NoQuote(
amount = amount,
@ -117,6 +116,11 @@ internal class CurrencyStatusOperations(
pendingTransactions = currentTransactions,
networkAddress = networkStatusValue.address,
yieldBalance = currentYieldBalance,
sources = CryptoCurrencyStatus.Sources(
networkSource = networkStatusValue.source,
quoteSource = (quote as? Quote.Value)?.source ?: StatusSource.ACTUAL,
yieldBalanceSource = currentYieldBalance?.source ?: StatusSource.ACTUAL,
),
)
quote is Quote.Value -> CryptoCurrencyStatus.Loaded(
amount = amount,
@ -127,11 +131,11 @@ internal class CurrencyStatusOperations(
pendingTransactions = currentTransactions,
networkAddress = networkStatusValue.address,
yieldBalance = currentYieldBalance,
source = listOf(
networkStatusValue.source,
currentYieldBalance?.source ?: StatusSource.ACTUAL,
quote.source,
).getResultStatusSource(),
sources = CryptoCurrencyStatus.Sources(
networkSource = networkStatusValue.source,
quoteSource = quote.source,
yieldBalanceSource = currentYieldBalance?.source ?: StatusSource.ACTUAL,
),
)
else -> CryptoCurrencyStatus.Loading
}

View file

@ -55,7 +55,7 @@ internal class TokenListFiatBalanceOperations(
}
return (fiatBalance as? TotalFiatBalance.Loaded)?.copy(
source = currencies.map { it.value.source }.getResultStatusSource(),
source = currencies.map { it.value.sources.total }.getResultStatusSource(),
) ?: fiatBalance
}
@ -67,7 +67,7 @@ internal class TokenListFiatBalanceOperations(
?: TotalFiatBalance.Loaded(
amount = BigDecimal.ZERO,
isAllAmountsSummarized = false,
source = (status as? CryptoCurrencyStatus.NoAccount)?.source ?: StatusSource.ACTUAL,
source = (status as? CryptoCurrencyStatus.NoAccount)?.sources?.total ?: StatusSource.ACTUAL,
)
}
@ -85,7 +85,7 @@ internal class TokenListFiatBalanceOperations(
) ?: TotalFiatBalance.Loaded(
amount = status.fiatAmount + fiatStakingBalance,
isAllAmountsSummarized = true,
source = status.source,
source = status.sources.total,
)
}
}

View file

@ -124,6 +124,7 @@ internal class GetPrimaryCurrencyStatusUpdatesUseCaseTest {
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
),
yieldBalance = null,
sources = CryptoCurrencyStatus.Sources(),
),
)
}

View file

@ -1,7 +1,6 @@
package com.tangem.domain.tokens.mock
import arrow.core.nonEmptyListOf
import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.*
import java.math.BigDecimal
@ -75,7 +74,7 @@ internal object MockTokensStates {
networkAddress = NetworkAddress.Single(
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
),
source = StatusSource.ACTUAL,
sources = CryptoCurrencyStatus.Sources(),
),
)
@ -89,7 +88,7 @@ internal object MockTokensStates {
networkAddress = NetworkAddress.Single(
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
),
source = StatusSource.ACTUAL,
sources = CryptoCurrencyStatus.Sources(),
),
)
@ -103,7 +102,7 @@ internal object MockTokensStates {
networkAddress = NetworkAddress.Single(
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
),
source = StatusSource.ACTUAL,
sources = CryptoCurrencyStatus.Sources(),
),
)
@ -117,7 +116,7 @@ internal object MockTokensStates {
networkAddress = NetworkAddress.Single(
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
),
source = StatusSource.ACTUAL,
sources = CryptoCurrencyStatus.Sources(),
),
)
@ -152,6 +151,7 @@ internal object MockTokensStates {
value = MockNetworks.verifiedNetworksStatuses.first { it.network == status.currency.network }.value as? NetworkStatus.Verified,
).address,
yieldBalance = null,
sources = CryptoCurrencyStatus.Sources(),
)
is Quote.Value -> CryptoCurrencyStatus.Loaded(
amount = amount,
@ -162,7 +162,7 @@ internal object MockTokensStates {
hasCurrentNetworkTransactions = false,
networkAddress = requireNotNull(networkStatus.value as? NetworkStatus.Verified).address,
yieldBalance = null,
source = StatusSource.ACTUAL,
sources = CryptoCurrencyStatus.Sources(),
)
}
status.copy(value = value)
@ -180,6 +180,7 @@ internal object MockTokensStates {
.value as? NetworkStatus.Verified,
).address,
yieldBalance = null,
sources = CryptoCurrencyStatus.Sources(),
),
)
}

View file

@ -12,7 +12,9 @@ import com.tangem.domain.models.StatusSource
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.feature.tokendetails.presentation.tokendetails.state.*
import com.tangem.feature.tokendetails.presentation.tokendetails.state.BalanceType
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryTransactionStateConverter
import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getBalance
@ -211,13 +213,5 @@ internal class TokenDetailsLoadedBalanceConverter(
return totalAmount.format { crypto(status.currency) }
}
private fun CryptoCurrencyStatus.Value.isFlickering(): Boolean = getStatusSource() == StatusSource.CACHE
private fun CryptoCurrencyStatus.Value.getStatusSource(): StatusSource? {
return when (this) {
is CryptoCurrencyStatus.Loaded -> source
is CryptoCurrencyStatus.NoAccount -> source
else -> null
}
}
private fun CryptoCurrencyStatus.Value.isFlickering(): Boolean = sources.total == StatusSource.CACHE
}

View file

@ -78,7 +78,7 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
element = WalletNotification.UsedOutdatedData,
condition = maybePrimaryCurrencyStatus.fold(
ifLeft = { false },
ifRight = { it.value.source == StatusSource.ONLY_CACHE },
ifRight = { it.value.sources.total == StatusSource.ONLY_CACHE },
),
)
}

View file

@ -68,7 +68,7 @@ internal class SingleWalletCardStateConverter(
balance = formatFiatAmount(status = status, appCurrency = appCurrency),
cardCount = selectedWallet.getCardsCount(),
isZeroBalance = status.fiatAmount?.isZero(),
isBalanceFlickering = (status as? CryptoCurrencyStatus.Loaded)?.source == StatusSource.CACHE,
isBalanceFlickering = (status as? CryptoCurrencyStatus.Loaded)?.sources?.total == StatusSource.CACHE,
)
}

View file

@ -1,5 +1,5 @@
[versions]
tangemBlockchainSdk = "release-app_5.21-969"
tangemBlockchainSdk = "release-app_5.21-976"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "release-app_5.21-435"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^