From 5d69093f1d3773e18ad83ba4299450c2835b57bf Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Jan 2024 16:31:19 +0300 Subject: [PATCH 1/2] Updated on 2026-08-14 --- .../usecase/CreateTransactionUseCase.kt | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransactionUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransactionUseCase.kt index 55c5e0cd88..55f503cf15 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransactionUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransactionUseCase.kt @@ -2,13 +2,17 @@ package com.tangem.domain.transaction.usecase import arrow.core.Either import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.common.transaction.Fee import com.tangem.domain.tokens.model.Network import com.tangem.domain.transaction.TransactionRepository import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.withContext class CreateTransactionUseCase( private val transactionRepository: TransactionRepository, + private val dispatchers: CoroutineDispatcherProvider, ) { /** @@ -22,16 +26,18 @@ class CreateTransactionUseCase( destination: String, userWalletId: UserWalletId, network: Network, - ) = Either.catch { - requireNotNull( - transactionRepository.createTransaction( - amount = amount, - fee = fee, - memo = memo, - destination = destination, - userWalletId = userWalletId, - network = network, - ), - ) { "Failed to create transaction" } + ): Either = withContext(dispatchers.io) { + Either.catch { + requireNotNull( + transactionRepository.createTransaction( + amount = amount, + fee = fee, + memo = memo, + destination = destination, + userWalletId = userWalletId, + network = network, + ), + ) { "Failed to create transaction" } + } } } \ No newline at end of file From 7ef0543a78ce09d1939c4f934cd205c06e3c0ef4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 19 Jan 2024 15:59:14 +0300 Subject: [PATCH 2/2] Updated on 2026-08-14 --- core/res/src/main/res/values-ru/strings.xml | 4 +- core/res/src/main/res/values/strings.xml | 4 +- .../usecase/CreateTransactionUseCase.kt | 28 ++++------ .../presentation/state/SendNotification.kt | 14 ++++- .../state/SendNotificationFactory.kt | 52 +++++++++++++++---- .../impl/presentation/state/SendUiState.kt | 1 + .../impl/presentation/ui/send/SendContent.kt | 5 +- .../viewmodel/SendClickIntents.kt | 4 ++ .../presentation/viewmodel/SendViewModel.kt | 11 ++++ 9 files changed, 91 insertions(+), 32 deletions(-) diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index dc64c4dac6..efdc1b3d26 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -479,8 +479,10 @@ Недостаточно средств Размер комиссии превышает баланс сети. Для продолжения необходимо пополнить баланс сети. Комиссия превышает баланс - Комиссия при переводе всего баланса выше. Для того, чтобы снизить комиссию Вы можете оставить 0.01. Увеличение комиссии + Комиссия при переводе всего баланса выше. Для того, чтобы снизить комиссию Вы можете оставить 0.01. + Оставить %s XTZ + Отправить все Установлена высокая комиссия Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна. Включенная комиссия превышает сумму перевода, что приводит к отрицательному значению diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index b0bd11e551..125fb77911 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -484,8 +484,10 @@ Total exceeds balance The commission fee exceeds the network balance. To continue, it is necessary to replenish the network balance. Fee exceeds balance - The fee for transferring the entire balance is higher. To reduce the commission, you can leave 0.01. 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 diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransactionUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransactionUseCase.kt index 55f503cf15..55c5e0cd88 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransactionUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransactionUseCase.kt @@ -2,17 +2,13 @@ package com.tangem.domain.transaction.usecase import arrow.core.Either import com.tangem.blockchain.common.Amount -import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.common.transaction.Fee import com.tangem.domain.tokens.model.Network import com.tangem.domain.transaction.TransactionRepository import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.withContext class CreateTransactionUseCase( private val transactionRepository: TransactionRepository, - private val dispatchers: CoroutineDispatcherProvider, ) { /** @@ -26,18 +22,16 @@ class CreateTransactionUseCase( destination: String, userWalletId: UserWalletId, network: Network, - ): Either = withContext(dispatchers.io) { - Either.catch { - requireNotNull( - transactionRepository.createTransaction( - amount = amount, - fee = fee, - memo = memo, - destination = destination, - userWalletId = userWalletId, - network = network, - ), - ) { "Failed to create transaction" } - } + ) = Either.catch { + requireNotNull( + transactionRepository.createTransaction( + amount = amount, + fee = fee, + memo = memo, + destination = destination, + userWalletId = userWalletId, + network = network, + ), + ) { "Failed to create transaction" } } } \ No newline at end of file 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 6d2975319a..cdbd005127 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 @@ -57,16 +57,28 @@ internal sealed class SendNotification(val config: NotificationConfig) { sealed class Warning( title: TextReference, subtitle: TextReference, + buttonsState: NotificationConfig.ButtonsState? = null, ) : SendNotification( config = NotificationConfig( title = title, subtitle = subtitle, iconResId = R.drawable.img_attention_20, + buttonsState = buttonsState, ), ) { - data class HighFeeError(val amount: String) : Warning( + data class HighFeeError( + val amount: String, + val onConfirmClick: () -> Unit, + val onDismissClick: () -> 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, + ), ) data class ExistentialDeposit(val deposit: String) : Warning( 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 ce29bd2c60..18e0b4f34c 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 @@ -6,6 +6,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWallet +import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents import com.tangem.utils.Provider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -21,6 +22,7 @@ internal class SendNotificationFactory( private val currentStateProvider: Provider, private val userWalletProvider: Provider, private val walletManagersFacade: WalletManagersFacade, + private val clickIntents: SendClickIntents, ) { fun create(): Flow> = currentStateProvider().currentState @@ -30,19 +32,33 @@ internal class SendNotificationFactory( val feeState = state.feeState ?: return@map persistentListOf() val recipientState = state.recipientState ?: return@map persistentListOf() val feeAmount = feeState.fee?.amount?.value ?: BigDecimal.ZERO + val amountValue = state.amountState?.amountTextField?.value?.toBigDecimalOrNull() ?: BigDecimal.ZERO + val sendAmount = if (feeState.isSubtract) feeState.receivedAmountValue else amountValue buildList { // errors - addExceedBalanceNotification(feeAmount, feeState.receivedAmountValue) - addInvalidAmountNotification(feeState.isSubtract, feeState.receivedAmountValue) - addMinimumAmountErrorNotification(feeAmount, feeState.receivedAmountValue) + addExceedBalanceNotification(feeAmount, sendAmount) + addInvalidAmountNotification(feeState.isSubtract, sendAmount) + addMinimumAmountErrorNotification(feeAmount, sendAmount) addReserveAmountErrorNotification(recipientState.addressTextField.value) - addTransactionLimitErrorNotification(feeAmount, feeState.receivedAmountValue) + addTransactionLimitErrorNotification(feeAmount, sendAmount) // warnings - addExistentialWarningNotification(feeAmount, feeState.receivedAmountValue) - addHighFeeWarningNotification() + addExistentialWarningNotification(feeAmount, sendAmount) + addHighFeeWarningNotification(amountValue, state.sendState.ignoreAmountReduce) }.toImmutableList() } + fun dismissHighFeeWarningState(): SendUiState { + val state = currentStateProvider() + val sendState = state.sendState + val updatedNotifications = sendState.notifications.filterNot { it is SendNotification.Warning.HighFeeError } + return state.copy( + sendState = sendState.copy( + ignoreAmountReduce = true, + notifications = updatedNotifications.toImmutableList(), + ), + ) + } + private fun MutableList.addExceedBalanceNotification( feeAmount: BigDecimal, receivedAmount: BigDecimal, @@ -173,16 +189,30 @@ internal class SendNotificationFactory( } } - private fun MutableList.addHighFeeWarningNotification() { - // TODO Move Blockchain check elsewhere - if (cryptoCurrencyStatusProvider().currency.network.id.value == Blockchain.Tezos.id) { - add(SendNotification.Warning.HighFeeError(TEZOS_FEE_THRESHOLD)) + private fun MutableList.addHighFeeWarningNotification( + sendAmount: BigDecimal, + ignoreAmountReduce: Boolean, + ) { + val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() + val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO + val isTezos = cryptoCurrencyStatus.currency.network.id.value == Blockchain.Tezos.id + if (!ignoreAmountReduce && sendAmount == balance && isTezos) { + add( + SendNotification.Warning.HighFeeError( + amount = TEZOS_FEE_THRESHOLD.toPlainString(), + onConfirmClick = { + val reduceTo = sendAmount.minus(TEZOS_FEE_THRESHOLD).toPlainString() + clickIntents.onAmountReduceClick(reduceTo) + }, + onDismissClick = clickIntents::onAmountReduceIgnoreClick, + ), + ) } } companion object { private const val CARDANO_MINIMUM = "1" private const val DOGECOIN_MINIMUM = "0.01" - private const val TEZOS_FEE_THRESHOLD = "0.01" + private val TEZOS_FEE_THRESHOLD = BigDecimal("0.01") } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt index 3db22025d6..46526153e8 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt @@ -88,6 +88,7 @@ internal sealed class SendStates { val isSuccess: Boolean = false, val transactionDate: Long = 0L, val txUrl: String = "", + val ignoreAmountReduce: Boolean = false, val notifications: ImmutableList = persistentListOf(), ) : SendStates() } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/SendContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/SendContent.kt index b9f84d7264..ccff5dd66b 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/SendContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/SendContent.kt @@ -197,7 +197,10 @@ internal fun LazyListScope.notifications(configs: ImmutableList TangemTheme.colors.background.action + else -> TangemTheme.colors.button.disabled + }, iconTint = when (it) { is SendNotification.Error -> TangemTheme.colors.icon.warning is SendNotification.Warning -> null 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 43a116ee65..90e3049f47 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 @@ -53,5 +53,9 @@ interface SendClickIntents { fun showFee() fun onExploreClick(txUrl: String) + + fun onAmountReduceClick(reducedAmount: String) + + fun onAmountReduceIgnoreClick() // 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 d4861a2e74..151eea4275 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 @@ -109,6 +109,7 @@ internal class SendViewModel @Inject constructor( currentStateProvider = Provider { uiState }, userWalletProvider = Provider { userWallet }, walletManagersFacade = walletManagersFacade, + clickIntents = this, ) // todo convert to StateFlow @@ -457,6 +458,16 @@ internal class SendViewModel @Inject constructor( override fun onExploreClick(txUrl: String) = innerRouter.openUrl(txUrl) + override fun onAmountReduceClick(reducedAmount: String) { + uiState = stateFactory.getOnAmountValueChange(reducedAmount) + uiState = sendNotificationFactory.dismissHighFeeWarningState() + getFee() + } + + override fun onAmountReduceIgnoreClick() { + uiState = sendNotificationFactory.dismissHighFeeWarningState() + } + private fun verifyAndSendTransaction() { val recipient = uiState.recipientState?.addressTextField?.value ?: return val feeState = uiState.feeState ?: return