diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 136cc2857f..256b94877c 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -79,7 +79,7 @@ Посмотреть историю транзакций Обозреватель Комиссия - Сетевые комиссии – это плата пользователя за обработку и подтверждение транзакций. Размер комиссии зависит от нагрузки на сеть, объема транзакции и приоритета исполнения. %s + Сетевые комиссии – это плата пользователя за обработку и подтверждение транзакций. Размер комиссии зависит от нагрузки на сеть, объема транзакции и приоритета исполнения. %s Свое Быстро По рынку @@ -310,7 +310,7 @@ В этом случае вам будет необходимо начать процесс заново. Вы хотите выйти из процесса активации? Подготовка - Другой кошелек уже был создан на карте, которую вы пытаетесь добавить. Хотите сбросить его и использовать карту для бэкапа? + Другой кошелек уже был создан на карте, которую вы пытаетесь добавить. Если на нем есть средства, пожалуйста сначала выведите их, а затем сделайте сброс до заводских настроек и используйте как резервную. Резервная копия Прочитать о seed-фразе @@ -426,12 +426,12 @@ Приготовьте свою карту Уже содержится в введенном адресе Вычесть - Недостаточно средств для покрытия комиссии сети. Вычесть комиссию %s из отправляемой сумму? + Недостаточно средств для покрытия комиссии сети. Вычесть комиссию %s из отправляемой суммы? + Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна. Вы указали комиссию ниже рекомендуемой, это может привести к задержке исполнения вашей транзакции. Продолжить? Причина: %1$s\nКод: %2$s Транзакция не выполнена Сумма - Подтверждение %1$s, %2$s Адрес Код назначения @@ -536,7 +536,7 @@ Балансы скрыты Балансы показаны Отменить - В данный момент покупка монеты %s недоступна. Но мы работаем над её добавлением.” + В данный момент покупка монеты %s недоступна. Но мы работаем над её добавлением. У вас нет средств для отправки. Пополните счет, чтобы иметь возможность отправить с него средства. Выбранная операция в данный момент недоступна. Попробуйте позже. Обмен %s не доступен. Но мы работаем над его добавлением. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index eacae3a8ac..a68246f965 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -310,7 +310,7 @@ In this case, you will need to start from the beginning. Do you want to exit the activation process? Getting started - Another wallet has already been created on the card you\'re trying to add. Do you want to reset it and use the card for a new wallet? + Another wallet has already been created on the card you\'re trying to add. If you have funds in this wallet, please withdraw it and then reset this card and add it as a backup. Creating a backup Read more about seed phrase @@ -422,11 +422,11 @@ Already included in the entered address Subtract Not enough funds to cover the network commission. Subtract the commission %s from the amount sent? + The commission amount is %s times the recommended amount. Make sure that the custom settings are correct. You specified a commission below the recommended amount, which could cause a delay in your transaction. Continue? Reason: %1$s\nCode: %2$s The transaction is not completed Amount - Confirm %1$s, %2$s Address Destination Tag 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 d3adc2e74c..b8da006bb9 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 @@ -58,6 +58,16 @@ internal sealed class SendAlertState { override val confirmButtonText: TextReference = resourceReference(R.string.common_continue) } + data class FeeTooHigh( + val times: String, + override val onConfirmClick: () -> Unit, + ) : SendAlertState() { + override val title: TextReference? = null + override val message: TextReference = + resourceReference(id = R.string.send_alert_fee_too_high_text, wrappedList(times)) + override val confirmButtonText: TextReference = resourceReference(R.string.common_continue) + } + data class FeeCoverage( val amount: String, override val onConfirmClick: (() -> Unit), 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 3e615c7835..1798d8fe79 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 @@ -115,6 +115,20 @@ internal class SendEventStateFactory( ) } + fun getFeeTooHighAlert(diff: String, onConsume: () -> Unit): SendUiState { + return currentStateProvider().copy( + event = triggeredEvent( + data = SendEvent.ShowAlert( + SendAlertState.FeeTooHigh( + onConfirmClick = clickIntents::showSend, + times = diff, + ), + ), + 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/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index 709779d1df..6a4e8a383e 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -30,6 +30,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import java.math.BigDecimal +import java.math.BigInteger @Suppress("LongParameterList") internal class SendNotificationFactory( @@ -64,6 +65,7 @@ internal class SendNotificationFactory( // warnings addExistentialWarningNotification(feeAmount, amountValue) addHighFeeWarningNotification(feeAmount, amountValue, sendState.ignoreAmountReduce) + addTooHighNotification(feeState.feeSelectorState) addTooLowNotification(feeState) }.toImmutableList() } @@ -279,6 +281,18 @@ internal class SendNotificationFactory( } } + private fun MutableList.addTooHighNotification(feeSelectorState: FeeSelectorState) { + if (feeSelectorState !is FeeSelectorState.Content) return + val multipleFees = feeSelectorState.fees as? TransactionFee.Choosable ?: return + val highValue = multipleFees.priority.amount.value ?: return + val customAmount = feeSelectorState.customValues.firstOrNull() ?: return + val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) + val diff = (customValue / highValue).toBigInteger() + if (feeSelectorState.selectedFee == FeeType.Custom && diff > FEE_MAX_DIFF) { + add(SendNotification.Warning.TooHigh(diff.toString())) + } + } + private suspend fun MutableList.addExceedsBalanceNotification(fee: Fee?) { val feeValue = fee?.amount?.value ?: BigDecimal.ZERO val userWalletId = userWalletProvider().walletId @@ -359,5 +373,6 @@ internal class SendNotificationFactory( companion object { private const val DOGECOIN_MINIMUM = "0.01" private val TEZOS_FEE_THRESHOLD = BigDecimal("0.01") + internal val FEE_MAX_DIFF = BigInteger("5") } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt index 1a57669334..06a47de259 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt @@ -4,6 +4,7 @@ import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.core.ui.utils.parseToBigDecimal import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.send.impl.presentation.state.SendUiState +import com.tangem.features.send.impl.presentation.state.confirm.SendNotificationFactory /** * Check if sending amount with fee is greater than balance @@ -26,4 +27,19 @@ internal fun checkIfFeeTooLow(state: SendUiState): Boolean { val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) return feeSelectorState.selectedFee == FeeType.Custom && minimumValue > customValue +} + +/** + * Check if custom fee is too high + */ +internal fun checkIfFeeTooHigh(state: SendUiState, onShow: (String) -> Unit): Boolean { + val feeSelectorState = state.feeState?.feeSelectorState as? FeeSelectorState.Content ?: return false + val multipleFees = feeSelectorState.fees as? TransactionFee.Choosable ?: return false + val highValue = multipleFees.priority.amount.value ?: return false + val customAmount = feeSelectorState.customValues.firstOrNull() ?: return false + val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) + val diff = (customValue / highValue).toBigInteger() + val isShow = feeSelectorState.selectedFee == FeeType.Custom && diff > SendNotificationFactory.FEE_MAX_DIFF + if (isShow) onShow(diff.toString()) + return isShow } \ No newline at end of file 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 217631c38e..92189a24ef 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 @@ -1,20 +1,15 @@ package com.tangem.features.send.impl.presentation.state.fee -import com.tangem.blockchain.common.transaction.TransactionFee -import com.tangem.core.ui.utils.parseToBigDecimal +import com.tangem.features.send.impl.presentation.state.SendNotification import com.tangem.features.send.impl.presentation.state.SendUiState import com.tangem.features.send.impl.presentation.state.SendUiStateType import com.tangem.features.send.impl.presentation.state.StateRouter -import com.tangem.features.send.impl.presentation.state.fields.SendTextField -import com.tangem.features.send.impl.presentation.state.SendNotification import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents import com.tangem.utils.Provider -import com.tangem.utils.toFormattedString import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map -import java.math.BigDecimal @Suppress("LongParameterList") internal class FeeNotificationFactory( @@ -29,16 +24,7 @@ internal class FeeNotificationFactory( val state = currentStateProvider() val feeState = state.feeState ?: return@map persistentListOf() buildList { - when (val feeSelectorState = feeState.feeSelectorState) { - FeeSelectorState.Error -> { - addFeeUnreachableNotification(feeSelectorState) - } - is FeeSelectorState.Content -> { - val customFee = feeSelectorState.customValues - val selectedFee = feeSelectorState.selectedFee - addTooHighNotification(feeSelectorState.fees, selectedFee, customFee) - } - } + addFeeUnreachableNotification(feeState.feeSelectorState) }.toImmutableList() } @@ -47,24 +33,4 @@ internal class FeeNotificationFactory( add(SendNotification.Warning.NetworkFeeUnreachable(clickIntents::feeReload)) } } - - private fun MutableList.addTooHighNotification( - transactionFee: TransactionFee, - selectedFee: FeeType, - customFee: List, - ) { - val multipleFees = transactionFee as? TransactionFee.Choosable ?: return - val highValue = multipleFees.priority.amount.value ?: return - val customAmount = customFee.firstOrNull() ?: return - val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) - val diff = customValue / highValue - if (selectedFee == FeeType.Custom && diff > FEE_MAX_DIFF) { - add(SendNotification.Warning.TooHigh(diff.toFormattedString(HIGH_FEE_DIFF_DECIMALS))) - } - } - - companion object { - private val FEE_MAX_DIFF = BigDecimal(5) - private const val HIGH_FEE_DIFF_DECIMALS = 0 - } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt index bb360d218b..0a2a65c93e 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt @@ -3,7 +3,6 @@ package com.tangem.features.send.impl.presentation.ui.fee import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.compose.animation.* -import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -12,15 +11,12 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.core.ui.components.SpacerWMax import com.tangem.core.ui.components.rows.SelectorRowItem import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.utils.BigDecimalFormatter -import com.tangem.features.send.impl.R -import com.tangem.features.send.impl.presentation.state.SendNotification import com.tangem.features.send.impl.presentation.state.SendStates import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState import com.tangem.features.send.impl.presentation.state.fee.FeeType @@ -64,11 +60,6 @@ internal fun SendSpeedSelectorItem( showDivider = showDivider, ) SendSpeedSelectorItemError(isError = feeSelectorState is FeeSelectorState.Error) - - if (feeType == FeeType.Custom) { - val showWarning = state.notifications.any { it is SendNotification.Warning.TooHigh } - WarningIcon(showWarning = showWarning) - } } } } @@ -97,29 +88,6 @@ private fun SendSpeedSelectorItemError(isError: Boolean) { } } -@Composable -private fun WarningIcon(showWarning: Boolean = false) { - Row { - SpacerWMax() - AnimatedVisibility( - visible = showWarning, - label = "Custom fee warning indicator", - enter = fadeIn(), - exit = fadeOut(), - ) { - Image( - painter = painterResource(R.drawable.ic_alert_triangle_20), - contentDescription = null, - modifier = Modifier - .padding( - vertical = TangemTheme.dimens.spacing12, - horizontal = TangemTheme.dimens.spacing14, - ), - ) - } - } -} - private fun FeeSelectorState.Content.getAmount(feeType: FeeType): Amount? { val choosableFees = fees as? TransactionFee.Choosable return when (feeType) { 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 1533c95e7c..8564920606 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 @@ -525,7 +525,15 @@ internal class SendViewModel @Inject constructor( ) return true } - return false + return checkIfFeeTooHigh( + state = uiState, + onShow = { diff -> + uiState = eventStateFactory.getFeeTooHighAlert( + diff = diff, + onConsume = { uiState = eventStateFactory.onConsumeEventState() }, + ) + }, + ) } private fun onFeeCoverageAlert(): Boolean {