Updated on 2026-08-14
This commit is contained in:
commit
1dd8c44e35
12 changed files with 220 additions and 196 deletions
|
|
@ -66,7 +66,7 @@ sealed class AmountActionUi : SendScreenActionUi {
|
|||
}
|
||||
|
||||
sealed class AmountAction : SendScreenAction {
|
||||
data class SetAmount(val amount: BigDecimal, val isUserInput: Boolean) : AmountAction()
|
||||
data class SetAmount(val amountCrypto: BigDecimal, val isUserInput: Boolean) : AmountAction()
|
||||
data class SetAmountError(val error: TapError?) : AmountAction()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,8 +129,7 @@ internal class AddressPayIdMiddleware {
|
|||
private fun extractAddressFromShareUri(shareUri: String): String {
|
||||
val sharePrefix = listOf("bitcoin:", "ethereum:", "ripple:")
|
||||
val prefixes = sharePrefix.filter { shareUri.contains(it) }
|
||||
return if (prefixes.isEmpty()) shareUri
|
||||
else shareUri.replace(prefixes[0], "")
|
||||
return if (prefixes.isEmpty()) shareUri else shareUri.replace(prefixes[0], "")
|
||||
}
|
||||
|
||||
private fun verifyClipboard(input: String?, appState: AppState?, dispatch: DispatchFunction) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.tap.features.send.redux.middlewares
|
|||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.TransactionError
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.extensions.isNegative
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.features.send.redux.AmountAction
|
||||
|
|
@ -31,22 +30,29 @@ class AmountMiddleware {
|
|||
|
||||
private fun handleUserInput(data: String, appState: AppState?, dispatch: (Action) -> Unit) {
|
||||
val sendState = appState?.sendState ?: return
|
||||
val amountState = sendState.amountState
|
||||
|
||||
val data = if (data == ".") "0.0" else data
|
||||
val inputValue = when {
|
||||
data.isEmpty() || data == "0" -> BigDecimal.ZERO
|
||||
else -> BigDecimal(data)
|
||||
}
|
||||
if (inputValue.isZero() && amountState.amountToSendCrypto.isZero()) return
|
||||
|
||||
if (inputValue.isZero() && sendState.amountState.amountToSendCrypto.isZero()) return
|
||||
val inputValueCrypto = if (amountState.mainCurrency.type == MainCurrencyType.CRYPTO) {
|
||||
inputValue
|
||||
} else {
|
||||
sendState.convertFiatToExtractCrypto(inputValue)
|
||||
}
|
||||
|
||||
dispatch(AmountAction.SetAmount(inputValue, true))
|
||||
dispatch(AmountAction.SetAmount(inputValueCrypto, true))
|
||||
dispatch(AmountActionUi.CheckAmountToSend)
|
||||
}
|
||||
|
||||
private fun checkAmountToSend(appState: AppState?, dispatch: (Action) -> Unit) {
|
||||
val sendState = appState?.sendState ?: return
|
||||
val walletManager = sendState.walletManager ?: return
|
||||
val typedAmount = sendState.amountState.amountToExtract ?: return
|
||||
|
||||
val inputCrypto = sendState.amountState.amountToSendCrypto
|
||||
if (sendState.amountState.viewAmountValue.value == "0" && inputCrypto.isZero()) {
|
||||
|
|
@ -55,12 +61,8 @@ class AmountMiddleware {
|
|||
return
|
||||
}
|
||||
|
||||
val feeCrypto = sendState.feeState.getCurrentFee()
|
||||
|
||||
val feeAmount = Amount(feeCrypto, walletManager.wallet.blockchain)
|
||||
val totalAmount = Amount(sendState.getTotalAmountToSend(inputCrypto), walletManager.wallet.blockchain)
|
||||
|
||||
val transactionErrors = walletManager.validateTransaction(totalAmount, feeAmount)
|
||||
val amountToSend = Amount(typedAmount, sendState.getTotalAmountToSend(inputCrypto))
|
||||
val transactionErrors = walletManager.validateTransaction(amountToSend, sendState.feeState.currentFee)
|
||||
if (transactionErrors.isEmpty()) {
|
||||
dispatch(AmountAction.SetAmountError(null))
|
||||
} else {
|
||||
|
|
@ -84,27 +86,20 @@ class AmountMiddleware {
|
|||
}
|
||||
|
||||
private fun setMaxAmount(appState: AppState?, dispatch: (Action) -> Unit) {
|
||||
val sendState = appState?.sendState ?: return
|
||||
val amountState = sendState.amountState
|
||||
val amountState = appState?.sendState?.amountState ?: return
|
||||
|
||||
val maxAmount = if (sendState.feeState.feeIsIncluded) amountState.balanceCrypto
|
||||
else amountState.balanceCrypto.minus(sendState.feeState.getCurrentFee())
|
||||
|
||||
if (maxAmount.isNegative()) {
|
||||
dispatch(AmountAction.SetAmountError(TapError.FeeExceedsBalance))
|
||||
} else {
|
||||
val currentCurrencyValue = if (amountState.mainCurrency.type == MainCurrencyType.CRYPTO) maxAmount
|
||||
else sendState.convertToFiat(maxAmount)
|
||||
|
||||
dispatch(AmountAction.SetAmount(currentCurrencyValue, false))
|
||||
}
|
||||
dispatch(AmountAction.SetAmount(amountState.balanceCrypto, false))
|
||||
}
|
||||
|
||||
private fun toggleMainCurrency(appState: AppState?, dispatch: (Action) -> Unit) {
|
||||
val amountState = appState?.sendState?.amountState ?: return
|
||||
if (!appState.sendState.coinIsConvertible()) return
|
||||
|
||||
val type = if (amountState.mainCurrency.type == MainCurrencyType.FIAT) MainCurrencyType.CRYPTO
|
||||
else MainCurrencyType.FIAT
|
||||
val type = if (amountState.mainCurrency.type == MainCurrencyType.FIAT) {
|
||||
MainCurrencyType.CRYPTO
|
||||
} else {
|
||||
MainCurrencyType.FIAT
|
||||
}
|
||||
|
||||
dispatch(AmountActionUi.SetMainCurrency(type))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -41,14 +42,11 @@ val sendMiddleware: Middleware<AppState> = { dispatch, appState ->
|
|||
private fun verifyAndSendTransaction(appState: AppState?, dispatch: (Action) -> Unit) {
|
||||
val sendState = appState?.sendState ?: return
|
||||
val walletManager = appState.globalState.scanNoteResponse?.walletManager ?: return
|
||||
val recipientAddress = sendState.addressPayIdState.recipientWalletAddress ?: return
|
||||
val typedAmount = sendState.amountState.amountToExtract ?: return
|
||||
val feeAmount = sendState.feeState.currentFee ?: return
|
||||
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
val recipientAddress = sendState.addressPayIdState.recipientWalletAddress!!
|
||||
|
||||
val feeAmount = Amount(sendState.feeState.getCurrentFee(), blockchain)
|
||||
val amountToSend = Amount(sendState.getTotalAmountToSend(), blockchain, recipientAddress)
|
||||
|
||||
val txSender = walletManager as TransactionSender
|
||||
val amountToSend = Amount(typedAmount, sendState.getTotalAmountToSend())
|
||||
|
||||
val verifyResult = walletManager.validateTransaction(amountToSend, feeAmount)
|
||||
if (verifyResult.isNotEmpty()) {
|
||||
|
|
@ -59,7 +57,8 @@ private fun verifyAndSendTransaction(appState: AppState?, dispatch: (Action) ->
|
|||
dispatch(SendAction.ChangeSendButtonState(SendButtonState.PROGRESS))
|
||||
val txData = walletManager.createTransaction(amountToSend, feeAmount, recipientAddress)
|
||||
scope.launch {
|
||||
val result = txSender.send(txData, Signer(tangemSdk))
|
||||
walletManager.update()
|
||||
val result = (walletManager as TransactionSender).send(txData, Signer(tangemSdk))
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
is SimpleResult.Success -> {
|
||||
|
|
@ -78,6 +77,7 @@ private fun verifyAndSendTransaction(appState: AppState?, dispatch: (Action) ->
|
|||
// user was cancelled the operation by closing the Sdk bottom sheet
|
||||
}
|
||||
else -> {
|
||||
Timber.e(result.error)
|
||||
dispatch(SendAction.SendError(TapError.BlockchainInternalError))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ class AddressPayIdReducer : SendInternalReducer {
|
|||
is AddressPayIdActionUi.HandleUserInput -> state
|
||||
is AddressPayIdActionUi.SetTruncateHandler -> state.copy(truncateHandler = action.handler)
|
||||
is AddressPayIdActionUi.TruncateOrRestore -> {
|
||||
val value = if (action.truncate) state.truncatedFieldValue ?: ""
|
||||
else state.normalFieldValue ?: ""
|
||||
val value = if (action.truncate) state.truncatedFieldValue ?: "" else state.normalFieldValue ?: ""
|
||||
state.copy(viewFieldValue = state.viewFieldValue.copy(value = value))
|
||||
}
|
||||
is AddressPayIdActionUi.PasteAddressPayId -> return sendState
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.send.redux.reducers
|
||||
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.extensions.scaleToFiat
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.features.send.redux.AmountAction
|
||||
import com.tangem.tap.features.send.redux.AmountActionUi
|
||||
|
|
@ -26,16 +25,21 @@ class AmountReducer : SendInternalReducer {
|
|||
private fun handleUiAction(action: AmountActionUi, sendState: SendState, state: AmountState): SendState {
|
||||
val result = when (action) {
|
||||
is SetMainCurrency -> {
|
||||
when (action.mainCurrency) {
|
||||
val currencyCanBeSwitched = sendState.mainCurrencyCanBeSwitched()
|
||||
|
||||
when (val currency = if (currencyCanBeSwitched) action.mainCurrency else MainCurrencyType.CRYPTO) {
|
||||
MainCurrencyType.FIAT -> {
|
||||
val fiatToSend = if (state.amountToSendCrypto.isZero()) BigDecimal.ZERO
|
||||
else sendState.convertToFiat(state.amountToSendCrypto)
|
||||
val rescaledBalance = sendState.convertToFiat(state.balanceCrypto, true)
|
||||
val fiatToSend = if (state.amountToSendCrypto.isZero()) {
|
||||
BigDecimal.ZERO
|
||||
} else {
|
||||
sendState.convertExtractCryptoToFiat(state.amountToSendCrypto)
|
||||
}
|
||||
val rescaledBalance = sendState.convertExtractCryptoToFiat(state.balanceCrypto, true)
|
||||
state.copy(
|
||||
viewAmountValue = InputViewValue(fiatToSend.stripZeroPlainString()),
|
||||
viewBalanceValue = rescaledBalance.stripZeroPlainString(),
|
||||
mainCurrency = state.createMainCurrency(action.mainCurrency),
|
||||
maxLengthOfAmount = sendState.getDecimals(action.mainCurrency),
|
||||
mainCurrency = state.createMainCurrency(currency, currencyCanBeSwitched),
|
||||
maxLengthOfAmount = sendState.getDecimals(currency),
|
||||
cursorAtTheSamePosition = false
|
||||
)
|
||||
}
|
||||
|
|
@ -43,8 +47,8 @@ class AmountReducer : SendInternalReducer {
|
|||
state.copy(
|
||||
viewAmountValue = InputViewValue(state.amountToSendCrypto.stripZeroPlainString()),
|
||||
viewBalanceValue = state.balanceCrypto.stripZeroPlainString(),
|
||||
mainCurrency = state.createMainCurrency(action.mainCurrency),
|
||||
maxLengthOfAmount = sendState.getDecimals(action.mainCurrency),
|
||||
mainCurrency = state.createMainCurrency(currency, currencyCanBeSwitched),
|
||||
maxLengthOfAmount = sendState.getDecimals(currency),
|
||||
cursorAtTheSamePosition = false
|
||||
)
|
||||
}
|
||||
|
|
@ -59,25 +63,17 @@ class AmountReducer : SendInternalReducer {
|
|||
private fun handleAction(action: AmountAction, sendState: SendState, state: AmountState): SendState {
|
||||
val result = when (action) {
|
||||
is AmountAction.SetAmount -> {
|
||||
when (state.mainCurrency.type) {
|
||||
MainCurrencyType.FIAT -> {
|
||||
val amountCrypto = sendState.convertToCrypto(action.amount)
|
||||
state.copy(
|
||||
viewAmountValue = InputViewValue(action.amount.scaleToFiat(false).stripZeroPlainString(), action.isUserInput),
|
||||
amountToSendCrypto = amountCrypto,
|
||||
cursorAtTheSamePosition = true,
|
||||
error = null
|
||||
)
|
||||
}
|
||||
MainCurrencyType.CRYPTO -> {
|
||||
state.copy(
|
||||
viewAmountValue = InputViewValue(action.amount.stripZeroPlainString(), action.isUserInput),
|
||||
amountToSendCrypto = action.amount,
|
||||
cursorAtTheSamePosition = true,
|
||||
error = null
|
||||
)
|
||||
}
|
||||
val amount = if (state.mainCurrency.type == MainCurrencyType.CRYPTO) {
|
||||
action.amountCrypto
|
||||
} else {
|
||||
sendState.convertExtractCryptoToFiat(action.amountCrypto, true)
|
||||
}
|
||||
state.copy(
|
||||
viewAmountValue = InputViewValue(amount.stripZeroPlainString(), action.isUserInput),
|
||||
amountToSendCrypto = action.amountCrypto,
|
||||
cursorAtTheSamePosition = true,
|
||||
error = null
|
||||
)
|
||||
}
|
||||
is AmountAction.SetAmountError -> {
|
||||
state.copy(error = action.error)
|
||||
|
|
|
|||
|
|
@ -2,95 +2,91 @@ package com.tangem.tap.features.send.redux.reducers
|
|||
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.tap.common.CurrencyConverter
|
||||
import com.tangem.tap.common.extensions.scaleToFiat
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.features.send.redux.ReceiptAction.RefreshReceipt
|
||||
import com.tangem.tap.features.send.redux.SendScreenAction
|
||||
import com.tangem.tap.features.send.redux.states.*
|
||||
import com.tangem.tap.store
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class ReceiptReducer : SendInternalReducer {
|
||||
|
||||
companion object {
|
||||
const val EMPTY = "-"
|
||||
}
|
||||
|
||||
private lateinit var sendState: SendState
|
||||
private lateinit var amountState: AmountState
|
||||
private lateinit var feeState: FeeState
|
||||
|
||||
override fun handle(action: SendScreenAction, sendState: SendState): SendState {
|
||||
this.sendState = sendState
|
||||
this.amountState = sendState.amountState
|
||||
this.feeState = sendState.feeState
|
||||
|
||||
return when (action) {
|
||||
is RefreshReceipt -> handleRefresh(action, sendState, sendState.receiptState)
|
||||
is RefreshReceipt -> handleRefresh(action, sendState.receiptState)
|
||||
else -> sendState
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun handleRefresh(action: RefreshReceipt, sendState: SendState, state: ReceiptState): SendState {
|
||||
private fun handleRefresh(action: RefreshReceipt, state: ReceiptState): SendState {
|
||||
val wallet = sendState.walletManager?.wallet ?: return sendState
|
||||
|
||||
val coinConverter = sendState.coinConverter
|
||||
val tokenConverter = sendState.tokenConverter
|
||||
val amountState = sendState.amountState
|
||||
val feeState = sendState.feeState
|
||||
|
||||
val layoutType = determineLayoutType(amountState.mainCurrency.type, sendState.amountState.typeOfAmount)
|
||||
val layoutType = determineLayoutType(amountState.mainCurrency.type, amountState.typeOfAmount)
|
||||
val symbols = determineSymbols(wallet)
|
||||
val showBlank = !sendState.isReadyToSend()
|
||||
val result = state.copy(
|
||||
visibleTypeOfReceipt = layoutType,
|
||||
mainCurrency = sendState.amountState.mainCurrency,
|
||||
fiat = createFiatType(coinConverter, amountState, feeState, symbols, showBlank),
|
||||
crypto = createCryptoType(coinConverter, amountState, feeState, symbols, showBlank),
|
||||
tokenFiat = createTokenFiatType(coinConverter, tokenConverter, amountState, feeState, symbols, showBlank),
|
||||
tokenCrypto = createTokenCryptoType(coinConverter, tokenConverter, amountState, feeState, symbols, showBlank)
|
||||
mainCurrency = amountState.mainCurrency,
|
||||
fiat = createFiatType(symbols, showBlank),
|
||||
crypto = createCryptoType(symbols, showBlank),
|
||||
tokenFiat = createTokenFiatType(symbols, showBlank),
|
||||
tokenCrypto = createTokenCryptoType(symbols, showBlank)
|
||||
)
|
||||
return updateLastState(sendState.copy(receiptState = result), result)
|
||||
}
|
||||
|
||||
private fun createFiatType(
|
||||
converter: CurrencyConverter,
|
||||
amountState: AmountState,
|
||||
feeState: FeeState,
|
||||
symbols: ReceiptSymbols,
|
||||
showBlank: Boolean
|
||||
): ReceiptFiat {
|
||||
val feeCrypto = feeState.getCurrentFee()
|
||||
val feeFiat = converter.toFiatWithPrecision(feeCrypto)
|
||||
private fun createFiatType(symbols: ReceiptSymbols, showBlank: Boolean): ReceiptFiat {
|
||||
val feeCrypto = feeState.getCurrentFeeValue()
|
||||
val feeFiat = convertToFiatPrecision(feeCrypto)
|
||||
|
||||
if (showBlank) {
|
||||
return ReceiptFiat("0", feeFiat.stripZeroPlainString(), "0", "0", symbols)
|
||||
return ReceiptFiat("0", feeFiat, "0", "0", symbols)
|
||||
}
|
||||
|
||||
return if (feeState.feeIsIncluded) {
|
||||
val amountFiat = converter.toFiatWithPrecision(amountState.amountToSendCrypto.minus(feeCrypto))
|
||||
val totalFiat = converter.toFiatWithPrecision(amountState.amountToSendCrypto)
|
||||
val amountFiat = convertToFiatPrecision(amountState.amountToSendCrypto.minus(feeCrypto))
|
||||
val totalFiat = convertToFiatPrecision(amountState.amountToSendCrypto)
|
||||
ReceiptFiat(
|
||||
amountFiat = amountFiat.stripZeroPlainString(),
|
||||
feeFiat = feeFiat.stripZeroPlainString(),
|
||||
totalFiat = totalFiat.stripZeroPlainString(),
|
||||
amountFiat = amountFiat,
|
||||
feeFiat = feeFiat,
|
||||
totalFiat = totalFiat,
|
||||
willSentCrypto = amountState.amountToSendCrypto.stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
} else {
|
||||
val totalAmountCrypto = amountState.amountToSendCrypto.plus(feeCrypto)
|
||||
val amountFiat = converter.toFiatWithPrecision(amountState.amountToSendCrypto)
|
||||
val totalFiat = converter.toFiatWithPrecision(totalAmountCrypto)
|
||||
val amountFiat = convertToFiatPrecision(amountState.amountToSendCrypto)
|
||||
val totalFiat = convertToFiatPrecision(totalAmountCrypto)
|
||||
ReceiptFiat(
|
||||
amountFiat = amountFiat.stripZeroPlainString(),
|
||||
feeFiat = feeFiat.stripZeroPlainString(),
|
||||
totalFiat = totalFiat.stripZeroPlainString(),
|
||||
amountFiat = amountFiat,
|
||||
feeFiat = feeFiat,
|
||||
totalFiat = totalFiat,
|
||||
willSentCrypto = totalAmountCrypto.stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCryptoType(
|
||||
converter: CurrencyConverter,
|
||||
amountState: AmountState,
|
||||
feeState: FeeState,
|
||||
symbols: ReceiptSymbols,
|
||||
showBlank: Boolean
|
||||
): ReceiptCrypto {
|
||||
val feeCrypto = feeState.getCurrentFee()
|
||||
val feeFiat = converter.toFiatWithPrecision(feeCrypto)
|
||||
private fun createCryptoType(symbols: ReceiptSymbols, showBlank: Boolean): ReceiptCrypto {
|
||||
val feeCrypto = feeState.getCurrentFeeValue()
|
||||
val feeFiat = convertToFiatPrecision(feeCrypto)
|
||||
if (showBlank) {
|
||||
return ReceiptCrypto("0", feeCrypto.stripZeroPlainString(), "0", "0", "0", symbols)
|
||||
}
|
||||
|
|
@ -100,8 +96,8 @@ class ReceiptReducer : SendInternalReducer {
|
|||
amountCrypto = amountState.amountToSendCrypto.minus(feeCrypto).stripZeroPlainString(),
|
||||
feeCrypto = feeCrypto.stripZeroPlainString(),
|
||||
totalCrypto = amountState.amountToSendCrypto.stripZeroPlainString(),
|
||||
feeFiat = feeFiat.stripZeroPlainString(),
|
||||
willSentFiat = converter.toFiatWithPrecision(amountState.amountToSendCrypto).stripZeroPlainString(),
|
||||
feeFiat = feeFiat,
|
||||
willSentFiat = convertToFiatPrecision(amountState.amountToSendCrypto),
|
||||
symbols = symbols
|
||||
)
|
||||
} else {
|
||||
|
|
@ -110,65 +106,73 @@ class ReceiptReducer : SendInternalReducer {
|
|||
amountCrypto = amountState.amountToSendCrypto.stripZeroPlainString(),
|
||||
feeCrypto = feeCrypto.stripZeroPlainString(),
|
||||
totalCrypto = totalCrypto.stripZeroPlainString(),
|
||||
feeFiat = feeFiat.stripZeroPlainString(),
|
||||
willSentFiat = converter.toFiatWithPrecision(totalCrypto).stripZeroPlainString(),
|
||||
feeFiat = feeFiat,
|
||||
willSentFiat = convertToFiatPrecision(totalCrypto),
|
||||
symbols = symbols
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTokenFiatType(
|
||||
coinConverter: CurrencyConverter,
|
||||
tokenConverter: CurrencyConverter,
|
||||
amountState: AmountState,
|
||||
feeState: FeeState,
|
||||
symbols: ReceiptSymbols,
|
||||
showBlank: Boolean
|
||||
): ReceiptTokenFiat {
|
||||
val feeCoin = feeState.getCurrentFee()
|
||||
val feeFiat = coinConverter.toFiatWithPrecision(feeCoin)
|
||||
private fun createTokenFiatType(symbols: ReceiptSymbols, showBlank: Boolean): ReceiptTokenFiat {
|
||||
val feeCoin = feeState.getCurrentFeeValue()
|
||||
if (showBlank) {
|
||||
return ReceiptTokenFiat("0", feeFiat.stripZeroPlainString(), "0", "0", "0", symbols)
|
||||
val feeFiat = convertToFiatPrecision(feeCoin)
|
||||
return ReceiptTokenFiat("0", feeFiat, "0", "0", "0", symbols)
|
||||
}
|
||||
|
||||
val tokensToSend = amountState.amountToSendCrypto
|
||||
val amountFiat = tokenConverter.toFiatUnscaled(tokensToSend)
|
||||
val totalFiat = amountFiat.plus(feeFiat)
|
||||
|
||||
return ReceiptTokenFiat(
|
||||
amountFiat = amountFiat.scaleToFiat().stripZeroPlainString(),
|
||||
feeFiat = feeFiat.stripZeroPlainString(),
|
||||
totalFiat = totalFiat.scaleToFiat().stripZeroPlainString(),
|
||||
willSentToken = tokensToSend.stripZeroPlainString(),
|
||||
willSentFeeCoin = feeCoin.stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
return if (sendState.coinIsConvertible() && sendState.tokenIsConvertible()) {
|
||||
val feeFiat = sendState.coinConverter!!.toFiatUnscaled(feeCoin)
|
||||
val amountFiat = sendState.tokenConverter!!.toFiatUnscaled(tokensToSend)
|
||||
val totalFiat = amountFiat.plus(feeFiat)
|
||||
ReceiptTokenFiat(
|
||||
amountFiat = amountFiat.scaleToFiat(true).stripZeroPlainString(),
|
||||
feeFiat = feeFiat.scaleToFiat(true).stripZeroPlainString(),
|
||||
totalFiat = totalFiat.scaleToFiat(true).stripZeroPlainString(),
|
||||
willSentToken = tokensToSend.stripZeroPlainString(),
|
||||
willSentFeeCoin = feeCoin.stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
} else {
|
||||
ReceiptTokenFiat(
|
||||
amountFiat = EMPTY,
|
||||
feeFiat = EMPTY,
|
||||
totalFiat = EMPTY,
|
||||
willSentToken = tokensToSend.stripZeroPlainString(),
|
||||
willSentFeeCoin = feeCoin.stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTokenCryptoType(
|
||||
coinConverter: CurrencyConverter,
|
||||
tokenConverter: CurrencyConverter,
|
||||
amountState: AmountState,
|
||||
feeState: FeeState,
|
||||
symbols: ReceiptSymbols,
|
||||
showBlank: Boolean
|
||||
): ReceiptTokenCrypto {
|
||||
val feeCoin = feeState.getCurrentFee()
|
||||
private fun createTokenCryptoType(symbols: ReceiptSymbols, showBlank: Boolean): ReceiptTokenCrypto {
|
||||
val feeCoin = feeState.getCurrentFeeValue()
|
||||
if (showBlank) {
|
||||
return ReceiptTokenCrypto("0", feeCoin.stripZeroPlainString(), "0", symbols)
|
||||
}
|
||||
|
||||
val tokensToSend = amountState.amountToSendCrypto
|
||||
val tokenFiat = tokenConverter.toFiatUnscaled(tokensToSend)
|
||||
val feeFiat = coinConverter.toFiatUnscaled(feeCoin)
|
||||
val totalFiat = tokenFiat.plus(feeFiat)
|
||||
|
||||
return ReceiptTokenCrypto(
|
||||
amountToken = tokensToSend.stripZeroPlainString(),
|
||||
feeCoin = feeCoin.stripZeroPlainString(),
|
||||
totalFiat = totalFiat.scaleToFiat().stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
return if (sendState.coinIsConvertible() && sendState.tokenIsConvertible()) {
|
||||
val tokenFiat = sendState.tokenConverter!!.toFiatUnscaled(tokensToSend)
|
||||
val feeFiat = sendState.coinConverter!!.toFiatUnscaled(feeCoin)
|
||||
val totalFiat = tokenFiat.plus(feeFiat)
|
||||
|
||||
ReceiptTokenCrypto(
|
||||
amountToken = tokensToSend.stripZeroPlainString(),
|
||||
feeCoin = feeCoin.stripZeroPlainString(),
|
||||
totalFiat = totalFiat.scaleToFiat(true).stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
} else {
|
||||
ReceiptTokenCrypto(
|
||||
amountToken = tokensToSend.stripZeroPlainString(),
|
||||
feeCoin = feeCoin.stripZeroPlainString(),
|
||||
totalFiat = EMPTY,
|
||||
symbols = symbols
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun determineSymbols(wallet: Wallet): ReceiptSymbols {
|
||||
|
|
@ -193,4 +197,12 @@ class ReceiptReducer : SendInternalReducer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertToFiatPrecision(value: BigDecimal, isToken: Boolean = false): String {
|
||||
return when {
|
||||
!isToken && sendState.coinIsConvertible() -> sendState.coinConverter!!.toFiatWithPrecision(value).stripZeroPlainString()
|
||||
isToken && sendState.tokenIsConvertible() -> sendState.tokenConverter!!.toFiatWithPrecision(value).stripZeroPlainString()
|
||||
else -> EMPTY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -56,25 +56,22 @@ private class PrepareSendScreenStatesReducer : SendInternalReducer {
|
|||
override fun handle(action: SendScreenAction, sendState: SendState): SendState {
|
||||
val prepareAction = action as PrepareSendScreen
|
||||
val walletManager = store.state.globalState.scanNoteResponse!!.walletManager!!
|
||||
val walletAmount = prepareAction.tokenAmount ?: prepareAction.coinAmount!!
|
||||
val decimals = walletAmount.decimals
|
||||
val amountToExtract = prepareAction.tokenAmount ?: prepareAction.coinAmount!!
|
||||
val decimals = amountToExtract.decimals
|
||||
|
||||
val coinConverter = createCurrencyConverter(walletManager.wallet.blockchain.currency, decimals)
|
||||
val tokenConverter = createCurrencyConverter(prepareAction.tokenAmount?.currencySymbol ?: "", decimals)
|
||||
if (coinConverter == null || (walletAmount.type == AmountType.Token && tokenConverter == null)) {
|
||||
return sendState.copy(hasInitializationError = true)
|
||||
}
|
||||
return sendState.copy(
|
||||
walletManager = walletManager,
|
||||
coinConverter = coinConverter,
|
||||
tokenConverter = tokenConverter ?: CurrencyConverter(BigDecimal.ONE, decimals),
|
||||
tokenConverter = tokenConverter,
|
||||
amountState = sendState.amountState.copy(
|
||||
walletAmount = walletAmount,
|
||||
typeOfAmount = walletAmount.type,
|
||||
balanceCrypto = walletAmount.value ?: BigDecimal.ZERO
|
||||
amountToExtract = amountToExtract,
|
||||
typeOfAmount = amountToExtract.type,
|
||||
balanceCrypto = amountToExtract.value ?: BigDecimal.ZERO
|
||||
),
|
||||
feeState = sendState.feeState.copy(
|
||||
includeFeeSwitcherIsEnabled = walletAmount.type == AmountType.Coin
|
||||
includeFeeSwitcherIsEnabled = amountToExtract.type == AmountType.Coin
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,5 +27,5 @@ data class FeeState(
|
|||
|
||||
fun isReady(): Boolean = error == null && currentFee != null
|
||||
|
||||
fun getCurrentFee(): BigDecimal = currentFee?.value ?: BigDecimal.ZERO
|
||||
fun getCurrentFeeValue(): BigDecimal = currentFee?.value ?: BigDecimal.ZERO
|
||||
}
|
||||
|
|
@ -27,15 +27,14 @@ interface SendScreenState : StateType, IdStateHolder
|
|||
|
||||
data class SendState(
|
||||
val walletManager: WalletManager? = null,
|
||||
val coinConverter: CurrencyConverter = CurrencyConverter(BigDecimal.ONE, 2),
|
||||
val tokenConverter: CurrencyConverter = CurrencyConverter(BigDecimal.ONE, 2),
|
||||
val coinConverter: CurrencyConverter? = null,
|
||||
val tokenConverter: CurrencyConverter? = null,
|
||||
val lastChangedStates: LinkedHashSet<StateId> = linkedSetOf(),
|
||||
val addressPayIdState: AddressPayIdState = AddressPayIdState(),
|
||||
val amountState: AmountState = AmountState(),
|
||||
val feeState: FeeState = FeeState(),
|
||||
val receiptState: ReceiptState = ReceiptState(),
|
||||
val sendButtonState: SendButtonState = SendButtonState.DISABLED,
|
||||
val hasInitializationError: Boolean = false
|
||||
val sendButtonState: SendButtonState = SendButtonState.DISABLED
|
||||
) : SendScreenState {
|
||||
|
||||
override val stateId: StateId = StateId.SEND_SCREEN
|
||||
|
|
@ -49,28 +48,61 @@ data class SendState(
|
|||
|
||||
fun getDecimals(type: MainCurrencyType): Int = when (type) {
|
||||
MainCurrencyType.FIAT -> 2
|
||||
MainCurrencyType.CRYPTO -> amountState.walletAmount?.decimals ?: 0
|
||||
MainCurrencyType.CRYPTO -> amountState.amountToExtract?.decimals ?: 0
|
||||
}
|
||||
|
||||
fun getConverter(): CurrencyConverter {
|
||||
return if (amountState.typeOfAmount == AmountType.Coin) coinConverter
|
||||
else tokenConverter
|
||||
fun convertFiatToCoin(value: BigDecimal): BigDecimal {
|
||||
return if (!this.coinIsConvertible()) value else coinConverter!!.toCrypto(value)
|
||||
}
|
||||
|
||||
fun convertToCrypto(value: BigDecimal): BigDecimal {
|
||||
return getConverter().toCrypto(value)
|
||||
fun convertFiatToToken(value: BigDecimal): BigDecimal {
|
||||
return if (!this.tokenIsConvertible()) value else tokenConverter!!.toCrypto(value)
|
||||
}
|
||||
|
||||
fun convertToFiat(value: BigDecimal, scaleWithPrecision: Boolean = false): BigDecimal {
|
||||
val converter = getConverter()
|
||||
fun convertCoinToFiat(value: BigDecimal, scaleWithPrecision: Boolean = false): BigDecimal {
|
||||
if (!this.coinIsConvertible()) return value
|
||||
|
||||
val converter = coinConverter!!
|
||||
return if (!scaleWithPrecision) converter.toFiat(value) else converter.toFiatWithPrecision(value)
|
||||
}
|
||||
|
||||
fun convertTokenToFiat(value: BigDecimal, scaleWithPrecision: Boolean = false): BigDecimal {
|
||||
if (!this.tokenIsConvertible()) return value
|
||||
|
||||
val converter = tokenConverter!!
|
||||
return if (!scaleWithPrecision) converter.toFiat(value) else converter.toFiatWithPrecision(value)
|
||||
}
|
||||
|
||||
fun convertFiatToExtractCrypto(fiatValue: BigDecimal): BigDecimal = when (amountState.typeOfAmount) {
|
||||
AmountType.Coin -> convertFiatToCoin(fiatValue)
|
||||
AmountType.Token -> convertFiatToToken(fiatValue)
|
||||
AmountType.Reserve -> fiatValue
|
||||
}
|
||||
|
||||
fun convertExtractCryptoToFiat(cryptoValue: BigDecimal, scaleWithPrecision: Boolean = false): BigDecimal {
|
||||
return when (amountState.typeOfAmount) {
|
||||
AmountType.Coin -> convertCoinToFiat(cryptoValue, scaleWithPrecision)
|
||||
AmountType.Token -> convertTokenToFiat(cryptoValue, scaleWithPrecision)
|
||||
AmountType.Reserve -> cryptoValue
|
||||
}
|
||||
}
|
||||
|
||||
fun getButtonState(): SendButtonState = if (isReadyToSend()) SendButtonState.ENABLED else SendButtonState.DISABLED
|
||||
|
||||
fun getTotalAmountToSend(value: BigDecimal = amountState.amountToSendCrypto): BigDecimal {
|
||||
val needToExtractFee = amountState.isCoinAmount() && feeState.feeIsIncluded
|
||||
return if (needToExtractFee) value.minus(feeState.getCurrentFee()) else value
|
||||
return if (needToExtractFee) value.minus(feeState.getCurrentFeeValue()) else value
|
||||
}
|
||||
|
||||
fun coinIsConvertible(): Boolean = coinConverter != null
|
||||
fun tokenIsConvertible(): Boolean = tokenConverter != null
|
||||
|
||||
fun mainCurrencyCanBeSwitched(): Boolean {
|
||||
return when (amountState.typeOfAmount) {
|
||||
AmountType.Coin -> coinIsConvertible()
|
||||
AmountType.Token -> tokenIsConvertible()
|
||||
AmountType.Reserve -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +111,7 @@ enum class SendButtonState {
|
|||
}
|
||||
|
||||
data class AmountState(
|
||||
val walletAmount: Amount? = null,
|
||||
val amountToExtract: Amount? = null,
|
||||
val typeOfAmount: AmountType = AmountType.Coin,
|
||||
val viewAmountValue: InputViewValue = InputViewValue(BigDecimal.ZERO.toPlainString()),
|
||||
val viewBalanceValue: String = BigDecimal.ZERO.toPlainString(),
|
||||
|
|
@ -97,10 +129,11 @@ data class AmountState(
|
|||
|
||||
fun isCoinAmount(): Boolean = typeOfAmount == AmountType.Coin
|
||||
|
||||
fun createMainCurrency(type: MainCurrencyType): MainCurrency {
|
||||
return when (type) {
|
||||
fun createMainCurrency(type: MainCurrencyType, canSwitched: Boolean): MainCurrency {
|
||||
return if (!canSwitched) MainCurrency(type, amountToExtract?.currencySymbol ?: "NONE", false)
|
||||
else when (type) {
|
||||
MainCurrencyType.FIAT -> MainCurrency(type, store.state.globalState.appCurrency)
|
||||
MainCurrencyType.CRYPTO -> MainCurrency(type, walletAmount?.currencySymbol ?: "NONE")
|
||||
MainCurrencyType.CRYPTO -> MainCurrency(type, amountToExtract?.currencySymbol ?: "NONE")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -112,5 +145,6 @@ enum class MainCurrencyType {
|
|||
|
||||
data class MainCurrency(
|
||||
val type: MainCurrencyType,
|
||||
val currencySymbol: String
|
||||
val currencySymbol: String,
|
||||
val isEnabled: Boolean = true
|
||||
)
|
||||
|
|
@ -16,7 +16,6 @@ import com.tangem.tap.common.extensions.getDrawableCompat
|
|||
import com.tangem.tap.common.extensions.getFromClipboard
|
||||
import com.tangem.tap.common.extensions.setOnImeActionListener
|
||||
import com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.common.snackBar.MaxAmountSnackbar
|
||||
import com.tangem.tap.common.text.truncateMiddleWith
|
||||
import com.tangem.tap.common.toggleWidget.*
|
||||
|
|
@ -58,11 +57,6 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (store.state.sendState.hasInitializationError) {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
return
|
||||
}
|
||||
|
||||
initSendButtonStates()
|
||||
setupAddressOrPayIdLayout()
|
||||
setupAmountLayout()
|
||||
|
|
@ -193,8 +187,6 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
}
|
||||
|
||||
override fun subscribeToStore() {
|
||||
if (store.state.sendState.hasInitializationError) return
|
||||
|
||||
store.subscribe(sendSubscriber) { appState ->
|
||||
appState.skipRepeats { oldState, newState ->
|
||||
oldState.sendState == newState.sendState
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.tap.domain.assembleErrorIds
|
|||
import com.tangem.tap.features.send.BaseStoreFragment
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.Error
|
||||
import com.tangem.tap.features.send.redux.FeeAction
|
||||
import com.tangem.tap.features.send.redux.reducers.ReceiptReducer
|
||||
import com.tangem.tap.features.send.redux.states.*
|
||||
import com.tangem.tap.features.send.ui.FeeUiHelper
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
|
|
@ -74,8 +75,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
Error.ADDRESS_SAME_AS_WALLET -> R.string.error_address_same_as_wallet
|
||||
else -> null
|
||||
}
|
||||
return if (resId == null) null
|
||||
else context.getString(resId)
|
||||
return if (resId == null) null else context.getString(resId)
|
||||
}
|
||||
fg.imvPaste.isEnabled = state.pasteIsEnabled
|
||||
|
||||
|
|
@ -183,6 +183,8 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
fun getString(id: Int): String = mainLayout.context.getString(id)
|
||||
|
||||
val rough = getString(R.string.sign_rough)
|
||||
fun roughOrEmpty(value: String): String = if (value == ReceiptReducer.EMPTY) value else "$rough $value"
|
||||
|
||||
when (state.visibleTypeOfReceipt) {
|
||||
ReceiptLayoutType.FIAT -> {
|
||||
val receipt = state.fiat ?: return
|
||||
|
|
@ -191,7 +193,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
totalTokenLayout.show(false)
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("$rough ${receipt.totalFiat} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
|
||||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold { append(receipt.willSentCrypto) }.append(" ")
|
||||
|
|
@ -211,8 +213,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold {
|
||||
append(rough).append(" ")
|
||||
append(receipt.willSentFiat).append(" ")
|
||||
append(roughOrEmpty(receipt.willSentFiat)).append(" ")
|
||||
append(receipt.symbols.fiat)
|
||||
append(" (fee: ${receipt.feeFiat} ")
|
||||
append(receipt.symbols.fiat).append(")")
|
||||
|
|
@ -226,7 +227,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
totalTokenLayout.show(false)
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("${receipt.totalFiat} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
|
||||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold {
|
||||
|
|
@ -252,8 +253,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold {
|
||||
append(getString(R.string.sign_rough)).append(" ")
|
||||
append(receipt.totalFiat).append(" ")
|
||||
append(roughOrEmpty(receipt.totalFiat)).append(" ")
|
||||
append(receipt.symbols.fiat)
|
||||
}
|
||||
totalTokenLayout.tvTotalTokenCryptoValue.update(willSent.toString())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue