Updated on 2026-08-14
This commit is contained in:
parent
a324c914e5
commit
94579f4af8
5 changed files with 138 additions and 48 deletions
|
|
@ -3,18 +3,13 @@ package com.tangem.common.ui.amountScreen.converters.field
|
|||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.common.ui.amountScreen.utils.checkExceedBalance
|
||||
import com.tangem.common.ui.amountScreen.utils.getAmountValidationError
|
||||
import com.tangem.common.ui.amountScreen.utils.getCryptoValue
|
||||
import com.tangem.common.ui.amountScreen.utils.getFiatValue
|
||||
import com.tangem.common.ui.amountScreen.utils.getKeyboardAction
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.parseToBigDecimal
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.utils.isNullOrZero
|
||||
|
|
@ -72,20 +67,12 @@ class AmountFieldChangeTransformer(
|
|||
value = cryptoValue,
|
||||
fiatValue = fiatValue,
|
||||
isError = isCheckFailed,
|
||||
error = when {
|
||||
isExceedBalance -> resourceReference(R.string.common_insufficient_balance)
|
||||
isLessThanMinimumIfProvided -> {
|
||||
val minimumAmount = minimumTransactionAmount.amount.format {
|
||||
crypto(cryptoCurrencyStatus.currency)
|
||||
}
|
||||
|
||||
resourceReference(
|
||||
R.string.transfer_notification_invalid_minimum_transaction_amount_text,
|
||||
wrappedList(minimumAmount, minimumAmount),
|
||||
)
|
||||
}
|
||||
else -> TextReference.EMPTY
|
||||
},
|
||||
error = getAmountValidationError(
|
||||
isExceedBalance = isExceedBalance,
|
||||
isLessThanMinimum = isLessThanMinimumIfProvided,
|
||||
minimumTransactionAmount = minimumTransactionAmount,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
),
|
||||
cryptoAmount = amountTextField.cryptoAmount.copy(value = decimalCryptoValue),
|
||||
fiatAmount = amountTextField.fiatAmount.copy(value = decimalFiatValue),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
package com.tangem.common.ui.amountScreen.converters.field
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.common.ui.amountScreen.utils.getAmountValidationError
|
||||
import com.tangem.common.ui.amountScreen.utils.getKeyboardAction
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.utils.isNullOrZero
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
/**
|
||||
* @property cryptoAmount the crypto amount to set, or `null` to clear the field
|
||||
* @property maxEnterAmount maximum allowed amount boundary (for balance validation)
|
||||
* @property minimumTransactionAmount minimum allowed amount boundary (optional)
|
||||
*/
|
||||
class AmountFieldQuoteTransformer(
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val cryptoAmount: BigDecimal?,
|
||||
private val maxEnterAmount: EnterAmountBoundary,
|
||||
private val minimumTransactionAmount: EnterAmountBoundary?,
|
||||
) : Transformer<AmountState> {
|
||||
|
||||
override fun transform(prevState: AmountState): AmountState {
|
||||
if (prevState !is AmountState.Data) return prevState
|
||||
if (cryptoAmount == null) return prevState.emptyState(maxEnterAmount.fiatRate)
|
||||
|
||||
val textField = prevState.amountTextField
|
||||
val cryptoDecimals = textField.cryptoAmount.decimals
|
||||
val fiatDecimals = textField.fiatAmount.decimals
|
||||
val fiatRate = maxEnterAmount.fiatRate
|
||||
val cryptoString = cryptoAmount.parseBigDecimal(cryptoDecimals)
|
||||
val fiatValue = fiatRate?.let { cryptoAmount.multiply(it).setScale(fiatDecimals, RoundingMode.HALF_UP) }
|
||||
val fiatString = fiatValue?.parseBigDecimal(fiatDecimals).orEmpty()
|
||||
|
||||
val isExceedBalance = if (textField.isFiatValue) {
|
||||
val maxFiat = maxEnterAmount.fiatAmount
|
||||
maxFiat != null && fiatValue != null && fiatValue > maxFiat
|
||||
} else {
|
||||
val maxCrypto = maxEnterAmount.amount
|
||||
maxCrypto != null && cryptoAmount > maxCrypto
|
||||
}
|
||||
val isLessThanMinimum = minimumTransactionAmount?.amount?.let { cryptoAmount < it } == true
|
||||
val isZero = cryptoAmount.isNullOrZero()
|
||||
val isCheckFailed = isExceedBalance || isLessThanMinimum
|
||||
|
||||
return prevState.copy(
|
||||
isPrimaryButtonEnabled = !isZero && !isCheckFailed,
|
||||
reduceAmountBy = BigDecimal.ZERO,
|
||||
amountTextField = textField.copy(
|
||||
value = cryptoString,
|
||||
fiatValue = fiatString,
|
||||
cryptoAmount = textField.cryptoAmount.copy(value = cryptoAmount),
|
||||
fiatAmount = textField.fiatAmount.copy(value = fiatValue),
|
||||
isError = isCheckFailed,
|
||||
error = getAmountValidationError(
|
||||
isExceedBalance = isExceedBalance,
|
||||
isLessThanMinimum = isLessThanMinimum,
|
||||
minimumTransactionAmount = minimumTransactionAmount,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = getKeyboardAction(isCheckFailed, cryptoAmount),
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun AmountState.Data.emptyState(fiatRate: BigDecimal?): AmountState.Data {
|
||||
return copy(
|
||||
isPrimaryButtonEnabled = false,
|
||||
reduceAmountBy = BigDecimal.ZERO,
|
||||
amountTextField = amountTextField.copy(
|
||||
value = "",
|
||||
fiatValue = "",
|
||||
cryptoAmount = amountTextField.cryptoAmount.copy(value = BigDecimal.ZERO),
|
||||
fiatAmount = amountTextField.fiatAmount.copy(value = if (fiatRate != null) BigDecimal.ZERO else null),
|
||||
isError = false,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.None,
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,10 @@ package com.tangem.common.ui.amountScreen.converters.field
|
|||
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.common.ui.amountScreen.utils.getAmountValidationError
|
||||
import com.tangem.common.ui.amountScreen.utils.getKeyboardAction
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.utils.extensions.isZero
|
||||
|
|
@ -52,16 +47,12 @@ class AmountFieldSetMaxAmountTransformer(
|
|||
value = cryptoValue,
|
||||
fiatValue = fiatValue,
|
||||
isError = isLessThanMinimumIfProvided,
|
||||
error = when {
|
||||
isLessThanMinimumIfProvided -> {
|
||||
val minimumAmount = minAmount.amount.format { crypto(cryptoCurrencyStatus.currency) }
|
||||
resourceReference(
|
||||
R.string.transfer_notification_invalid_minimum_transaction_amount_text,
|
||||
wrappedList(minimumAmount, minimumAmount),
|
||||
)
|
||||
}
|
||||
else -> TextReference.EMPTY
|
||||
},
|
||||
error = getAmountValidationError(
|
||||
isExceedBalance = false,
|
||||
isLessThanMinimum = isLessThanMinimumIfProvided,
|
||||
minimumTransactionAmount = minAmount,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
),
|
||||
cryptoAmount = amountTextField.cryptoAmount.copy(value = decimalCryptoValue),
|
||||
fiatAmount = amountTextField.fiatAmount.copy(value = decimalFiatValue),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
package com.tangem.common.ui.amountScreen.utils
|
||||
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.amountScreen.models.AmountFieldModel
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.core.ui.utils.parseToBigDecimal
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.utils.extensions.isZero
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
|
@ -56,4 +63,21 @@ internal fun getKeyboardAction(isCheckFailed: Boolean, decimalCryptoValue: BigDe
|
|||
ImeAction.Done
|
||||
} else {
|
||||
ImeAction.None
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getAmountValidationError(
|
||||
isExceedBalance: Boolean,
|
||||
isLessThanMinimum: Boolean,
|
||||
minimumTransactionAmount: EnterAmountBoundary?,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): TextReference = when {
|
||||
isExceedBalance -> resourceReference(R.string.common_insufficient_balance)
|
||||
isLessThanMinimum -> {
|
||||
val minimumAmount = minimumTransactionAmount?.amount.format { crypto(cryptoCurrency) }
|
||||
resourceReference(
|
||||
R.string.transfer_notification_invalid_minimum_transaction_amount_text,
|
||||
wrappedList(minimumAmount, minimumAmount),
|
||||
)
|
||||
}
|
||||
else -> TextReference.EMPTY
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
package com.tangem.features.swap.v2.impl.amount.model.transformers
|
||||
|
||||
import com.tangem.common.ui.amountScreen.converters.field.AmountFieldChangeTransformer
|
||||
import com.tangem.common.ui.amountScreen.converters.field.AmountFieldQuoteTransformer
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.swap.models.SwapAmountType
|
||||
import com.tangem.features.swap.v2.impl.R
|
||||
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountFieldUM
|
||||
|
|
@ -93,13 +92,11 @@ internal class SwapAmountSelectQuoteTransformer(
|
|||
isAmountEmpty = false,
|
||||
displayAmount = fromAmount,
|
||||
).copy(
|
||||
amountField = AmountFieldChangeTransformer(
|
||||
amountField = AmountFieldQuoteTransformer(
|
||||
cryptoCurrencyStatus = prevState.primaryCryptoCurrencyStatus,
|
||||
cryptoAmount = fromAmount,
|
||||
maxEnterAmount = primaryMaximumAmountBoundary,
|
||||
minimumTransactionAmount = primaryMinimumAmountBoundary,
|
||||
value = fromAmount.parseBigDecimal(
|
||||
prevState.primaryCryptoCurrencyStatus.currency.decimals,
|
||||
),
|
||||
).transform(fromField.amountField),
|
||||
)
|
||||
} ?: prevState.primaryAmount
|
||||
|
|
@ -123,11 +120,11 @@ internal class SwapAmountSelectQuoteTransformer(
|
|||
cryptoCurrencyStatus = prevState.primaryCryptoCurrencyStatus,
|
||||
isAmountEmpty = true,
|
||||
).copy(
|
||||
amountField = AmountFieldChangeTransformer(
|
||||
amountField = AmountFieldQuoteTransformer(
|
||||
cryptoCurrencyStatus = prevState.primaryCryptoCurrencyStatus,
|
||||
cryptoAmount = null,
|
||||
maxEnterAmount = primaryMaximumAmountBoundary,
|
||||
minimumTransactionAmount = primaryMinimumAmountBoundary,
|
||||
value = "",
|
||||
).transform(primarySwapAmountField.amountField),
|
||||
)
|
||||
}
|
||||
|
|
@ -163,12 +160,11 @@ internal class SwapAmountSelectQuoteTransformer(
|
|||
val transformedSecondaryAmountField = if (isSecondarySelected && toAmount == null) {
|
||||
secondarySwapAmountField.amountField
|
||||
} else {
|
||||
AmountFieldChangeTransformer(
|
||||
AmountFieldQuoteTransformer(
|
||||
cryptoCurrencyStatus = prevState.secondaryCryptoCurrencyStatus,
|
||||
cryptoAmount = toAmount,
|
||||
maxEnterAmount = secondaryMaximumAmountBoundary,
|
||||
minimumTransactionAmount = secondaryMinimumAmountBoundary,
|
||||
value = toAmount?.parseBigDecimal(prevState.secondaryCryptoCurrencyStatus.currency.decimals)
|
||||
.orEmpty(),
|
||||
).transform(secondarySwapAmountField.amountField)
|
||||
}
|
||||
val insufficientFundsError = if (isSecondarySelected && fromAmount != null) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue