Updated on 2026-08-14

This commit is contained in:
Tangem 2024-07-23 18:55:55 +05:00
parent 7cc1bb7379
commit ea30176490
14 changed files with 156 additions and 43 deletions

View file

@ -127,7 +127,7 @@ internal class SetInitialDataStateTransformer(
startText = TextReference.Res(R.string.staking_details_minimum_requirement),
endText = TextReference.Str(
value = BigDecimalFormatter.formatCryptoAmount(
cryptoAmount = yield.args.enter.args[KEY_AMOUNT]?.minimum?.toBigDecimal(),
cryptoAmount = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum,
cryptoCurrency = cryptoCurrencyStatus.currency.symbol,
decimals = cryptoCurrencyStatus.currency.decimals,
),
@ -191,6 +191,5 @@ internal class SetInitialDataStateTransformer(
companion object {
private val EQUALITY_THRESHOLD = BigDecimal(1E-10)
private const val KEY_AMOUNT = "amount"
}
}

View file

@ -1,18 +1,33 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import com.tangem.common.ui.amountScreen.converters.field.AmountFieldChangeTransformer
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class AmountChangeStateTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val yield: Yield,
private val value: String,
) : Transformer<StakingUiState> {
private val amountRequirementStateTransformer by lazy(LazyThreadSafetyMode.NONE) {
AmountRequirementStateTransformer(
cryptoCurrencyStatus,
yield,
value,
)
}
override fun transform(prevState: StakingUiState): StakingUiState {
val updatedAmountState = AmountFieldChangeTransformer(
cryptoCurrencyStatus,
value,
).transform(prevState.amountState)
return prevState.copy(
amountState = AmountFieldChangeTransformer(cryptoCurrencyStatus, value).transform(prevState.amountState),
amountState = amountRequirementStateTransformer.transform(updatedAmountState),
)
}
}

View file

@ -1,16 +1,32 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import com.tangem.common.ui.amountScreen.converters.field.AmountFieldMaxAmountTransformer
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class AmountMaxValueStateTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val yield: Yield,
) : Transformer<StakingUiState> {
private val amountRequirementStateTransformer by lazy(LazyThreadSafetyMode.NONE) {
val value = cryptoCurrencyStatus.value.amount
?.parseBigDecimal(cryptoCurrencyStatus.currency.decimals)
.orEmpty()
AmountRequirementStateTransformer(
cryptoCurrencyStatus,
yield,
value,
)
}
override fun transform(prevState: StakingUiState): StakingUiState {
val updatedAmountState = AmountFieldMaxAmountTransformer(cryptoCurrencyStatus).transform(prevState.amountState)
return prevState.copy(
amountState = AmountFieldMaxAmountTransformer(cryptoCurrencyStatus).transform(prevState.amountState),
amountState = amountRequirementStateTransformer.transform(updatedAmountState),
)
}
}

View file

@ -0,0 +1,55 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import com.tangem.common.extensions.isZero
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.R
import com.tangem.utils.transformer.Transformer
internal class AmountRequirementStateTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val yield: Yield,
private val value: String,
) : Transformer<AmountState> {
override fun transform(prevState: AmountState): AmountState {
val amountRequirements = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]
val amountDecimal = value.parseToBigDecimal(cryptoCurrencyStatus.currency.decimals)
return if (prevState !is AmountState.Data || amountRequirements == null) {
prevState
} else {
val isAlreadyErrorState = prevState.amountTextField.isError
val isAmountRequired = amountRequirements.required
val isAmountZero = amountDecimal.isZero()
val isExceedsRequirements =
amountRequirements.maximum?.compareTo(amountDecimal) == -1 ||
amountRequirements.minimum?.compareTo(amountDecimal) == 1
val isRequirementError = !isAmountZero && isAmountRequired && isExceedsRequirements && !isAlreadyErrorState
if (isRequirementError) {
prevState.copy(
amountTextField = prevState.amountTextField.copy(
isError = true,
error = resourceReference(
R.string.staking_amount_requirement_error,
wrappedList(
BigDecimalFormatter.formatCryptoAmount(
amountRequirements.minimum,
cryptoCurrencyStatus.currency.symbol,
cryptoCurrencyStatus.currency.decimals,
),
),
),
),
)
} else {
prevState
}
}
}
}

View file

