From b7c6ea61a68252c11c9b9797f5c65949fee3b260 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 28 Feb 2024 11:20:48 +0500 Subject: [PATCH] Updated on 2026-08-14 --- core/res/src/main/res/values-ru/strings.xml | 10 +++--- core/res/src/main/res/values/strings.xml | 13 ++++--- .../impl/presentation/state/SendAlertState.kt | 8 +++++ .../state/SendEventStateFactory.kt | 24 +++++++++++++ .../presentation/state/SendNotification.kt | 27 ++++++++++---- .../state/SendNotificationFactory.kt | 35 ++++++++++++++++--- .../state/fee/FeeNotificationFactory.kt | 15 -------- .../state/fee/SendFeeNotification.kt | 5 --- .../ui/fee/SendSpeedAndFeeContent.kt | 5 +-- .../presentation/ui/fee/SendSpeedSelector.kt | 5 +-- .../viewmodel/SendClickIntents.kt | 7 ++-- .../presentation/viewmodel/SendViewModel.kt | 15 +++++--- 12 files changed, 112 insertions(+), 57 deletions(-) diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 5cd4aa90a1..2629c88c99 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -480,14 +480,12 @@ Комиссия не превысит Максимальная cумма комиссии Сетевая комиссия - Сумма отправки будет уменьшена для покрытия выбранного уровня комиссии + Сумма отправки будет уменьшена на %1$s для покрытия выбранного уровня комиссии. Получателю будет отправлено %2$s. Покрытие сетевой комиссии Недостаточно средств для перевода, так как сумма комиссии и сумма перевода в совокупности больше имеющегося баланса Недостаточно средств Увеличение комиссии Комиссия при переводе всего баланса выше. Для того, чтобы снизить комиссию Вы можете оставить 0.01. - Оставить %s XTZ - Отправить все Установлена высокая комиссия Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна. Включенная комиссия превышает сумму перевода, что приводит к отрицательному значению @@ -497,8 +495,10 @@ Сумма отправки не может быть менее %1$s Обратите внимание, что при определенных параметрах комиссии возможны задержки по вашей транзакции Возможны задержки по транзакции - Уменьшить до [%s] - Уменьшить на [%s] + Лимит транзакции + Из-за ограничений %1$s в одну транзакцию может поместиться только %2$s UTXO. Это означает, что вы можете отправить только %3$s или меньше. Вам нужно уменьшить сумму. + Уменьшить до %s + Уменьшить на %s Необязательное Последние Получатель diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index a089602733..a4fd2f577a 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -459,8 +459,9 @@ The recipient will receive %s The transaction is not completed Reason: %1$s\nCode: %2$s - Недостаточно средств для покрытия комиссии сети. Вычесть комиссию из отправляемой сумму? - Вычесть + Not enough funds to cover the network commission. Subtract the commission from the amount sent? + Subtract + Вы указали комиссию ниже рекомендуемой, это может привести к задержке исполнения вашей транзакции. Продолжить? Confirm %1$s at %2$s Address @@ -494,8 +495,6 @@ Total exceeds balance Fee is increased The fee for transferring the entire balance is higher. To reduce the commission, you can leave 0.01. - Reduce by %s XTZ - No, send all Custom fee is high The commission amount is %s times the recommended amount. Make sure that the custom settings are correct. The included commission exceeds the transfer amount, leading to a negative value @@ -506,11 +505,11 @@ Kindly be aware that your transaction may experience delays under specific fee settings Transaction delays are possible Transaction limitation - Due to %1$s limitations only %2$s UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount. + Due to %1$s limitations only %2$s UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount. Existential deposit The account will be wiped from the blockchain if a balance goes below the existential deposit. Please ensure that the remaining balance after sending will not be less than %s. - Reduce by [%s] - Reduce to [%s] + Reduce by %s + Reduce to %s Optional Please align your QR code with the square to scan it. Ensure you scan %s network address. Recent diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendAlertState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendAlertState.kt index 204b99d3fb..30becd1f7e 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendAlertState.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendAlertState.kt @@ -50,6 +50,14 @@ internal sealed class SendAlertState { override val message: TextReference = resourceReference(id = R.string.send_notification_high_fee_title) } + data class FeeTooLow( + override val onConfirmClick: () -> Unit, + ) : SendAlertState() { + override val title: TextReference? = null + override val message: TextReference = resourceReference(id = R.string.send_alert_fee_too_low_text) + override val confirmButtonText: TextReference = resourceReference(R.string.common_continue) + } + data class FeeCoverage( override val onConfirmClick: (() -> Unit), ) : SendAlertState() { diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendEventStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendEventStateFactory.kt index 1bfe20a62b..fbbc8953ab 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendEventStateFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendEventStateFactory.kt @@ -3,6 +3,7 @@ package com.tangem.features.send.impl.presentation.state import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.core.ui.event.consumedEvent import com.tangem.core.ui.event.triggeredEvent +import com.tangem.core.ui.utils.parseToBigDecimal 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 @@ -88,6 +89,29 @@ internal class SendEventStateFactory( } } + fun getFeeTooLowAlert(onConsume: () -> Unit): SendUiState { + val state = currentStateProvider() + val feeSelectorState = state.feeState?.feeSelectorState as? FeeSelectorState.Content ?: return state + val multipleFees = feeSelectorState.fees as? TransactionFee.Choosable ?: return state + val minimumValue = multipleFees.minimum.amount.value ?: return state + val customAmount = feeSelectorState.customValues.firstOrNull() ?: return state + val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) + + val isFeeTooLow = feeSelectorState.selectedFee == FeeType.Custom && minimumValue > customValue + if (!isFeeTooLow) return state + + return state.copy( + event = triggeredEvent( + data = SendEvent.ShowAlert( + SendAlertState.FeeTooLow( + onConfirmClick = clickIntents::showSend, + ), + ), + onConsume = onConsume, + ), + ) + } + fun getGenericErrorState(error: Throwable? = null, onConsume: () -> Unit): SendUiState { val state = currentStateProvider() return state.copy( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt index 4ab6952836..bf5148d51e 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt @@ -12,12 +12,14 @@ internal sealed class SendNotification(val config: NotificationConfig) { title: TextReference, subtitle: TextReference, buttonState: NotificationConfig.ButtonsState? = null, + onCloseClick: (() -> Unit)? = null, ) : SendNotification( config = NotificationConfig( title = title, subtitle = subtitle, iconResId = R.drawable.ic_alert_24, buttonsState = buttonState, + onCloseClick = onCloseClick, ), ) { @@ -45,12 +47,17 @@ internal sealed class SendNotification(val config: NotificationConfig) { val cryptoCurrency: String, val utxoLimit: String, val amountLimit: String, + val onConfirmClick: () -> Unit, ) : Error( title = resourceReference(R.string.send_notifiaction_transaction_limit_title), subtitle = resourceReference( - R.string.send_notifiaction_transaction_limit_text, + R.string.send_notification_transaction_limit_text, wrappedList(cryptoCurrency, utxoLimit, amountLimit), ), + buttonState = NotificationConfig.ButtonsState.PrimaryButtonConfig( + text = resourceReference(R.string.send_notification_reduce_to, wrappedList(amountLimit)), + onClick = onConfirmClick, + ), ) } @@ -58,27 +65,28 @@ internal sealed class SendNotification(val config: NotificationConfig) { title: TextReference, subtitle: TextReference, buttonsState: NotificationConfig.ButtonsState? = null, + onCloseClick: (() -> Unit)? = null, ) : SendNotification( config = NotificationConfig( title = title, subtitle = subtitle, iconResId = R.drawable.img_attention_20, buttonsState = buttonsState, + onCloseClick = onCloseClick, ), ) { data class HighFeeError( val amount: String, val onConfirmClick: () -> Unit, - val onDismissClick: () -> Unit, + val onCloseClick: () -> Unit, ) : Warning( title = resourceReference(R.string.send_notification_high_fee_title), subtitle = resourceReference(R.string.send_notification_high_fee_text, wrappedList(amount)), - buttonsState = NotificationConfig.ButtonsState.PairButtonsConfig( - primaryText = resourceReference(R.string.send_notification_fee_too_high_accept, wrappedList(amount)), - onPrimaryClick = onConfirmClick, - secondaryText = resourceReference(R.string.send_notification_fee_too_high_ignore), - onSecondaryClick = onDismissClick, + buttonsState = NotificationConfig.ButtonsState.PrimaryButtonConfig( + text = resourceReference(R.string.send_notification_reduce_by, wrappedList(amount)), + onClick = onConfirmClick, ), + onCloseClick = onCloseClick, ) data class ExistentialDeposit(val deposit: String) : Warning( @@ -96,5 +104,10 @@ internal sealed class SendNotification(val config: NotificationConfig) { formatArgs = wrappedList(amountReducedBy, amountReduced), ), ) + + data object FeeTooLow : Warning( + title = resourceReference(id = R.string.send_notification_transaction_delay_title), + subtitle = resourceReference(id = R.string.send_notification_transaction_delay_text), + ) } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotificationFactory.kt index b253266100..12ea309a87 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotificationFactory.kt @@ -1,11 +1,15 @@ package com.tangem.features.send.impl.presentation.state import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.core.ui.utils.BigDecimalFormatter +import com.tangem.core.ui.utils.parseToBigDecimal import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.repository.CurrencyChecksRepository import com.tangem.domain.wallets.models.UserWallet +import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState +import com.tangem.features.send.impl.presentation.state.fee.FeeType import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents import com.tangem.utils.Provider import com.tangem.utils.isNullOrZero @@ -48,13 +52,16 @@ internal class SendNotificationFactory( addFeeCoverageNotification(sendState.isSubtract, sendAmount) addExistentialWarningNotification(feeAmount, sendAmount) addHighFeeWarningNotification(sendAmount, sendState.ignoreAmountReduce) + addTooLowNotification(feeState) }.toImmutableList() } - fun dismissHighFeeWarningState(): SendUiState { + fun dismissNotificationState(clazz: Class): SendUiState { val state = currentStateProvider() val sendState = state.sendState - val updatedNotifications = sendState.notifications.filterNot { it is SendNotification.Warning.HighFeeError } + val notificationsToRemove = sendState.notifications.filterIsInstance(clazz) + val updatedNotifications = sendState.notifications.toMutableList() + updatedNotifications.removeAll(notificationsToRemove) return state.copy( sendState = sendState.copy( ignoreAmountReduce = true, @@ -162,6 +169,13 @@ internal class SendNotificationFactory( cryptoAmount = utxoLimit.maxAmount, cryptoCurrency = cryptoCurrency, ), + onConfirmClick = { + val reduceTo = utxoLimit.maxAmount.toPlainString() + clickIntents.onAmountReduceClick( + reduceTo, + SendNotification.Error.TransactionLimitError::class.java, + ) + }, ), ) } @@ -207,9 +221,11 @@ internal class SendNotificationFactory( amount = TEZOS_FEE_THRESHOLD.toPlainString(), onConfirmClick = { val reduceTo = sendAmount.minus(TEZOS_FEE_THRESHOLD).toPlainString() - clickIntents.onAmountReduceClick(reduceTo) + clickIntents.onAmountReduceClick(reduceTo, SendNotification.Warning.HighFeeError::class.java) + }, + onCloseClick = { + clickIntents.onNotificationCancel(SendNotification.Warning.HighFeeError::class.java) }, - onDismissClick = clickIntents::onAmountReduceIgnoreClick, ), ) } @@ -261,6 +277,17 @@ internal class SendNotificationFactory( } } + private fun MutableList.addTooLowNotification(feeState: SendStates.FeeState) { + val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return + val multipleFees = feeSelectorState.fees as? TransactionFee.Choosable ?: return + val minimumValue = multipleFees.minimum.amount.value ?: return + val customAmount = feeSelectorState.customValues.firstOrNull() ?: return + val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) + if (feeSelectorState.selectedFee == FeeType.Custom && minimumValue > customValue) { + add(SendNotification.Warning.FeeTooLow) + } + } + companion object { private const val CARDANO_MINIMUM = "1" private const val DOGECOIN_MINIMUM = "0.01" diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt index f8c304748b..da1277412a 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeNotificationFactory.kt @@ -47,7 +47,6 @@ internal class FeeNotificationFactory( is FeeSelectorState.Content -> { val customFee = feeSelectorState.customValues val selectedFee = feeSelectorState.selectedFee - addTooLowNotification(feeSelectorState.fees, selectedFee, customFee) addTooHighNotification(feeSelectorState.fees, selectedFee, customFee) addExceedsBalanceNotification(feeState.fee) } @@ -61,20 +60,6 @@ internal class FeeNotificationFactory( } } - private fun MutableList.addTooLowNotification( - transactionFee: TransactionFee, - selectedFee: FeeType, - customFee: List, - ) { - val multipleFees = transactionFee as? TransactionFee.Choosable ?: return - val minimumValue = multipleFees.minimum.amount.value ?: return - val customAmount = customFee.firstOrNull() ?: return - val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) - if (selectedFee == FeeType.Custom && minimumValue > customValue) { - add(SendFeeNotification.Warning.TooLow) - } - } - private fun MutableList.addTooHighNotification( transactionFee: TransactionFee, selectedFee: FeeType, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeNotification.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeNotification.kt index 56add5cfe5..c82f072f6a 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeNotification.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeNotification.kt @@ -20,11 +20,6 @@ sealed class SendFeeNotification(val config: NotificationConfig) { buttonsState = buttonsState, ), ) { - object TooLow : Warning( - title = resourceReference(id = R.string.send_notification_transaction_delay_title), - subtitle = resourceReference(id = R.string.send_notification_transaction_delay_text), - ) - data class TooHigh( val value: String, ) : Warning( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt index 5acd6b57b1..1695763049 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedAndFeeContent.kt @@ -74,10 +74,7 @@ private fun LazyListScope.middleNotifications( modifier: Modifier = Modifier, ) { notifications( - configs = configs.filter { - it is SendFeeNotification.Warning.TooLow || - it is SendFeeNotification.Warning.TooHigh - }.toImmutableList(), + configs = configs.filterIsInstance().toImmutableList(), modifier = modifier, ) } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt index 4d13b7d7a5..f5b10f50a8 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelector.kt @@ -117,10 +117,7 @@ internal fun SendSpeedSelector( visible = fees.normal is Fee.Ethereum, label = "Custom fee appearance animation", ) { - val showWarning = state.notifications.any { - it is SendFeeNotification.Warning.TooHigh || - it is SendFeeNotification.Warning.TooLow - } + val showWarning = state.notifications.any { it is SendFeeNotification.Warning.TooHigh } SendSpeedSelectorItem( titleRes = R.string.common_fee_selector_option_custom, iconRes = R.drawable.ic_edit_24, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt index f2eedb220d..9af06fb346 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendClickIntents.kt @@ -3,6 +3,7 @@ package com.tangem.features.send.impl.presentation.viewmodel import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.send.impl.presentation.analytics.EnterAddressSource +import com.tangem.features.send.impl.presentation.state.SendNotification import com.tangem.features.send.impl.presentation.state.fee.FeeType @Suppress("TooManyFunctions") @@ -57,12 +58,14 @@ internal interface SendClickIntents { fun showFee() + fun showSend() + fun onExploreClick() fun onShareClick() - fun onAmountReduceClick(reducedAmount: String) + fun onAmountReduceClick(reducedAmount: String, clazz: Class) - fun onAmountReduceIgnoreClick() + fun onNotificationCancel(clazz: Class) // endregion } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index 7b47227a2e..8267ee3c2a 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -394,6 +394,9 @@ internal class SendViewModel @Inject constructor( val currentState = stateRouter.currentState.value val isCurrentFee = currentState.type == SendUiStateType.Fee if (isCurrentFee) { + uiState = eventStateFactory.getFeeTooLowAlert( + onConsume = { uiState = eventStateFactory.onConsumeEventState() }, + ) val isFeeCoverage = checkFeeCoverage(uiState, cryptoCurrencyStatus) if (isAmountSubtractAvailable && isFeeCoverage) { uiState = eventStateFactory.getFeeCoverageAlert( @@ -606,6 +609,10 @@ internal class SendViewModel @Inject constructor( analyticsEventHandler.send(SendAnalyticEvents.ScreenReopened(SendScreenSource.Fee)) } + override fun showSend() { + stateRouter.showSend() + } + override fun onExploreClick() { analyticsEventHandler.send(SendAnalyticEvents.ExploreButtonClicked) innerRouter.openUrl(uiState.sendState.txUrl) @@ -615,14 +622,14 @@ internal class SendViewModel @Inject constructor( analyticsEventHandler.send(SendAnalyticEvents.ShareButtonClicked) } - override fun onAmountReduceClick(reducedAmount: String) { + override fun onAmountReduceClick(reducedAmount: String, clazz: Class) { uiState = amountStateFactory.getOnAmountValueChange(reducedAmount) - uiState = sendNotificationFactory.dismissHighFeeWarningState() + uiState = sendNotificationFactory.dismissNotificationState(clazz) loadFee() } - override fun onAmountReduceIgnoreClick() { - uiState = sendNotificationFactory.dismissHighFeeWarningState() + override fun onNotificationCancel(clazz: Class) { + uiState = sendNotificationFactory.dismissNotificationState(clazz) } private fun verifyAndSendTransaction() {