Updated on 2026-08-14
This commit is contained in:
commit
2fd16863a7
10 changed files with 291 additions and 109 deletions
|
|
@ -7,7 +7,6 @@ import com.tangem.domain.transaction.error.SendTransactionError
|
|||
import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState
|
||||
import com.tangem.features.send.impl.presentation.state.fee.FeeStateFactory
|
||||
import com.tangem.features.send.impl.presentation.state.fee.FeeType
|
||||
import com.tangem.features.send.impl.presentation.state.fee.getFee
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -58,7 +57,7 @@ internal class SendEventStateFactory(
|
|||
}
|
||||
|
||||
val newFeeValue = newFee.amount.value ?: BigDecimal.ZERO
|
||||
val oldFeeValue = feeSelector.getFee().amount.value ?: BigDecimal.ZERO
|
||||
val oldFeeValue = feeStateFactory.feeConverter.convert(feeSelector).amount.value ?: BigDecimal.ZERO
|
||||
val updateFeeState = feeStateFactory.onFeeOnLoadedState(fee)
|
||||
return if (newFeeValue > oldFeeValue) {
|
||||
updateFeeState.copy(
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ internal sealed class SendStates {
|
|||
abstract val isPrimaryButtonEnabled: Boolean
|
||||
|
||||
/** Amount state */
|
||||
@Stable
|
||||
data class AmountState(
|
||||
override val type: SendUiStateType = SendUiStateType.Amount,
|
||||
override val isPrimaryButtonEnabled: Boolean,
|
||||
|
|
@ -54,6 +55,7 @@ internal sealed class SendStates {
|
|||
) : SendStates()
|
||||
|
||||
/** Recipient state */
|
||||
@Stable
|
||||
data class RecipientState(
|
||||
override val type: SendUiStateType = SendUiStateType.Recipient,
|
||||
override val isPrimaryButtonEnabled: Boolean,
|
||||
|
|
@ -65,6 +67,7 @@ internal sealed class SendStates {
|
|||
) : SendStates()
|
||||
|
||||
/** Fee and speed state */
|
||||
@Stable
|
||||
data class FeeState(
|
||||
override val type: SendUiStateType = SendUiStateType.Fee,
|
||||
override val isPrimaryButtonEnabled: Boolean = false,
|
||||
|
|
@ -82,6 +85,7 @@ internal sealed class SendStates {
|
|||
) : SendStates()
|
||||
|
||||
/** Send state */
|
||||
@Stable
|
||||
data class SendState(
|
||||
override val type: SendUiStateType = SendUiStateType.Send,
|
||||
override val isPrimaryButtonEnabled: Boolean = true,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package com.tangem.features.send.impl.presentation.state.fee
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.extensions.toBigDecimalOrDefault
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -14,27 +12,3 @@ internal fun calculateReceiveAmount(state: SendUiState, feeAmount: Fee): BigDeci
|
|||
val fee = feeAmount.amount.value ?: return BigDecimal.ZERO
|
||||
return amountValue.minus(fee)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns fee amount depending on current state
|
||||
*/
|
||||
internal fun FeeSelectorState.Content.getFee(): Fee {
|
||||
return when (fees) {
|
||||
is TransactionFee.Choosable -> {
|
||||
when (selectedFee) {
|
||||
FeeType.SLOW -> fees.minimum
|
||||
FeeType.MARKET -> fees.normal
|
||||
FeeType.FAST -> fees.priority
|
||||
FeeType.CUSTOM -> {
|
||||
val feeAmount = customValues.firstOrNull()?.value.toBigDecimalOrDefault()
|
||||
Fee.Common(
|
||||
fees.normal.amount.copy(
|
||||
value = feeAmount,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is TransactionFee.Single -> fees.normal
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.tangem.features.send.impl.presentation.state.fee
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.core.ui.utils.parseToBigDecimal
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class FeeConverter(
|
||||
private val clickIntents: SendClickIntents,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
) : Converter<FeeSelectorState.Content, Fee> {
|
||||
|
||||
private val ethereumCustomFeeConverter by lazy {
|
||||
EthereumCustomFeeConverter(
|
||||
clickIntents = clickIntents,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
)
|
||||
}
|
||||
|
||||
override fun convert(value: FeeSelectorState.Content): Fee {
|
||||
return when (val fees = value.fees) {
|
||||
is TransactionFee.Choosable -> {
|
||||
when (value.selectedFee) {
|
||||
FeeType.SLOW -> fees.minimum
|
||||
FeeType.MARKET -> fees.normal
|
||||
FeeType.FAST -> fees.priority
|
||||
FeeType.CUSTOM -> convertCustom(value, fees)
|
||||
}
|
||||
}
|
||||
is TransactionFee.Single -> fees.normal
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertCustom(feeSelectorState: FeeSelectorState.Content, fees: TransactionFee): Fee {
|
||||
val customValues = feeSelectorState.customValues
|
||||
val normalFee = fees.normal
|
||||
return if (customValues.isEmpty()) {
|
||||
normalFee
|
||||
} else {
|
||||
when (normalFee) {
|
||||
is Fee.Ethereum -> ethereumCustomFeeConverter.convertBack(normalFee = normalFee, value = customValues)
|
||||
else -> {
|
||||
val customFee = customValues.firstOrNull()
|
||||
Fee.Common(
|
||||
normalFee.amount.copy(
|
||||
value = customFee?.value?.parseToBigDecimal(customFee.decimals),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.features.send.impl.presentation.state.fee
|
|||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.core.ui.extensions.networkIconResId
|
||||
import com.tangem.core.ui.utils.parseToBigDecimal
|
||||
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
||||
|
|
@ -14,6 +15,7 @@ import com.tangem.features.send.impl.presentation.state.SendUiStateType
|
|||
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.toFormattedString
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
|
@ -65,7 +67,8 @@ internal class FeeNotificationFactory(
|
|||
) {
|
||||
val multipleFees = transactionFee as? TransactionFee.Choosable ?: return
|
||||
val minimumValue = multipleFees.minimum.amount.value ?: return
|
||||
val customValue = customFee.firstOrNull()?.value?.toBigDecimalOrNull() ?: return
|
||||
val customAmount = customFee.firstOrNull() ?: return
|
||||
val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals)
|
||||
if (selectedFee == FeeType.CUSTOM && minimumValue > customValue) {
|
||||
add(SendFeeNotification.Informational.TooLow)
|
||||
}
|
||||
|
|
@ -78,10 +81,11 @@ internal class FeeNotificationFactory(
|
|||
) {
|
||||
val multipleFees = transactionFee as? TransactionFee.Choosable ?: return
|
||||
val highValue = multipleFees.priority.amount.value ?: return
|
||||
val customValue = customFee.firstOrNull()?.value?.toBigDecimalOrNull() ?: return
|
||||
val customAmount = customFee.firstOrNull() ?: return
|
||||
val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals)
|
||||
val diff = customValue / highValue
|
||||
if (selectedFee == FeeType.CUSTOM && diff > FEE_MAX_DIFF) {
|
||||
add(SendFeeNotification.Warning.TooHigh(diff.toInt().toString()))
|
||||
add(SendFeeNotification.Warning.TooHigh(diff.toFormattedString(HIGH_FEE_DIFF_DECIMALS)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,5 +162,6 @@ internal class FeeNotificationFactory(
|
|||
|
||||
companion object {
|
||||
private val FEE_MAX_DIFF = BigDecimal(5)
|
||||
private const val HIGH_FEE_DIFF_DECIMALS = 0
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,9 @@ package com.tangem.features.send.impl.presentation.state.fee
|
|||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.parseToBigDecimal
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
|
||||
|
|
@ -10,10 +12,8 @@ import com.tangem.features.send.impl.presentation.state.SendStates
|
|||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.isNullOrZero
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
|
|
@ -31,6 +31,15 @@ internal class FeeStateFactory(
|
|||
SendFeeCustomFieldConverter(
|
||||
clickIntents = clickIntents,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
)
|
||||
}
|
||||
|
||||
val feeConverter by lazy {
|
||||
FeeConverter(
|
||||
clickIntents = clickIntents,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +67,7 @@ internal class FeeStateFactory(
|
|||
customValues = customFeeFieldConverter.convert(fees.normal),
|
||||
)
|
||||
|
||||
val fee = feeSelectorState.getFee()
|
||||
val fee = feeConverter.convert(feeSelectorState)
|
||||
val receivedAmount = calculateReceiveAmount(state, fee)
|
||||
return state.copy(
|
||||
feeState = feeState.copy(
|
||||
|
|
@ -83,7 +92,7 @@ internal class FeeStateFactory(
|
|||
fees = fees,
|
||||
customValues = customFeeFieldConverter.convert(fees.normal),
|
||||
)
|
||||
val fee = updatedFeeSelector.getFee()
|
||||
val fee = feeConverter.convert(updatedFeeSelector)
|
||||
val receivedAmount = calculateReceiveAmount(state, fee)
|
||||
return state.copy(
|
||||
feeState = feeState.copy(
|
||||
|
|
@ -112,7 +121,7 @@ internal class FeeStateFactory(
|
|||
val balance = coinCryptoCurrencyStatusProvider().value.amount ?: BigDecimal.ZERO
|
||||
|
||||
val updatedFeeSelectorState = feeSelectorState.copy(selectedFee = feeType)
|
||||
val fee = updatedFeeSelectorState.getFee()
|
||||
val fee = feeConverter.convert(updatedFeeSelectorState)
|
||||
val receivedAmount = calculateReceiveAmount(state, fee)
|
||||
return state.copy(
|
||||
feeState = feeState.copy(
|
||||
|
|
@ -129,14 +138,10 @@ internal class FeeStateFactory(
|
|||
val state = currentStateProvider()
|
||||
val feeState = state.feeState ?: return state
|
||||
val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return state
|
||||
val updatedFeeSelectorState = feeSelectorState.copy(
|
||||
customValues = feeSelectorState.customValues.toMutableList().apply {
|
||||
set(index, feeSelectorState.customValues[index].copy(value = value))
|
||||
}.toImmutableList(),
|
||||
)
|
||||
val updatedFeeSelectorState = customFeeFieldConverter.onValueChange(feeSelectorState, index, value)
|
||||
val balance = coinCryptoCurrencyStatusProvider().value.amount ?: BigDecimal.ZERO
|
||||
|
||||
val fee = updatedFeeSelectorState.getFee()
|
||||
val fee = feeConverter.convert(updatedFeeSelectorState)
|
||||
val receivedAmount = calculateReceiveAmount(state, fee)
|
||||
return state.copy(
|
||||
feeState = feeState.copy(
|
||||
|
|
@ -153,7 +158,7 @@ internal class FeeStateFactory(
|
|||
val state = currentStateProvider()
|
||||
val feeState = state.feeState ?: return state
|
||||
val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return state
|
||||
val fee = feeSelectorState.getFee()
|
||||
val fee = feeConverter.convert(feeSelectorState)
|
||||
val receivedAmount = calculateReceiveAmount(state, fee)
|
||||
return state.copy(
|
||||
feeState = feeState.copy(
|
||||
|
|
@ -181,13 +186,17 @@ internal class FeeStateFactory(
|
|||
notifications: ImmutableList<SendFeeNotification>,
|
||||
): Boolean {
|
||||
val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return false
|
||||
val customValue = feeSelectorState.customValues.firstOrNull()?.value?.toBigDecimalOrNull()
|
||||
val customValue = feeSelectorState.customValues.firstOrNull()
|
||||
val balance = coinCryptoCurrencyStatusProvider().value.amount ?: BigDecimal.ZERO
|
||||
val fee = feeSelectorState.getFee()
|
||||
val fee = feeConverter.convert(feeSelectorState)
|
||||
val feeValue = fee.amount.value ?: BigDecimal.ZERO
|
||||
|
||||
val isNotCustom = feeSelectorState.selectedFee != FeeType.CUSTOM
|
||||
val isNotEmptyCustom = !customValue.isNullOrZero() && !isNotCustom
|
||||
val isNotEmptyCustom = if (customValue != null) {
|
||||
!customValue.value.parseToBigDecimal(customValue.decimals).isZero() && !isNotCustom
|
||||
} else {
|
||||
false
|
||||
}
|
||||
val noErrors = notifications.none { it is SendFeeNotification.Error }
|
||||
val isSubtractRequired = when {
|
||||
!feeState.isSubtractAvailable -> true // current currency is not fee currency
|
||||
|
|
|
|||
|
|
@ -1,79 +1,47 @@
|
|||
package com.tangem.features.send.impl.presentation.state.fee
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.features.send.impl.R
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.toFormattedString
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal class SendFeeCustomFieldConverter(
|
||||
private val clickIntents: SendClickIntents,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
) : Converter<Fee, ImmutableList<SendTextField.CustomFee>> {
|
||||
|
||||
private val ethereumCustomFeeConverter by lazy {
|
||||
EthereumCustomFeeConverter(
|
||||
clickIntents = clickIntents,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
)
|
||||
}
|
||||
|
||||
override fun convert(value: Fee): ImmutableList<SendTextField.CustomFee> {
|
||||
val ethereumFee = value as? Fee.Ethereum ?: return persistentListOf()
|
||||
val appCurrency = appCurrencyProvider()
|
||||
|
||||
val maxFeeFiat = BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = ethereumFee.amount.value,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
|
||||
return persistentListOf(
|
||||
SendTextField.CustomFee(
|
||||
value = ethereumFee.amount.value?.toFormattedString(ethereumFee.amount.decimals).orEmpty(),
|
||||
decimals = ethereumFee.amount.decimals,
|
||||
symbol = ethereumFee.amount.currencySymbol,
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(0, it) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Next,
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
title = resourceReference(R.string.send_max_fee),
|
||||
footer = resourceReference(R.string.send_max_fee_footer),
|
||||
label = stringReference(maxFeeFiat),
|
||||
),
|
||||
SendTextField.CustomFee(
|
||||
value = ethereumFee.gasPrice.toString(),
|
||||
decimals = 0,
|
||||
symbol = ETHEREUM_UNIT,
|
||||
title = resourceReference(R.string.send_gas_price),
|
||||
footer = resourceReference(R.string.send_gas_price_footer),
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(1, it) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Next,
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
),
|
||||
SendTextField.CustomFee(
|
||||
value = ethereumFee.gasLimit.toString(),
|
||||
decimals = 0,
|
||||
symbol = null,
|
||||
title = resourceReference(R.string.send_gas_limit),
|
||||
footer = resourceReference(R.string.send_gas_limit_footer),
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(2, it) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Done,
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
),
|
||||
)
|
||||
return when (value) {
|
||||
is Fee.Ethereum -> {
|
||||
ethereumCustomFeeConverter.convert(value)
|
||||
}
|
||||
else -> persistentListOf()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ETHEREUM_UNIT = "GWEI"
|
||||
}
|
||||
fun onValueChange(feeSelectorState: FeeSelectorState.Content, index: Int, value: String) = feeSelectorState.copy(
|
||||
customValues = when (feeSelectorState.fees.normal) {
|
||||
is Fee.Ethereum -> ethereumCustomFeeConverter.onValueChange(
|
||||
customValues = feeSelectorState.customValues,
|
||||
index = index,
|
||||
value = value,
|
||||
)
|
||||
else -> feeSelectorState.customValues
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
package com.tangem.features.send.impl.presentation.state.fee.custom
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.core.ui.utils.parseToBigDecimal
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.impl.R
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
internal class EthereumCustomFeeConverter(
|
||||
private val clickIntents: SendClickIntents,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
) : Converter<Fee.Ethereum, ImmutableList<SendTextField.CustomFee>> {
|
||||
|
||||
override fun convert(value: Fee.Ethereum): ImmutableList<SendTextField.CustomFee> {
|
||||
return persistentListOf(
|
||||
SendTextField.CustomFee(
|
||||
value = value.amount.value?.parseBigDecimal(value.amount.decimals).orEmpty(),
|
||||
decimals = value.amount.decimals,
|
||||
symbol = value.amount.currencySymbol,
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(FEE_AMOUNT, it) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Next,
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
title = resourceReference(R.string.send_max_fee),
|
||||
footer = resourceReference(R.string.send_max_fee_footer),
|
||||
label = getFeeFormatted(value.amount.value),
|
||||
),
|
||||
SendTextField.CustomFee(
|
||||
value = value.gasPrice.toString(),
|
||||
decimals = ETHEREUM_GAS_DECIMALS,
|
||||
symbol = ETHEREUM_GAS_UNIT,
|
||||
title = resourceReference(R.string.send_gas_price),
|
||||
footer = resourceReference(R.string.send_gas_price_footer),
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(GAS_PRICE, it) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Next,
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
),
|
||||
SendTextField.CustomFee(
|
||||
value = value.gasLimit.toString(),
|
||||
decimals = GAS_DECIMALS,
|
||||
symbol = null,
|
||||
title = resourceReference(R.string.send_gas_limit),
|
||||
footer = resourceReference(R.string.send_gas_limit_footer),
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(GAS_LIMIT, it) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Done,
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun convertBack(normalFee: Fee.Ethereum, value: ImmutableList<SendTextField.CustomFee>): Fee.Ethereum {
|
||||
val feeAmount = value[FEE_AMOUNT].value.parseToBigDecimal(value[FEE_AMOUNT].decimals)
|
||||
val gasPrice = value[GAS_PRICE].value.parseToBigDecimal(GAS_DECIMALS).toBigInteger()
|
||||
val gasLimit = value[GAS_LIMIT].value.parseToBigDecimal(GAS_DECIMALS).toBigInteger()
|
||||
return normalFee.copy(
|
||||
amount = normalFee.amount.copy(value = feeAmount),
|
||||
gasPrice = gasPrice,
|
||||
gasLimit = gasLimit,
|
||||
)
|
||||
}
|
||||
|
||||
fun onValueChange(
|
||||
customValues: ImmutableList<SendTextField.CustomFee>,
|
||||
index: Int,
|
||||
value: String,
|
||||
): ImmutableList<SendTextField.CustomFee> {
|
||||
val mutableCustomValues = customValues.toMutableList()
|
||||
return mutableCustomValues.apply {
|
||||
val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals)
|
||||
when (index) {
|
||||
FEE_AMOUNT -> {
|
||||
val newFeeAmountDecimal = value.parseToBigDecimal(this[FEE_AMOUNT].decimals)
|
||||
val newFeeAmount = newFeeAmountDecimal.movePointRight(this[FEE_AMOUNT].decimals)
|
||||
val newGasPrice = newFeeAmount.divide(gasLimit, GAS_DECIMALS, RoundingMode.HALF_UP)
|
||||
set(GAS_PRICE, this[GAS_PRICE].copy(value = newGasPrice.parseBigDecimal(GAS_DECIMALS)))
|
||||
set(
|
||||
index,
|
||||
this[index].copy(
|
||||
value = value,
|
||||
label = getFeeFormatted(newFeeAmountDecimal),
|
||||
),
|
||||
)
|
||||
}
|
||||
GAS_PRICE -> {
|
||||
val newGasPrice = value.parseToBigDecimal(this[GAS_PRICE].decimals)
|
||||
.movePointLeft(this[GAS_PRICE].decimals)
|
||||
val newFeeAmount = gasLimit * newGasPrice
|
||||
set(
|
||||
FEE_AMOUNT,
|
||||
this[FEE_AMOUNT].copy(
|
||||
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
|
||||
label = getFeeFormatted(newFeeAmount),
|
||||
),
|
||||
)
|
||||
set(index, this[index].copy(value = value))
|
||||
}
|
||||
else -> {
|
||||
val newGasLimit = value.parseToBigDecimal(this[GAS_LIMIT].decimals)
|
||||
val gasPrice = this[GAS_PRICE].value.parseToBigDecimal(this[GAS_PRICE].decimals)
|
||||
.movePointLeft(this[FEE_AMOUNT].decimals)
|
||||
val newFeeAmount = newGasLimit * gasPrice
|
||||
set(
|
||||
FEE_AMOUNT,
|
||||
this[FEE_AMOUNT].copy(
|
||||
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
|
||||
label = getFeeFormatted(newFeeAmount),
|
||||
),
|
||||
)
|
||||
set(index, this[index].copy(value = value))
|
||||
}
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
private fun getFeeFormatted(fee: BigDecimal?): TextReference {
|
||||
val appCurrency = appCurrencyProvider()
|
||||
val rate = cryptoCurrencyStatusProvider().value.fiatRate
|
||||
val fiatFee = rate?.let { fee?.multiply(it) }
|
||||
return stringReference(
|
||||
BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = fiatFee,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ETHEREUM_GAS_UNIT = "GWEI"
|
||||
private const val ETHEREUM_GAS_DECIMALS = 18
|
||||
private const val FEE_AMOUNT = 0
|
||||
private const val GAS_PRICE = 1
|
||||
private const val GAS_LIMIT = 2
|
||||
private const val GAS_DECIMALS = 0
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +38,10 @@ import com.tangem.features.send.api.navigation.SendRouter
|
|||
import com.tangem.features.send.impl.navigation.InnerSendRouter
|
||||
import com.tangem.features.send.impl.presentation.domain.AvailableWallet
|
||||
import com.tangem.features.send.impl.presentation.state.*
|
||||
import com.tangem.features.send.impl.presentation.state.fee.*
|
||||
import com.tangem.features.send.impl.presentation.state.fee.FeeNotificationFactory
|
||||
import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState
|
||||
import com.tangem.features.send.impl.presentation.state.fee.FeeStateFactory
|
||||
import com.tangem.features.send.impl.presentation.state.fee.FeeType
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
|
|
@ -71,7 +74,7 @@ internal class SendViewModel @Inject constructor(
|
|||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase,
|
||||
private val isFeeApproximateUseCase: IsFeeApproximateUseCase,
|
||||
isFeeApproximateUseCase: IsFeeApproximateUseCase,
|
||||
getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
|
||||
validateWalletMemoUseCase: ValidateWalletMemoUseCase,
|
||||
getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase,
|
||||
|
|
@ -536,7 +539,7 @@ internal class SendViewModel @Inject constructor(
|
|||
val feeState = uiState.feeState ?: return
|
||||
val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return
|
||||
val memo = uiState.recipientState?.memoTextField?.value
|
||||
val fee = feeSelectorState.getFee()
|
||||
val fee = feeStateFactory.feeConverter.convert(feeSelectorState)
|
||||
val amountValue = uiState.amountState?.amountTextField?.cryptoAmount?.value ?: return
|
||||
val amountToSend = if (feeState.isSubtract && isAmountSubtractAvailable) {
|
||||
feeState.receivedAmountValue
|
||||
|
|
@ -555,6 +558,7 @@ internal class SendViewModel @Inject constructor(
|
|||
).fold(
|
||||
ifLeft = {
|
||||
Timber.e(it)
|
||||
uiState = stateFactory.getSendingStateUpdate(isSending = false)
|
||||
uiState = eventStateFactory.getGenericErrorState(
|
||||
error = it,
|
||||
onConsume = { uiState = eventStateFactory.onConsumeEventState() },
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ spr-client = "3.6.2"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-470"
|
||||
tangemBlockchainSdk = "develop-471"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-324"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue