From 9e399946d7a03ab910442c5b1aa8925334a81315 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sat, 19 Sep 2020 21:58:22 +0300 Subject: [PATCH] Updated on 2026-08-14 --- app/build.gradle | 2 +- .../tangem/tap/common/CurrencyConverter.kt | 27 +++-- .../tangem/tap/common/extensions/Specific.kt | 25 ++++- .../common/redux/NotificationsMiddleware.kt | 29 +++-- .../java/com/tangem/tap/domain/TapErrors.kt | 44 ++++++-- .../features/send/redux/SendScreenAction.kt | 7 +- .../redux/middlewares/AmountMiddleware.kt | 100 ++++++------------ .../send/redux/reducers/AmountReducer.kt | 28 ++--- .../send/redux/reducers/ReceiptReducer.kt | 76 +++++++------ .../send/redux/reducers/SendScreenReducer.kt | 31 ++++-- .../send/redux/states/AddressPayIdState.kt | 5 +- .../features/send/redux/states/FeeState.kt | 5 +- .../send/redux/states/ReceiptState.kt | 13 +-- .../features/send/redux/states/SendState.kt | 51 +++++++-- .../tap/features/send/ui/SendFragment.kt | 8 ++ .../stateSubscribers/SendStateSubscriber.kt | 41 +++---- app/src/main/res/values/strings.xml | 10 +- 17 files changed, 304 insertions(+), 198 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7a6c354f62..56fa51dc9b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -64,7 +64,7 @@ dependencies { implementation 'com.google.android.material:material:1.2.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10' - implementation 'com.tangem:blockchain:1.31.0' + implementation 'com.tangem:blockchain:1.35.0' //lifecycle implementation "androidx.lifecycle:lifecycle-runtime:2.2.0" diff --git a/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt b/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt index 07ac39e6dc..0ca9b929bd 100644 --- a/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt @@ -1,23 +1,36 @@ package com.tangem.tap.common import com.tangem.common.extensions.isZero +import com.tangem.tap.common.extensions.scaleToFiat import java.math.BigDecimal import java.math.RoundingMode /** [REDACTED_AUTHOR] */ -class CurrencyConverter(var rateValue: BigDecimal) { +class CurrencyConverter( + private val rateValue: BigDecimal, + private val decimals: Int +) { + private val roundingMode = RoundingMode.DOWN - fun toFiat(crypto: BigDecimal, decimals: Int = 2): BigDecimal { - return rateValue.multiply(crypto).setScale(decimals, RoundingMode.DOWN) + fun toFiat(crypto: BigDecimal, fiatDecimals: Int = 2): BigDecimal { + return toFiatUnscaled(crypto).setScale(fiatDecimals, roundingMode) } - fun toCrypto(fiat: BigDecimal, decimals: Int): BigDecimal { - if (fiat.isZero() || rateValue.isZero()) return fiat + fun toFiatUnscaled(crypto: BigDecimal): BigDecimal { + return rateValue.multiply(crypto).setScale(decimals, roundingMode) + } - val scaledRateValue = rateValue.setScale(decimals, RoundingMode.DOWN) - val scaledFiat = fiat.setScale(decimals, RoundingMode.DOWN) + fun toFiatWithPrecision(crypto: BigDecimal): BigDecimal { + return toFiatUnscaled(crypto).scaleToFiat(true) + } + + fun toCrypto(fiat: BigDecimal): BigDecimal { + if (fiat.isZero()) return fiat + + val scaledRateValue = rateValue.setScale(decimals, roundingMode) + val scaledFiat = fiat.setScale(decimals, roundingMode) return scaledFiat.divide(scaledRateValue, RoundingMode.UP) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt index 46072d5765..925969d32f 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -6,6 +6,7 @@ import com.google.zxing.BarcodeFormat import com.google.zxing.EncodeHintType import com.google.zxing.qrcode.QRCodeWriter import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel +import com.tangem.common.extensions.isZero import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.network.coinmarketcap.FiatCurrency import java.math.BigDecimal @@ -58,8 +59,28 @@ fun BigDecimal.toFiatString(rateValue: BigDecimal, fiatCurrencyName: FiatCurrenc return "≈ ${fiatCurrencyName}  $fiatValue" } +fun FiatCurrency.toFormattedString(): String = "${this.name} (${this.symbol}) - ${this.sign}" + fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString() +// 0.00 -> 0.00 +// 0.00002345 -> 0.00002 +// 1.00002345 -> 1.00 +// 1.45002345 -> 1.45 +fun BigDecimal.scaleToFiat(applyPrecision: Boolean = false): BigDecimal { + if (this.isZero()) return this + + val scaledFiat = this.setScale(2, RoundingMode.DOWN) + return if (scaledFiat.isZero() && applyPrecision) this.setPrecision(1) + else scaledFiat + +} + +fun BigDecimal.setPrecision(precision: Int, roundingMode: RoundingMode = RoundingMode.DOWN): BigDecimal { + if (precision == precision() || scale() <= precision) return this + return this.setScale(scale() - precision() + precision, roundingMode) +} + fun BigDecimal.isPositive(): Boolean = this.compareTo(BigDecimal.ZERO) == 1 fun BigDecimal.isNegative(): Boolean = this.compareTo(BigDecimal.ZERO) == -1 fun BigDecimal.isGreaterThan(value: BigDecimal): Boolean = this.compareTo(value) == 1 @@ -73,6 +94,4 @@ fun BigDecimal.isGreaterThanOrEqual(value: BigDecimal): Boolean { fun BigDecimal.isLessThanOrEqual(value: BigDecimal): Boolean { val compareResult = this.compareTo(value) return compareResult == -1 || compareResult == 0 -} - -fun FiatCurrency.toFormattedString(): String = "${this.name} (${this.symbol}) - ${this.sign}" \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt index 177089ffba..7e84963643 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt @@ -3,7 +3,9 @@ package com.tangem.tap.common.redux import android.widget.Toast import androidx.coordinatorlayout.widget.CoordinatorLayout import com.google.android.material.snackbar.Snackbar +import com.tangem.tap.domain.MultiMessageError import com.tangem.tap.domain.TapError +import com.tangem.tap.domain.assembleErrorIds import com.tangem.tap.notificationsHandler import org.rekotlin.Action import org.rekotlin.Middleware @@ -39,19 +41,30 @@ class NotificationsHandler(coordinatorLayout: CoordinatorLayout) { Toast.makeText(it.context, it.context.getString(message), Toast.LENGTH_LONG).show() } } + + fun showNotification(errorList: List, builder: (List) -> String) { + val context = baseLayout.get()?.context ?: return + + val message = builder(errorList.map { context.getString(it) }) + showNotification(message) + } } val notificationsMiddleware: Middleware = { dispatch, state -> { next -> { action -> - if (action is NotificationAction) { - notificationsHandler?.showNotification(action.messageResource) - } - if (action is ToastNotificationAction) { - notificationsHandler?.showToastNotification(action.messageResource) - } - if (action is ErrorAction) { - notificationsHandler?.showNotification(action.error.localizedMessage) + when (action) { + is NotificationAction -> notificationsHandler?.showNotification(action.messageResource) + is ToastNotificationAction -> notificationsHandler?.showToastNotification(action.messageResource) + is ErrorAction -> { + when (action.error) { + is MultiMessageError -> { + val multiError = action.error as MultiMessageError + notificationsHandler?.showNotification(multiError.assembleErrorIds(), multiError.builder) + } + else -> notificationsHandler?.showNotification(action.error.localizedMessage) + } + } } next(action) } diff --git a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt index 4f98257223..4bd45c181d 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt @@ -3,13 +3,39 @@ package com.tangem.tap.domain import androidx.annotation.StringRes import com.tangem.wallet.R -sealed class TapError(@StringRes val localizedMessage: Int): Throwable() { - object PayIdAlreadyCreated: TapError(R.string.error_payid_already_created) - object PayIdCreatingError: TapError(R.string.error_creating_payid) - object PayIdEmptyField: TapError(R.string.wallet_create_payid_empty) - object UnknownBlockchain: TapError(R.string.wallet_unknown_blockchain) - object NoInternetConnection: TapError(R.string.notification_no_internet) - object InsufficientBalance: TapError(R.string.error_insufficient_balance) - object BlockchainInternalError: TapError(R.string.error_blockchain_internal) - object UnknownError: TapError(R.string.error_unknown) +interface TapErrors +interface MultiMessageError : TapErrors { + val errorList: List + val builder: (List) -> String +} + +sealed class TapError(@StringRes val localizedMessage: Int) : Throwable(), TapErrors { + object UnknownError : TapError(R.string.error_unknown) + object PayIdAlreadyCreated : TapError(R.string.error_payid_already_created) + object PayIdCreatingError : TapError(R.string.error_creating_payid) + object PayIdEmptyField : TapError(R.string.wallet_create_payid_empty) + object UnknownBlockchain : TapError(R.string.wallet_unknown_blockchain) + object NoInternetConnection : TapError(R.string.notification_no_internet) + object InsufficientBalance : TapError(R.string.error_insufficient_balance) + object BlockchainInternalError : TapError(R.string.error_blockchain_internal) + object AmountExceedsBalance : TapError(R.string.amount_exceeds_balance) + object FeeExceedsBalance : TapError(R.string.fee_exceeds_balance) + object TotalExceedsBalance : TapError(R.string.total_exceeds_balance) + object InvalidAmountValue : TapError(R.string.invalid_amount_value) + object InvalidFeeValue : TapError(R.string.invalid_fee_value) + object DustAmount : TapError(R.string.dust_amount) + object DustChang : TapError(R.string.dust_change) + data class ValidateTransactionErrors( + override val errorList: List, + override val builder: (List) -> String + ) : TapError(-1), MultiMessageError +} + +fun TapErrors.assembleErrorIds(): MutableList { + val idList = mutableListOf() + when (this) { + is MultiMessageError -> this.errorList.forEach { idList.addAll(it.assembleErrorIds()) } + is TapError -> idList.add(this.localizedMessage) + } + return idList } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt index 2dba8c385f..5596123814 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt @@ -64,14 +64,9 @@ sealed class AmountActionUi : SendScreenActionUi { } sealed class AmountAction : SendScreenAction { - enum class Error { - FEE_GREATER_THAN_AMOUNT, - AMOUNT_WITH_FEE_GREATER_THAN_BALANCE - } - sealed class AmountVerification : AmountAction() { data class SetAmount(val amount: BigDecimal) : AmountVerification() - data class SetError(val amount: BigDecimal, val error: Error) : AmountVerification() + data class SetError(val amount: BigDecimal, val error: TapError) : AmountVerification() } } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt index 259051b8a4..c68901c350 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AmountMiddleware.kt @@ -1,13 +1,13 @@ package com.tangem.tap.features.send.redux.middlewares -import com.tangem.tap.common.CurrencyConverter -import com.tangem.tap.common.extensions.isGreaterThan -import com.tangem.tap.common.extensions.isGreaterThanOrEqual +import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.TransactionError +import com.tangem.common.extensions.isZero import com.tangem.tap.common.redux.AppState +import com.tangem.tap.domain.TapError import com.tangem.tap.features.send.redux.AmountAction import com.tangem.tap.features.send.redux.ReceiptAction import com.tangem.tap.features.send.redux.SendAction -import com.tangem.tap.features.send.redux.states.MainCurrencyType import com.tangem.tap.store import org.rekotlin.Action import java.math.BigDecimal @@ -19,81 +19,47 @@ class AmountMiddleware { fun handle(rawData: String?, appState: AppState?, dispatch: (Action) -> Unit) { val sendState = appState?.sendState ?: return + val walletManager = sendState.walletManager ?: return val rawData = rawData ?: store.state.sendState.amountState.viewAmountValue val data = if (rawData == ".") "0.0" else rawData - val proposedAmountValue = when { + val inputValue = when { data.isEmpty() || data == "0" -> BigDecimal.ZERO else -> BigDecimal(data) } - val balanceCrypto = sendState.amount?.value ?: BigDecimal.ZERO - val amountChecker = when (sendState.amountState.mainCurrency.value) { - MainCurrencyType.FIAT -> FiatAmountChecker(balanceCrypto, sendState.currencyConverter) - MainCurrencyType.CRYPTO -> CryptoAmountChecker(balanceCrypto) - } + if (inputValue.isZero() && sendState.amountState.amountToSendCrypto.isZero()) return - val checkResult = amountChecker.check( - proposedAmountValue, - sendState.feeState.getCurrentFee(), - sendState.feeState.feeIsIncluded - ) - if (checkResult.error == null) { - dispatch(AmountAction.AmountVerification.SetAmount(checkResult.amount)) + val inputCrypto = sendState.convertInputValueToCrypto(inputValue) + val fee = sendState.feeState.getCurrentFee() + + val needToExtractFee = sendState.amountState.isCoinAmount() && sendState.feeState.feeIsIncluded + val totalToSend = if (needToExtractFee) inputCrypto.minus(fee) else inputCrypto + + val feeAmount = Amount(fee, walletManager.wallet.blockchain) + val totalAmount = Amount(totalToSend, walletManager.wallet.blockchain) + + val transactionErrors = walletManager.validateTransaction(totalAmount, feeAmount) + if (transactionErrors.isEmpty()) { + dispatch(AmountAction.AmountVerification.SetAmount(inputValue)) } else { - dispatch(AmountAction.AmountVerification.SetError(checkResult.amount, checkResult.error)) + val tapErrors = transactionErrors.map { + when (it) { + TransactionError.AmountExceedsBalance -> TapError.AmountExceedsBalance + TransactionError.FeeExceedsBalance -> TapError.FeeExceedsBalance + TransactionError.TotalExceedsBalance -> TapError.TotalExceedsBalance + TransactionError.InvalidAmountValue -> TapError.InvalidAmountValue + TransactionError.InvalidFeeValue -> TapError.InvalidFeeValue + TransactionError.DustAmount -> TapError.DustAmount + TransactionError.DustChange -> TapError.DustChang + else -> TapError.UnknownError + } + } + val error = TapError.ValidateTransactionErrors(tapErrors) { it.joinToString("\r\n") } + dispatch(AmountAction.AmountVerification.SetError(inputValue, error)) } dispatch(ReceiptAction.RefreshReceipt) dispatch(SendAction.ChangeSendButtonState(sendState.getButtonState())) } -} - -interface AmountChecker { - data class Result(val amount: BigDecimal, val error: AmountAction.Error? = null) - - fun check(value: BigDecimal, feeCrypto: BigDecimal, feeIsIncluded: Boolean): Result -} - -abstract class BaseAmountChecker( - protected val balanceCrypto: BigDecimal -) : AmountChecker { - - override fun check(value: BigDecimal, feeCrypto: BigDecimal, feeIsIncluded: Boolean): AmountChecker.Result { - val convertedFee = convert(feeCrypto) - val convertedBalance = convert(balanceCrypto) - if (feeIsIncluded) { - return if (value.isGreaterThan(convertedFee)) { - if (convertedBalance.isGreaterThanOrEqual(value)) { - AmountChecker.Result(value) - } else { - AmountChecker.Result(value, AmountAction.Error.FEE_GREATER_THAN_AMOUNT) - } - } else { - AmountChecker.Result(value, AmountAction.Error.AMOUNT_WITH_FEE_GREATER_THAN_BALANCE) - } - } else { - val amountWithFee = value.plus(convertedFee) - return if (convertedBalance.isGreaterThanOrEqual(amountWithFee)) { - AmountChecker.Result(value) - } else { - AmountChecker.Result(value, AmountAction.Error.AMOUNT_WITH_FEE_GREATER_THAN_BALANCE) - } - } - } - - protected abstract fun convert(value: BigDecimal): BigDecimal -} - -class CryptoAmountChecker( - balanceCrypto: BigDecimal -) : BaseAmountChecker(balanceCrypto) { - override fun convert(value: BigDecimal): BigDecimal = value -} - -class FiatAmountChecker( - balanceCrypto: BigDecimal, - private val converter: CurrencyConverter -) : BaseAmountChecker(balanceCrypto) { - override fun convert(value: BigDecimal): BigDecimal = converter.toFiat(value) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt index 5129a95646..a9416145d3 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AmountReducer.kt @@ -1,7 +1,6 @@ package com.tangem.tap.features.send.redux.reducers import com.tangem.common.extensions.isZero -import com.tangem.tap.common.CurrencyConverter import com.tangem.tap.common.extensions.isNegative import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.features.send.redux.AmountAction @@ -11,8 +10,6 @@ import com.tangem.tap.features.send.redux.SendScreenAction import com.tangem.tap.features.send.redux.states.AmountState import com.tangem.tap.features.send.redux.states.MainCurrencyType import com.tangem.tap.features.send.redux.states.SendState -import com.tangem.tap.features.send.redux.states.Value -import com.tangem.tap.store import java.math.BigDecimal /** @@ -26,7 +23,6 @@ class AmountReducer : SendInternalReducer { } private fun handleUiAction(action: AmountActionUi, sendState: SendState, state: AmountState): SendState { - val converter = sendState.currencyConverter val result = when (action) { is ToggleMainCurrency -> { val type = if (state.mainCurrency.value == MainCurrencyType.FIAT) MainCurrencyType.CRYPTO @@ -38,21 +34,21 @@ class AmountReducer : SendInternalReducer { when (action.mainCurrency) { MainCurrencyType.FIAT -> { val fiatToSend = if (state.amountToSendCrypto.isZero()) BigDecimal.ZERO - else converter.toFiat(state.amountToSendCrypto) + else sendState.convertToFiat(state.amountToSendCrypto) + val rescaledBalance = sendState.convertToFiat(state.balanceCrypto, true) state.copy( viewAmountValue = fiatToSend.stripZeroPlainString(), - viewBalanceValue = converter.toFiat(state.balanceCrypto).stripZeroPlainString(), - mainCurrency = Value(MainCurrencyType.FIAT, store.state.globalState.appCurrency), + viewBalanceValue = rescaledBalance.stripZeroPlainString(), + mainCurrency = state.createMainCurrencyValue(action.mainCurrency), maxLengthOfAmount = sendState.getDecimals(action.mainCurrency), cursorAtTheSamePosition = false ) } MainCurrencyType.CRYPTO -> { - val mainCurrency = Value(MainCurrencyType.CRYPTO, sendState.amount?.currencySymbol ?: "null") state.copy( viewAmountValue = state.amountToSendCrypto.stripZeroPlainString(), viewBalanceValue = state.balanceCrypto.stripZeroPlainString(), - mainCurrency = mainCurrency, + mainCurrency = state.createMainCurrencyValue(action.mainCurrency), maxLengthOfAmount = sendState.getDecimals(action.mainCurrency), cursorAtTheSamePosition = false ) @@ -69,7 +65,7 @@ class AmountReducer : SendInternalReducer { } val etFieldValue = if (state.mainCurrency.value == MainCurrencyType.CRYPTO) maxAmount - else converter.toFiat(maxAmount) + else sendState.convertToFiat(maxAmount) state.copy( viewAmountValue = etFieldValue.stripZeroPlainString(), amountToSendCrypto = maxAmount, @@ -83,25 +79,21 @@ class AmountReducer : SendInternalReducer { } private fun handleAction(action: AmountAction, sendState: SendState, state: AmountState): SendState { - val decimals = sendState.amount?.decimals ?: return sendState - val result = when (action) { is AmountAction.AmountVerification.SetAmount -> { - setAmount(sendState.currencyConverter, decimals, action.amount, state) + setAmount(sendState, action.amount, state) } is AmountAction.AmountVerification.SetError -> { - setAmount(sendState.currencyConverter, decimals, action.amount, state).copy(error = action.error) + setAmount(sendState, action.amount, state).copy(error = action.error) } } - return updateLastState(sendState.copy(amountState = result), result) - } - private fun setAmount(converter: CurrencyConverter, decimals: Int, amount: BigDecimal, state: AmountState): AmountState { + private fun setAmount(sendState: SendState, amount: BigDecimal, state: AmountState): AmountState { return when (state.mainCurrency.value) { MainCurrencyType.FIAT -> { - val amountCrypto = converter.toCrypto(amount, decimals).stripTrailingZeros() + val amountCrypto = sendState.convertToCrypto(amount) state.copy( viewAmountValue = amount.stripZeroPlainString(), amountToSendCrypto = amountCrypto, diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt index 91726cb199..41eeb5d614 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt @@ -3,6 +3,7 @@ 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 @@ -24,20 +25,21 @@ class ReceiptReducer : SendInternalReducer { private fun handleRefresh(action: RefreshReceipt, sendState: SendState, state: ReceiptState): SendState { val wallet = sendState.walletManager?.wallet ?: return sendState - val converter = sendState.currencyConverter + val coinConverter = sendState.coinConverter + val tokenConverter = sendState.tokenConverter val amountState = sendState.amountState val feeState = sendState.feeState - val layoutType = determineLayoutType(amountState.mainCurrency.value, amountState.typeOfAmount) + val layoutType = determineLayoutType(amountState.mainCurrency.value, sendState.amountState.typeOfAmount) val symbols = determineSymbols(wallet) val showBlank = !sendState.isReadyToSend() val result = state.copy( visibleTypeOfReceipt = layoutType, mainCurrencyType = sendState.amountState.mainCurrency, - fiat = createFiatType(converter, amountState, feeState, symbols, showBlank), - crypto = createCryptoType(converter, amountState, feeState, symbols, showBlank), - tokenFiat = createTokenFiatType(converter, amountState, feeState, symbols, showBlank), - tokenCrypto = createTokenCryptoType(converter, amountState, feeState, symbols, showBlank) + 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) ) return updateLastState(sendState.copy(receiptState = result), result) } @@ -50,15 +52,15 @@ class ReceiptReducer : SendInternalReducer { showBlank: Boolean ): ReceiptFiat { val feeCrypto = feeState.getCurrentFee() - val feeFiat = converter.toFiat(feeCrypto) + val feeFiat = converter.toFiatWithPrecision(feeCrypto) if (showBlank) { - return ReceiptFiat("0", feeFiat.stripZeroPlainString(), feeFiat.stripZeroPlainString(), "0", symbols) + return ReceiptFiat("0", feeFiat.stripZeroPlainString(), "0", "0", symbols) } return if (feeState.feeIsIncluded) { - val amountFiat = converter.toFiat(amountState.amountToSendCrypto.minus(feeCrypto)) - val totalFiat = converter.toFiat(amountState.amountToSendCrypto) + val amountFiat = converter.toFiatWithPrecision(amountState.amountToSendCrypto.minus(feeCrypto)) + val totalFiat = converter.toFiatWithPrecision(amountState.amountToSendCrypto) ReceiptFiat( amountFiat = amountFiat.stripZeroPlainString(), feeFiat = feeFiat.stripZeroPlainString(), @@ -68,8 +70,8 @@ class ReceiptReducer : SendInternalReducer { ) } else { val totalAmountCrypto = amountState.amountToSendCrypto.plus(feeCrypto) - val amountFiat = converter.toFiat(amountState.amountToSendCrypto) - val totalFiat = converter.toFiat(totalAmountCrypto) + val amountFiat = converter.toFiatWithPrecision(amountState.amountToSendCrypto) + val totalFiat = converter.toFiatWithPrecision(totalAmountCrypto) ReceiptFiat( amountFiat = amountFiat.stripZeroPlainString(), feeFiat = feeFiat.stripZeroPlainString(), @@ -88,9 +90,9 @@ class ReceiptReducer : SendInternalReducer { showBlank: Boolean ): ReceiptCrypto { val feeCrypto = feeState.getCurrentFee() - + val feeFiat = converter.toFiatWithPrecision(feeCrypto) if (showBlank) { - return ReceiptCrypto("0", feeCrypto.stripZeroPlainString(), "0", converter.toFiat(feeCrypto).stripZeroPlainString(), "0", symbols) + return ReceiptCrypto("0", feeCrypto.stripZeroPlainString(), "0", "0", "0", symbols) } if (feeState.feeIsIncluded) { @@ -98,8 +100,8 @@ class ReceiptReducer : SendInternalReducer { amountCrypto = amountState.amountToSendCrypto.minus(feeCrypto).stripZeroPlainString(), feeCrypto = feeCrypto.stripZeroPlainString(), totalCrypto = amountState.amountToSendCrypto.stripZeroPlainString(), - feeFiat = converter.toFiat(feeCrypto).stripZeroPlainString(), - willSentFiat = converter.toFiat(amountState.amountToSendCrypto).stripZeroPlainString(), + feeFiat = feeFiat.stripZeroPlainString(), + willSentFiat = converter.toFiatWithPrecision(amountState.amountToSendCrypto).stripZeroPlainString(), symbols = symbols ) } else { @@ -108,7 +110,7 @@ class ReceiptReducer : SendInternalReducer { amountCrypto = amountState.amountToSendCrypto.stripZeroPlainString(), feeCrypto = feeCrypto.stripZeroPlainString(), totalCrypto = totalCrypto.stripZeroPlainString(), - feeFiat = converter.toFiat(feeCrypto).stripZeroPlainString(), + feeFiat = feeFiat.stripZeroPlainString(), willSentFiat = converter.toFiat(totalCrypto).stripZeroPlainString(), symbols = symbols ) @@ -116,47 +118,55 @@ class ReceiptReducer : SendInternalReducer { } private fun createTokenFiatType( - converter: CurrencyConverter, + coinConverter: CurrencyConverter, + tokenConverter: CurrencyConverter, amountState: AmountState, feeState: FeeState, symbols: ReceiptSymbols, showBlank: Boolean ): ReceiptTokenFiat { - val feeCrypto = feeState.getCurrentFee() - val amountFiat = converter.toFiat(amountState.amountToSendCrypto) - val feeFiat = converter.toFiat(feeCrypto) - + val feeCoin = feeState.getCurrentFee() + val feeFiat = coinConverter.toFiatWithPrecision(feeCoin) if (showBlank) { return ReceiptTokenFiat("0", feeFiat.stripZeroPlainString(), "0", "0", "0", symbols) } + val tokensToSend = amountState.amountToSendCrypto + val amountFiat = tokenConverter.toFiatUnscaled(tokensToSend) + val totalFiat = amountFiat.plus(feeFiat) + return ReceiptTokenFiat( - amountFiat = amountFiat.stripZeroPlainString(), + amountFiat = amountFiat.scaleToFiat().stripZeroPlainString(), feeFiat = feeFiat.stripZeroPlainString(), - totalFiat = amountFiat.plus(feeFiat).stripZeroPlainString(), - willSentTokenCrypto = amountState.amountToSendCrypto.stripZeroPlainString(), - willSentFeeCrypto = feeCrypto.stripZeroPlainString(), + totalFiat = totalFiat.scaleToFiat().stripZeroPlainString(), + willSentToken = tokensToSend.stripZeroPlainString(), + willSentFeeCoin = feeCoin.stripZeroPlainString(), symbols = symbols ) } private fun createTokenCryptoType( - converter: CurrencyConverter, + coinConverter: CurrencyConverter, + tokenConverter: CurrencyConverter, amountState: AmountState, feeState: FeeState, symbols: ReceiptSymbols, showBlank: Boolean ): ReceiptTokenCrypto { - val feeCrypto = feeState.getCurrentFee() - val totalFiat = converter.toFiat(amountState.amountToSendCrypto).plus(converter.toFiat(feeCrypto)) + val feeCoin = feeState.getCurrentFee() if (showBlank) { - return ReceiptTokenCrypto("0", feeCrypto.stripZeroPlainString(), "0", symbols) + 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 = amountState.amountToSendCrypto.stripZeroPlainString(), - feeCrypto = feeCrypto.stripZeroPlainString(), - totalFiat = totalFiat.stripZeroPlainString(), + amountToken = tokensToSend.stripZeroPlainString(), + feeCoin = feeCoin.stripZeroPlainString(), + totalFiat = totalFiat.scaleToFiat().stripZeroPlainString(), symbols = symbols ) } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt index 858b626b15..8a18db9d5e 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt @@ -1,6 +1,6 @@ package com.tangem.tap.features.send.redux.reducers -import com.tangem.blockchain.common.WalletManager +import com.tangem.blockchain.common.AmountType import com.tangem.tap.common.CurrencyConverter import com.tangem.tap.features.send.redux.* import com.tangem.tap.features.send.redux.states.IdStateHolder @@ -54,19 +54,34 @@ private class EmptyReducer : SendInternalReducer { private class PrepareSendScreenStatesReducer : SendInternalReducer { override fun handle(action: SendScreenAction, sendState: SendState): SendState { - val amount = (action as PrepareSendScreen).tokenAmount ?: action.coinAmount + val prepareAction = action as PrepareSendScreen val walletManager = store.state.globalState.scanNoteResponse!!.walletManager!! + val walletAmount = prepareAction.tokenAmount ?: prepareAction.coinAmount!! + val decimals = walletAmount.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( - amount = amount, walletManager = walletManager, - currencyConverter = createCurrencyConverter(walletManager), - amountState = sendState.amountState.copy(balanceCrypto = amount?.value ?: BigDecimal.ZERO) + coinConverter = coinConverter, + tokenConverter = tokenConverter ?: CurrencyConverter(BigDecimal.ONE, decimals), + amountState = sendState.amountState.copy( + walletAmount = walletAmount, + typeOfAmount = walletAmount.type, + balanceCrypto = walletAmount.value ?: BigDecimal.ZERO + ), + feeState = sendState.feeState.copy( + includeFeeSwitcherIsEnabled = walletAmount.type == AmountType.Coin + ) ) } - private fun createCurrencyConverter(walletManager: WalletManager): CurrencyConverter { - val rate = store.state.globalState.conversionRates.getRate(walletManager.wallet.blockchain.currency) - return if (rate == null) CurrencyConverter(BigDecimal.ONE) else CurrencyConverter(rate) + private fun createCurrencyConverter(currency: String, decimals: Int): CurrencyConverter? { + val rate = store.state.globalState.conversionRates.getRate(currency) + return if (rate == null) null else CurrencyConverter(rate, decimals) } } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt index e7e10b5acd..6c453d6ae5 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt @@ -9,10 +9,11 @@ data class AddressPayIdState( val recipientWalletAddress: String? = null, val error: AddressPayIdVerifyAction.Error? = null, val truncateHandler: ((String) -> String)? = null, - val pasteIsEnabled: Boolean = false, - override val stateId: StateId = StateId.ADDRESS_PAY_ID + val pasteIsEnabled: Boolean = false ) : SendScreenState { + override val stateId: StateId = StateId.ADDRESS_PAY_ID + fun isReady(): Boolean = error == null && recipientWalletAddress?.isNotEmpty() ?: false fun isPayIdState(): Boolean = recipientWalletAddress != null && recipientWalletAddress != normalFieldValue diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/FeeState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/FeeState.kt index 37260d98be..3e450e5c09 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/FeeState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/FeeState.kt @@ -19,9 +19,12 @@ data class FeeState( val mainLayoutIsVisible: Boolean = false, val controlsLayoutIsVisible: Boolean = false, val feeChipGroupIsVisible: Boolean = true, + val includeFeeSwitcherIsEnabled: Boolean = true, val error: FeeAction.Error? = null, - override val stateId: StateId = StateId.FEE ) : SendScreenState { + + override val stateId: StateId = StateId.FEE + fun isReady(): Boolean = error == null && currentFee != null fun getCurrentFee(): BigDecimal = currentFee?.value?.value ?: BigDecimal.ZERO diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/ReceiptState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/ReceiptState.kt index 321cfe43b8..df43c5f9a5 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/ReceiptState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/ReceiptState.kt @@ -11,9 +11,10 @@ data class ReceiptState( val crypto: ReceiptCrypto? = null, val tokenFiat: ReceiptTokenFiat? = null, val tokenCrypto: ReceiptTokenCrypto? = null, - val mainCurrencyType: Value? = null, - override val stateId: StateId = StateId.RECEIPT -) : SendScreenState + val mainCurrencyType: Value? = null +) : SendScreenState { + override val stateId: StateId = StateId.RECEIPT +} data class ReceiptSymbols( val fiat: String, @@ -40,7 +41,7 @@ data class ReceiptCrypto( data class ReceiptTokenCrypto( val amountToken: String, - val feeCrypto: String, + val feeCoin: String, val totalFiat: String, val symbols: ReceiptSymbols ) @@ -49,7 +50,7 @@ data class ReceiptTokenFiat( val amountFiat: String, val feeFiat: String, val totalFiat: String, - val willSentTokenCrypto: String, - val willSentFeeCrypto: String, + val willSentToken: String, + val willSentFeeCoin: String, val symbols: ReceiptSymbols ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt index 7d3df6c928..578cda3497 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt @@ -6,7 +6,7 @@ import com.tangem.blockchain.common.WalletManager import com.tangem.common.extensions.isZero import com.tangem.tap.common.CurrencyConverter import com.tangem.tap.common.entities.TapCurrency -import com.tangem.tap.features.send.redux.AmountAction +import com.tangem.tap.domain.TapError import com.tangem.tap.store import org.rekotlin.StateType import java.math.BigDecimal @@ -26,18 +26,20 @@ enum class StateId { interface SendScreenState : StateType, IdStateHolder data class SendState( - val amount: Amount? = null, val walletManager: WalletManager? = null, - val currencyConverter: CurrencyConverter = CurrencyConverter(BigDecimal.ONE), + val coinConverter: CurrencyConverter = CurrencyConverter(BigDecimal.ONE, 2), + val tokenConverter: CurrencyConverter = CurrencyConverter(BigDecimal.ONE, 2), val lastChangedStates: LinkedHashSet = linkedSetOf(), val addressPayIdState: AddressPayIdState = AddressPayIdState(), val amountState: AmountState = AmountState(), val feeState: FeeState = FeeState(), val receiptState: ReceiptState = ReceiptState(), val sendButtonState: SendButtonState = SendButtonState.DISABLED, - override val stateId: StateId = StateId.SEND_SCREEN + val hasInitializationError: Boolean = false ) : SendScreenState { + override val stateId: StateId = StateId.SEND_SCREEN + fun isReadyToSend(): Boolean { val sendState = store.state.sendState return addressPayIdIsReady() && sendState.amountState.isReady() && sendState.feeState.isReady() @@ -47,7 +49,28 @@ data class SendState( fun getDecimals(type: MainCurrencyType): Int = when (type) { MainCurrencyType.FIAT -> 2 - MainCurrencyType.CRYPTO -> amount?.decimals ?: 0 + MainCurrencyType.CRYPTO -> amountState.walletAmount?.decimals ?: 0 + } + + fun getConverter(): CurrencyConverter { + return if (amountState.typeOfAmount == AmountType.Coin) coinConverter + else tokenConverter + } + + fun convertToCrypto(value: BigDecimal): BigDecimal { + return getConverter().toCrypto(value) + } + + fun convertToFiat(value: BigDecimal, scaleWithPrecision: Boolean = false): BigDecimal { + val converter = getConverter() + return if (scaleWithPrecision) converter.toFiat(value) else converter.toFiatWithPrecision(value) + } + + fun convertInputValueToCrypto(inputValue: BigDecimal): BigDecimal { + return when (amountState.mainCurrency.value) { + MainCurrencyType.FIAT -> convertToCrypto(inputValue) + MainCurrencyType.CRYPTO -> inputValue + } } fun getButtonState(): SendButtonState = if (isReadyToSend()) SendButtonState.ENABLED else SendButtonState.DISABLED @@ -58,18 +81,30 @@ enum class SendButtonState { } data class AmountState( + val walletAmount: Amount? = null, + val typeOfAmount: AmountType = AmountType.Coin, val viewAmountValue: String = BigDecimal.ZERO.toPlainString(), val viewBalanceValue: String = BigDecimal.ZERO.toPlainString(), val mainCurrency: Value = Value(MainCurrencyType.FIAT, TapCurrency.DEFAULT_FIAT_CURRENCY), - val typeOfAmount: AmountType = AmountType.Coin, val amountToSendCrypto: BigDecimal = BigDecimal.ZERO, val balanceCrypto: BigDecimal = BigDecimal.ZERO, val cursorAtTheSamePosition: Boolean = true, val maxLengthOfAmount: Int = 2, - val error: AmountAction.Error? = null, - override val stateId: StateId = StateId.AMOUNT + val error: TapError? = null ) : SendScreenState { + + override val stateId: StateId = StateId.AMOUNT + fun isReady(): Boolean = error == null && !amountToSendCrypto.isZero() + + fun isCoinAmount(): Boolean = typeOfAmount == AmountType.Coin + + fun createMainCurrencyValue(type: MainCurrencyType): Value { + return when (type) { + MainCurrencyType.FIAT -> Value(type, store.state.globalState.appCurrency) + MainCurrencyType.CRYPTO -> Value(type, walletAmount?.currencySymbol ?: "NONE") + } + } } enum class MainCurrencyType { diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt index 8201b03f38..415731d02c 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt @@ -16,6 +16,7 @@ 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.* @@ -57,6 +58,11 @@ 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() @@ -187,6 +193,8 @@ 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 diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index c4ee8d767a..38a9768bd5 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -10,9 +10,10 @@ import com.tangem.tap.common.extensions.show import com.tangem.tap.common.extensions.update import com.tangem.tap.common.text.DecimalDigitsInputFilter import com.tangem.tap.common.toggleWidget.ProgressState +import com.tangem.tap.domain.MultiMessageError +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.AmountAction import com.tangem.tap.features.send.redux.FeeAction import com.tangem.tap.features.send.redux.states.* import com.tangem.tap.features.send.ui.FeeUiHelper @@ -96,19 +97,21 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber } private fun handleAmountState(fg: BaseStoreFragment, state: AmountState) { - when (state.error) { - AmountAction.Error.FEE_GREATER_THAN_AMOUNT -> { - fg.amountContainer.parent?.beginDelayedTransition() - fg.tilAmountToSend.enableError(true, fg.getString(R.string.error_fee_greater_than_amount)) - } - AmountAction.Error.AMOUNT_WITH_FEE_GREATER_THAN_BALANCE -> { - fg.amountContainer.parent?.beginDelayedTransition() - fg.tilAmountToSend.enableError(true, fg.getString(R.string.error_amount_with_fee_greater_than_balance)) - } - null -> { - if (fg.tilAmountToSend.isErrorEnabled) fg.amountContainer.parent?.beginDelayedTransition() - fg.tilAmountToSend.enableError(false) + if (state.error != null) { + val context = fg.requireContext() + val message = when (state.error) { + is MultiMessageError -> { + val multiError = state.error as MultiMessageError + val messageList = multiError.assembleErrorIds().map { context.getString(it) } + multiError.builder(messageList) + } + else -> context.getString(state.error.localizedMessage) } + fg.amountContainer.parent?.beginDelayedTransition() + fg.tilAmountToSend.enableError(true, message) + } else { + if (fg.tilAmountToSend.isErrorEnabled) fg.amountContainer.parent?.beginDelayedTransition() + fg.tilAmountToSend.enableError(false) } fg.etAmountToSend.filters = arrayOf(DecimalDigitsInputFilter(12, state.maxLengthOfAmount)) @@ -162,6 +165,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber } } + fg.swIncludeFee.isEnabled = state.includeFeeSwitcherIsEnabled if (fg.swIncludeFee.isChecked != state.feeIsIncluded) { fg.swIncludeFee.isChecked = state.feeIsIncluded } @@ -182,6 +186,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber val totalTokenLayout = fg.flTotalTokenCrypto as ViewGroup fun getString(id: Int): String = mainLayout.context.getString(id) + val rough = getString(R.string.sign_rough) when (state.visibleTypeOfReceipt) { ReceiptLayoutType.FIAT -> { val receipt = state.fiat ?: return @@ -190,7 +195,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("$rough ${receipt.totalFiat} ${receipt.symbols.fiat}") val willSent = SpannableStringBuilder() .bold { append(receipt.willSentCrypto) }.append(" ") @@ -210,7 +215,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber val willSent = SpannableStringBuilder() .bold { - append(getString(R.string.sign_rough)).append(" ") + append(rough).append(" ") append(receipt.willSentFiat).append(" ") append(receipt.symbols.fiat) append(" (fee: ${receipt.feeFiat} ") @@ -231,11 +236,11 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber .bold { append(receipt.symbols.token) append(" ") - append(receipt.willSentFeeCrypto) + append(receipt.willSentToken) }.append(" ").append(getString(R.string.generic_and)).append(" ") .bold { append(receipt.symbols.crypto).append(" ") - append(receipt.willSentFeeCrypto).append(" ") + append(receipt.willSentFeeCoin).append(" ") } .append(mainLayout.context.getString(R.string.send_total_will_be_sent)) totalLayout.tvWillBeSentValue.update(willSent.toString()) @@ -247,7 +252,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber totalTokenLayout.show(true) fg.tvReceiptAmountValue.update("${receipt.amountToken} ${receipt.symbols.token}") - fg.tvReceiptFeeValue.update("${receipt.feeCrypto} ${receipt.symbols.crypto}") + fg.tvReceiptFeeValue.update("${receipt.feeCoin} ${receipt.symbols.crypto}") val willSent = SpannableStringBuilder() .bold { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9373ea5d54..22a73a85d7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -57,11 +57,15 @@ Address is invalid or unsupported by blockchain Address is the same as wallet address Network fee request is failed - Fee greater than amount - Amount with fee greater than balance Insufficient balance Blockchain internal error - + amount_exceeds_balance + fee_exceeds_balance + total_exceeds_balance + invalid_amount_value + invalid_fee_value + dust_amount + dust_change Send Address or PayID