Updated on 2026-08-14

This commit is contained in:
Tangem 2024-08-07 15:08:26 +03:00
commit 2a5e3fa7eb
220 changed files with 5932 additions and 1815 deletions

View file

@ -11,10 +11,11 @@ import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.staking.model.StakingEntryInfo
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.BalanceType
import com.tangem.feature.tokendetails.presentation.tokendetails.state.*
import com.tangem.feature.tokendetails.presentation.tokendetails.state.StakingBlockUM
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
@ -31,9 +32,11 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import java.math.BigDecimal
@Suppress("LongParameterList")
internal class TokenDetailsLoadedBalanceConverter(
private val currentStateProvider: Provider<TokenDetailsState>,
private val appCurrencyProvider: Provider<AppCurrency>,
private val stakingEntryInfoProvider: Provider<StakingEntryInfo?>,
private val symbol: String,
private val decimals: Int,
private val clickIntents: TokenDetailsClickIntents,
@ -136,39 +139,28 @@ internal class TokenDetailsLoadedBalanceConverter(
private fun getYieldBalance(status: CryptoCurrencyStatus, state: TokenDetailsState): StakingBlockUM {
val yieldBalance = status.value.yieldBalance as? YieldBalance.Data
val stakingCryptoAmount = yieldBalance?.getTotalStakingBalance()
val stakingRewardAmount = yieldBalance?.getRewardStakingBalance()
val stakingFiatAmount = stakingCryptoAmount?.let { status.value.fiatRate?.multiply(it) }
return if (stakingCryptoAmount.isNullOrZero()) {
StakingBlockUM.Loading(state.tokenInfoBlockState.iconState)
} else {
StakingBlockUM.Staked(
cryptoAmount = stakingCryptoAmount,
fiatAmount = stakingFiatAmount,
cryptoValue = stringReference(
BigDecimalFormatter.formatCryptoAmount(stakingCryptoAmount, symbol, decimals),
),
fiatValue = stringReference(
BigDecimalFormatter.formatFiatAmount(
stakingFiatAmount,
appCurrencyProvider().code,
appCurrencyProvider().symbol,
),
),
rewardValue = resourceReference(
R.string.staking_details_rewards_to_claim,
wrappedList(
BigDecimalFormatter.formatFiatAmount(
stakingRewardAmount,
appCurrencyProvider().code,
appCurrencyProvider().symbol,
),
),
),
onStakeClicked = clickIntents::onStakeBannerClick,
)
val stakingEntryInfo = stakingEntryInfoProvider.invoke()
val iconState = state.tokenInfoBlockState.iconState
return when {
stakingCryptoAmount.isNullOrZero() && stakingEntryInfo != null -> {
getStakeAvailableState(stakingEntryInfo, iconState)
}
stakingCryptoAmount.isNullOrZero() && stakingEntryInfo == null -> {
StakingBlockUM.Error(iconState = iconState)
}
else -> {
val stakingRewardAmount = yieldBalance?.getRewardStakingBalance()
val stakingFiatAmount = stakingCryptoAmount?.let { status.value.fiatRate?.multiply(it) }
getStakedState(
stakingCryptoAmount = stakingCryptoAmount,
stakingFiatAmount = stakingFiatAmount,
stakingRewardAmount = stakingRewardAmount,
)
}
}
}
@ -195,6 +187,54 @@ internal class TokenDetailsLoadedBalanceConverter(
}
}
private fun getStakeAvailableState(
stakingEntryInfo: StakingEntryInfo,
iconState: IconState,
): StakingBlockUM.StakeAvailable {
return StakingBlockUM.StakeAvailable(
interestRate = BigDecimalFormatter.formatPercent(
percent = stakingEntryInfo.interestRate,
useAbsoluteValue = true,
),
periodInDays = stakingEntryInfo.periodInDays,
tokenSymbol = stakingEntryInfo.tokenSymbol,
iconState = iconState,
onStakeClicked = clickIntents::onStakeBannerClick,
)
}
private fun getStakedState(
stakingCryptoAmount: BigDecimal?,
stakingFiatAmount: BigDecimal?,
stakingRewardAmount: BigDecimal?,
): StakingBlockUM.Staked {
return StakingBlockUM.Staked(
cryptoAmount = stakingCryptoAmount,
fiatAmount = stakingFiatAmount,
cryptoValue = stringReference(
BigDecimalFormatter.formatCryptoAmount(stakingCryptoAmount, symbol, decimals),
),
fiatValue = stringReference(
BigDecimalFormatter.formatFiatAmount(
stakingFiatAmount,
appCurrencyProvider().code,
appCurrencyProvider().symbol,
),
),
rewardValue = resourceReference(
R.string.staking_details_rewards_to_claim,
wrappedList(
BigDecimalFormatter.formatFiatAmount(
stakingRewardAmount,
appCurrencyProvider().code,
appCurrencyProvider().symbol,
),
),
),
onStakeClicked = clickIntents::onStakeBannerClick,
)
}
private fun CryptoCurrencyStatus.Value.toContentConfig(currencySymbol: String): MarketPriceBlockState.Content {
return MarketPriceBlockState.Content(
currencySymbol = currencySymbol,

View file

@ -50,6 +50,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
internal class TokenDetailsStateFactory(
private val currentStateProvider: Provider<TokenDetailsState>,
private val appCurrencyProvider: Provider<AppCurrency>,
private val stakingEntryInfoProvider: Provider<StakingEntryInfo?>,
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
private val clickIntents: TokenDetailsClickIntents,
private val featureToggles: TokenDetailsFeatureToggles,
@ -79,6 +80,7 @@ internal class TokenDetailsStateFactory(
TokenDetailsLoadedBalanceConverter(
currentStateProvider = currentStateProvider,
appCurrencyProvider = appCurrencyProvider,
stakingEntryInfoProvider = stakingEntryInfoProvider,
symbol = symbol,
decimals = decimals,
clickIntents = clickIntents,

View file

@ -34,6 +34,7 @@ import com.tangem.domain.staking.GetStakingAvailabilityUseCase
import com.tangem.domain.staking.GetStakingEntryInfoUseCase
import com.tangem.domain.staking.GetYieldUseCase
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingEntryInfo
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.legacy.TradeCryptoAction.TransactionInfo
@ -144,15 +145,16 @@ internal class TokenDetailsViewModel @Inject constructor(
private val refreshStateJobHolder = JobHolder()
private val warningsJobHolder = JobHolder()
private val swapTxJobHolder = JobHolder()
private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null
private var swapTxStatusTaskScheduler = SingleTaskScheduler<PersistentList<SwapTransactionsState>>()
private val selectedAppCurrencyFlow: StateFlow<AppCurrency> = createSelectedAppCurrencyFlow()
private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null
private var stakingEntryInfo: StakingEntryInfo? = null
private var swapTxStatusTaskScheduler = SingleTaskScheduler<PersistentList<SwapTransactionsState>>()
private val stateFactory = TokenDetailsStateFactory(
currentStateProvider = Provider { uiState.value },
appCurrencyProvider = Provider(selectedAppCurrencyFlow::value),
stakingEntryInfoProvider = Provider { stakingEntryInfo },
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
clickIntents = this,
symbol = cryptoCurrency.symbol,
@ -399,7 +401,8 @@ internal class TokenDetailsViewModel @Inject constructor(
cryptoCurrencyId = cryptoCurrency.id,
symbol = cryptoCurrency.symbol,
)
internalUiState.value = stateFactory.getStateWithStaking(stakingInfo)
stakingEntryInfo = stakingInfo.getOrNull()
}
}
}
@ -568,7 +571,7 @@ internal class TokenDetailsViewModel @Inject constructor(
viewModelScope.launch(dispatchers.main) {
val extendedKey = getExtendedPublicKeyForCurrencyUseCase(
userWalletId,
cryptoCurrency.network.derivationPath,
cryptoCurrency.network,
).fold(
ifLeft = {
Timber.e(it.cause?.localizedMessage.orEmpty())