Updated on 2026-08-14

This commit is contained in:
Tangem 2024-11-04 17:01:38 +05:00
parent f8b4614125
commit ede7143a03
12 changed files with 126 additions and 76 deletions

View file

@ -39,7 +39,7 @@ internal object StakingNotification {
) : NotificationUM.Warning(
title = title,
subtitle = subtitle,
iconResId = R.drawable.ic_alert_circle_24,
iconResId = R.drawable.img_attention_20,
buttonsState = buttonsState,
onCloseClick = onCloseClick,
) {
@ -47,6 +47,11 @@ internal object StakingNotification {
val title: TextReference,
val description: TextReference,
) : StakingNotification.Warning(title = title, subtitle = description)
data object LowStakedBalance : StakingNotification.Warning(
title = resourceReference(R.string.staking_notification_low_staked_balance_title),
subtitle = resourceReference(R.string.staking_notification_low_staked_balance_text),
)
}
sealed class Info(

View file

@ -1,5 +1,6 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import androidx.annotation.StringRes
import androidx.compose.ui.text.input.ImeAction
import com.tangem.common.extensions.isZero
import com.tangem.common.ui.amountScreen.models.AmountState
@ -26,25 +27,18 @@ internal class AmountRequirementStateTransformer(
private val actionType: StakingActionCommonType,
) : Transformer<AmountState> {
override fun transform(prevState: AmountState): AmountState {
val amountRequirements = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]
return if (prevState is AmountState.Data && amountRequirements != null) {
return if (prevState is AmountState.Data) {
updateWithError(
prevState,
actionType,
amountRequirements,
)
} else {
prevState
}
}
private fun updateWithError(
amountState: AmountState.Data,
actionType: StakingActionCommonType,
amountRequirements: AddressArgument,
): AmountState {
val isRequirementError = isRequirementError(amountState, amountRequirements)
private fun updateWithError(amountState: AmountState.Data, actionType: StakingActionCommonType): AmountState {
val requirementError = getRequirementError(amountState)
val isIntegerOnlyError = isIntegerOnlyError(amountState, actionType)
val cryptoAmount = amountState.amountTextField.cryptoAmount
@ -53,14 +47,7 @@ internal class AmountRequirementStateTransformer(
val errorText = when {
amountState.amountTextField.isError -> amountState.amountTextField.error
isRequirementError -> resourceReference(
R.string.staking_amount_requirement_error,
wrappedList(
amountRequirements.minimum.format {
crypto(cryptoCurrencyStatus.currency)
},
),
)
requirementError != null -> requirementError
isIntegerOnlyError -> when (actionType) {
StakingActionCommonType.Enter -> resourceReference(
R.string.staking_amount_tron_integer_error,
@ -70,11 +57,11 @@ internal class AmountRequirementStateTransformer(
R.string.staking_amount_tron_integer_error_unstaking,
wrappedList(value),
)
else -> TODO()
else -> TextReference.EMPTY
}
else -> TextReference.EMPTY
}
val isError = amountState.amountTextField.isError || isRequirementError
val isError = amountState.amountTextField.isError || requirementError != null
return if (!errorText.isNullOrEmpty()) {
amountState.copy(
isPrimaryButtonEnabled = !isError,
@ -92,17 +79,25 @@ internal class AmountRequirementStateTransformer(
}
}
private fun isRequirementError(prevState: AmountState.Data, amountRequirements: AddressArgument): Boolean {
val amountDecimal = prevState.amountTextField.cryptoAmount.value ?: return false
private fun getRequirementError(prevState: AmountState.Data): TextReference? {
val amountDecimal = prevState.amountTextField.cryptoAmount.value ?: return null
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
return !isAmountZero && isAmountRequired && isExceedsRequirements && !isAlreadyErrorState
if (isAlreadyErrorState || isAmountZero) return null
return when (actionType) {
StakingActionCommonType.Enter -> {
val enterRequirements = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]
enterRequirements?.getError(amountDecimal, R.string.staking_amount_requirement_error)
}
StakingActionCommonType.Exit -> {
val exitRequirements = yield.args.exit?.args?.get(Yield.Args.ArgType.AMOUNT)
exitRequirements?.getError(amountDecimal, R.string.staking_unstake_amount_requirement_error)
}
else -> null
}
}
private fun isIntegerOnlyError(amountState: AmountState.Data, actionType: StakingActionCommonType): Boolean {
@ -116,6 +111,20 @@ internal class AmountRequirementStateTransformer(
return isEnterOrExit && isTron && !isIntegerOnly
}
private fun AddressArgument.getError(amount: BigDecimal, @StringRes errorTextRes: Int): TextReference? {
val isExceedsRequirements = maximum?.compareTo(amount) == -1 ||
minimum?.compareTo(amount) == 1
return resourceReference(
errorTextRes,
wrappedList(
minimum.format {
crypto(cryptoCurrencyStatus.currency)
},
),
).takeIf { required && isExceedsRequirements }
}
data class Data(
val amountState: AmountState,
val actionType: StakingActionCommonType,

View file

@ -107,6 +107,7 @@ internal class AddStakingNotificationsTransformer(
notifications = this,
prevState = prevState,
sendingAmount = sendingAmount,
actionAmount = amountValue,
feeValue = feeValue,
)
}.toImmutableList()

View file

@ -17,6 +17,7 @@ import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.lib.crypto.BlockchainUtils.isCosmos
import com.tangem.lib.crypto.BlockchainUtils.isTron
import com.tangem.utils.Provider
import com.tangem.utils.extensions.isZero
import com.tangem.utils.extensions.orZero
import java.math.BigDecimal
@ -26,12 +27,22 @@ internal class StakingInfoNotificationsFactory(
private val isSubtractAvailable: Boolean,
) {
/**
* @param notifications current notification to display
* @param prevState current screen state to update
* @param sendingAmount amount being transferred from user account
* @param actionAmount any amount being transferred or used action
* @param feeValue fee amount payed from user account
*/
fun addInfoNotifications(
notifications: MutableList<NotificationUM>,
prevState: StakingUiState,
sendingAmount: BigDecimal,
actionAmount: BigDecimal,
feeValue: BigDecimal,
) = with(notifications) {
addStakingLowBalanceNotification(prevState, actionAmount)
when (prevState.actionType) {
StakingActionCommonType.Enter -> addEnterInfoNotifications(sendingAmount, feeValue)
StakingActionCommonType.Exit -> addExitInfoNotifications()
@ -149,4 +160,21 @@ internal class StakingInfoNotificationsFactory(
add(StakingNotification.Info.StakeEntireBalance)
}
}
private fun MutableList<NotificationUM>.addStakingLowBalanceNotification(
prevState: StakingUiState,
actionAmount: BigDecimal,
) {
if (prevState.actionType != StakingActionCommonType.Exit) return
val maxAmount = prevState.balanceState?.cryptoAmount ?: return
val exitRequirements = yield.args.exit?.args?.get(Yield.Args.ArgType.AMOUNT) ?: return
val amountLeft = maxAmount - actionAmount
val isNotEnoughLeft = !amountLeft.isZero() && amountLeft < exitRequirements.minimum
if (exitRequirements.required && isNotEnoughLeft) {
add(StakingNotification.Warning.LowStakedBalance)
}
}
}