@ -67,7 +67,7 @@ internal fun StakingInitialInfoContent(state: StakingStates.InitialInfoState, cl
)
}
}
AnimatedContent(targetState = state.yieldBalance, label = "Rewards block visibility animation") {
AnimatedContent(targetState = state.yieldBalance, label = "Staking yield visibility animation") {
if (it is InnerYieldBalanceState.Data) {
ActiveStakingBlock(it.balance, clickIntents::onActiveStake)
}
@ -168,6 +168,7 @@ private fun StakingRewardBlock(
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(),
enabled = isRewardsToClaim,
onClick = onRewardsClick,
),
)
@ -192,18 +193,20 @@ private fun ActiveStakingBlock(groups: List<BalanceGroupedState>, onClick: (Bala
) {
group.items.forEachIndexed { index, balance ->
key(balance.validator.address) {
val caption = combinedReference(
if (group.type == BalanceGroupType.UNSTAKED) {
resourceReference(R.string.staking_details_unbonding_period)
val caption = if (group.type == BalanceGroupType.UNSTAKED) {
combinedReference(
resourceReference(R.string.staking_details_unbonding_period),
annotatedReference {
appendSpace()
appendColored(
text = balance.unbondingPeriod.resolveReference(),
color = TangemTheme.colors.text.accent,
)
}
} else {
resourceReference(R.string.app_name)
},
)
} else {
combinedReference(
resourceReference(R.string.app_name),
annotatedReference {
appendSpace()
appendColored(
@ -213,9 +216,9 @@ private fun ActiveStakingBlock(groups: List<BalanceGroupedState>, onClick: (Bala
),
color = TangemTheme.colors.text.accent,
)
}
},
)
},
)
}
InputRowImageInfo(
title = group.title.takeIf { index == 0 },
subtitle = stringReference(balance.validator.name),

View file

@ -148,17 +148,10 @@ private fun getButtonData(currentState: StakingUiState): Int {
private fun onPrimaryClick(currentState: StakingUiState) {
when (currentState.currentStep) {
StakingStep.InitialInfo -> {
val initialState = currentState.initialInfoState as? StakingStates.InitialInfoState.Data
if (initialState?.yieldBalance is InnerYieldBalanceState.Data) {
if (initialState.isStakeMoreAvailable) {
currentState.clickIntents.onNextClick()
}
} else {
currentState.clickIntents.onNextClick()
}
}
StakingStep.Amount -> currentState.clickIntents.onNextClick()
StakingStep.InitialInfo,
StakingStep.Validators,
StakingStep.Amount,
-> currentState.clickIntents.onNextClick()
StakingStep.Confirmation -> {
val confirmationState = currentState.confirmationState
if (confirmationState is StakingStates.ConfirmationState.Data) {
@ -171,7 +164,6 @@ private fun onPrimaryClick(currentState: StakingUiState) {
currentState.clickIntents.onBackClick()
}
}
StakingStep.Validators -> currentState.clickIntents.onNextClick()
StakingStep.RewardsValidators -> Unit
}
}

View file

@ -196,7 +196,7 @@ internal class StakingViewModel @Inject constructor(
}
override fun onAmountValueChange(value: String) {
stateController.update(AmountChangeStateTransformer(cryptoCurrencyStatus, value))
stateController.update(AmountChangeStateTransformer(cryptoCurrencyStatus, yield, value))
}
override fun onAmountPasteTriggerDismiss() {
@ -204,7 +204,7 @@ internal class StakingViewModel @Inject constructor(
}
override fun onMaxValueClick() {
stateController.update(AmountMaxValueStateTransformer(cryptoCurrencyStatus))
stateController.update(AmountMaxValueStateTransformer(cryptoCurrencyStatus, yield))
}
override fun onCurrencyChangeClick(isFiat: Boolean) {
@ -223,7 +223,7 @@ internal class StakingViewModel @Inject constructor(
}
override fun selectRewardValidator(rewardValue: String) {
stateController.update(AmountChangeStateTransformer(cryptoCurrencyStatus, rewardValue))
stateController.update(AmountChangeStateTransformer(cryptoCurrencyStatus, yield, rewardValue))
onNextClick()
}
@ -234,7 +234,7 @@ internal class StakingViewModel @Inject constructor(
RouteType.OTHER
}
stateController.update { it.copy(routeType = routeType) }
stateController.update(AmountChangeStateTransformer(cryptoCurrencyStatus, activeStake.cryptoValue))
stateController.update(AmountChangeStateTransformer(cryptoCurrencyStatus, yield, activeStake.cryptoValue))
onNextClick(activeStake.pendingActions)
}