Updated on 2026-08-14
This commit is contained in:
commit
ac34e887d8
27 changed files with 165 additions and 236 deletions
|
|
@ -4,12 +4,16 @@
|
|||
<string name="add_tokens_title">Валюты</string>
|
||||
<string name="address_qr_code_message_format">Отправляйте только %1$s (%2$s) в сети %3$s на этот адрес. Использование другой сети может привести к утрате средств.</string>
|
||||
<string name="alert_button_request_support">Обратиться в поддержку</string>
|
||||
<string name="alert_button_try_again">Попробовать снова</string>
|
||||
<string name="alert_demo_feature_disabled">Эта функция недоступна в демонстрационном режиме</string>
|
||||
<string name="alert_failed_to_send_transaction_message">Причина: %s</string>
|
||||
<string name="alert_failed_to_send_transaction_title">Не могу отправить транзакцию</string>
|
||||
<string name="alert_manage_tokens_unsupported_blockchain_by_card_message">Выбранный кошелёк не поддерживает сеть %1$s</string>
|
||||
<string name="alert_manage_tokens_unsupported_curve_message">Для активации криптографии сети %1$s необходимо сбросить кошелек до заводских настроек. Пожалуйста, выведите свои средства, чтобы не потерять их, после сброса доступ к текущему кошельку будет невозможен.</string>
|
||||
<string name="alert_manage_tokens_unsupported_message">Токены в сети %1$s не поддерживаются этой картой из-за ограничений прошивки.</string>
|
||||
<string name="alert_negative_app_rate_sent_message">Спасибо за ваш отзыв. Мы ответим в кратчайшие сроки.</string>
|
||||
<string name="alert_negative_app_rate_sent_title">Ваши предложения отправлены</string>
|
||||
<string name="alert_troubleshooting_scan_card_message">Пожалуйста, попробуйте приложить карту в точности, как показано на анимации, или запросите поддержку.</string>
|
||||
<string name="alert_troubleshooting_scan_card_title">У вас возникли трудности со сканированием карты?</string>
|
||||
<string name="alert_unsupported_card">Эта карта не предназначена для работы с этим приложением</string>
|
||||
<string name="app_settings_default_fee_footer">Подключите функцию комиссии по умолчанию и при формировании транзакции на отправку средств комиссия будет выставлена автоматически, а экран комиссии пропущен. Вы всегда сможете на него вернуться.</string>
|
||||
|
|
@ -24,6 +28,8 @@
|
|||
<string name="app_settings_theme_mode_dark">Тёмная</string>
|
||||
<string name="app_settings_theme_mode_light">Светлая</string>
|
||||
<string name="app_settings_theme_mode_system">Как в системе</string>
|
||||
<string name="app_settings_theme_selection_footer">При выборе настройки как в системе приложение будет использовать тему в соответствии с настройками вашего устройства</string>
|
||||
<string name="app_settings_theme_selection_system_short">Системная</string>
|
||||
<string name="app_settings_theme_selector_title">Тема</string>
|
||||
<string name="app_settings_title">Настройки приложения</string>
|
||||
<string name="balance_hidden_description">Чтобы скрыть или показать баланс, просто поверните ваше устройство вниз или отключите опцию его в разделе \"Настройки\"</string>
|
||||
|
|
@ -75,6 +81,7 @@
|
|||
<string name="common_create">Создать</string>
|
||||
<string name="common_delete">Удалить</string>
|
||||
<string name="common_disabled">Отключено</string>
|
||||
<string name="common_disconnect">Отключить</string>
|
||||
<string name="common_done">Готово</string>
|
||||
<string name="common_enable">Включить</string>
|
||||
<string name="common_enabled">Включено</string>
|
||||
|
|
@ -107,6 +114,7 @@
|
|||
<string name="common_reject">Отклонить</string>
|
||||
<string name="common_reload">Перезагрузить</string>
|
||||
<string name="common_rename">Переименовать</string>
|
||||
<string name="common_retry">Повторить</string>
|
||||
<string name="common_save_changes">Сохранить изменения</string>
|
||||
<string name="common_search">Искать</string>
|
||||
<string name="common_search_tokens">Поиск токенов</string>
|
||||
|
|
@ -130,6 +138,7 @@
|
|||
<string name="common_understand">Я понял</string>
|
||||
<string name="common_unknown_error">Произошла ошибка. Пожалуйста, попробуйте снова.</string>
|
||||
<string name="common_unreachable">Недоступно</string>
|
||||
<string name="common_warning">Предупреждение</string>
|
||||
<string name="common_yes">Да</string>
|
||||
<string name="contract_address_copied_message">Адрес контракта скопирован!</string>
|
||||
<string name="currency_subtitle_expanded">Доступные сети</string>
|
||||
|
|
@ -176,6 +185,7 @@
|
|||
<string name="details_row_title_flip_to_hide">Скрывать балансы жестом переворота</string>
|
||||
<string name="details_row_title_issuer">Эмитент</string>
|
||||
<string name="details_row_title_signed_hashes">Подписано</string>
|
||||
<string name="details_security_management_warning">Если вы забудете код, то потеряете доступ к своим средствам. Восстановление кода невозможно.</string>
|
||||
<string name="details_title">Подробности</string>
|
||||
<string name="disclaimer_error_loading">Проверьте подключение с интернетом или переключитесь на другую сеть</string>
|
||||
<string name="disclaimer_title">Условия использования</string>
|
||||
|
|
@ -430,8 +440,6 @@
|
|||
<string name="scan_card_settings_message">Отсканируйте карту, чтобы изменить ее настройки. Изменения затронут только ту карту, которую вы отсканировали, и не повлияют на другие карты, привязанные к вашему кошельку.</string>
|
||||
<string name="scan_card_settings_title">Приготовьте свою карту</string>
|
||||
<string name="send_additional_field_already_included">Уже содержится в введенном адресе</string>
|
||||
<string name="send_alert_fee_coverage_subract_text">Вычесть</string>
|
||||
<string name="send_alert_fee_coverage_title">Недостаточно средств для покрытия комиссии сети. Вычесть недостающую сумму для покрытия комиссии из отправляемой суммы?</string>
|
||||
<string name="send_alert_fee_too_high_text">Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна.</string>
|
||||
<string name="send_alert_fee_too_low_text">Вы указали комиссию ниже рекомендуемой, это может привести к задержке исполнения вашей транзакции. Продолжить?</string>
|
||||
<string name="send_alert_transaction_failed_text">Причина: %1$s\nКод: %2$s</string>
|
||||
|
|
@ -547,6 +555,7 @@
|
|||
<string name="token_button_unavailability_reason_empty_balance">У вас нет средств для отправки. Пополните счет, чтобы иметь возможность отправить с него средства.</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">Обмен %s не доступен. Но мы работаем над его добавлением.</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">В данный момент продажа монеты %s недоступна. Но мы работаем над её добавлением.</string>
|
||||
<string name="token_details_choose_address">Выберите адрес</string>
|
||||
<string name="token_details_generate_xpub">Сгенерировать XPUB</string>
|
||||
<string name="token_details_hide_alert_hide">Скрыть</string>
|
||||
<string name="token_details_hide_alert_message">Вы скрываете токен с главного экрана, но в любой момент сможете добавить его обратно через страницу управления токенами.</string>
|
||||
|
|
@ -656,6 +665,10 @@
|
|||
<string name="warning_express_wrong_amount_description">Пожалуйста, измените сумму для обмена</string>
|
||||
<string name="warning_failed_to_verify_card_message">Возможно, данная карта - образец или подделка</string>
|
||||
<string name="warning_failed_to_verify_card_title">Ошибка проверки подлинности</string>
|
||||
<string name="warning_hedera_missing_token_association_button_title">Ассоциировать</string>
|
||||
<string name="warning_hedera_missing_token_association_message">Этот токен должен быть ассоциирован с вашей учетной записью Hedera, прежде чем вы сможете его принять. Стоимость ассоциации ~%.4f %s</string>
|
||||
<string name="warning_hedera_missing_token_association_message_brief">Этот токен должен быть ассоциирован с вашей учетной записью Hedera, прежде чем вы сможете его принять</string>
|
||||
<string name="warning_hedera_missing_token_association_title">Ассоциируете свой токен</string>
|
||||
<string name="warning_low_signatures_message">На этой карте осталось всего %s подписей. Вам следует вывести все ваши средства.</string>
|
||||
<string name="warning_low_signatures_title">Малое количество подписей</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Токены на разных сетях могут иметь разные адреса. Пожалуйста, убедитесь при переводе средств, что ваш адрес соответствует сети.</string>
|
||||
|
|
|
|||
|
|
@ -4,12 +4,16 @@
|
|||
<string name="add_tokens_title">Manage tokens</string>
|
||||
<string name="address_qr_code_message_format">Send only %1$s (%2$s) from %3$s network to this address. Using other tokens and networks may result in loss of funds.</string>
|
||||
<string name="alert_button_request_support">Request support</string>
|
||||
<string name="alert_button_try_again">Try again</string>
|
||||
<string name="alert_demo_feature_disabled">This feature is disabled in Demo mode</string>
|
||||
<string name="alert_failed_to_send_transaction_message">Reason: %s</string>
|
||||
<string name="alert_failed_to_send_transaction_title">Can\'t send a transaction</string>
|
||||
<string name="alert_manage_tokens_unsupported_blockchain_by_card_message">The selected does not support the %1$s network</string>
|
||||
<string name="alert_manage_tokens_unsupported_curve_message">To activate the %1$s blockchain\'s cryptographic encryption, you\'ll need to reset the wallet to factory settings. Please withdraw your funds before doing so to ensure that you don\'t lose them, and then complete the reset process. Access to the current wallet will not be possible after the reset.</string>
|
||||
<string name="alert_manage_tokens_unsupported_message">Tokens in %1$s network are not supported by this card due to firmware limitation.</string>
|
||||
<string name="alert_negative_app_rate_sent_message">Thank you for your feedback. We will respond as soon as possible</string>
|
||||
<string name="alert_negative_app_rate_sent_title">Your suggestions were sent</string>
|
||||
<string name="alert_troubleshooting_scan_card_message">Please try to tap the card exactly as shown in the animation or request support.</string>
|
||||
<string name="alert_troubleshooting_scan_card_title">Are you having difficulty scanning your card?</string>
|
||||
<string name="alert_unsupported_card">This card is not designed to work with this app</string>
|
||||
<string name="app_settings_default_fee">Default Fee</string>
|
||||
|
|
@ -25,6 +29,8 @@
|
|||
<string name="app_settings_theme_mode_dark">Dark</string>
|
||||
<string name="app_settings_theme_mode_light">Light</string>
|
||||
<string name="app_settings_theme_mode_system">System default</string>
|
||||
<string name="app_settings_theme_selection_footer">If system is selected, the app will auto-adjust based on your device\'s system settings</string>
|
||||
<string name="app_settings_theme_selection_system_short">System</string>
|
||||
<string name="app_settings_theme_selector_title">Theme</string>
|
||||
<string name="app_settings_title">App Settings</string>
|
||||
<string name="balance_hidden_description">To hide or show your balances, simply flip your device screen down, or switch it off in Settings</string>
|
||||
|
|
@ -74,6 +80,7 @@
|
|||
<string name="common_create">Create</string>
|
||||
<string name="common_delete">Delete</string>
|
||||
<string name="common_disabled">Disabled</string>
|
||||
<string name="common_disconnect">Disconnect</string>
|
||||
<string name="common_done">Done</string>
|
||||
<string name="common_enable">Enable</string>
|
||||
<string name="common_enabled">Enabled</string>
|
||||
|
|
@ -106,6 +113,7 @@
|
|||
<string name="common_reject">Reject</string>
|
||||
<string name="common_reload">Reload</string>
|
||||
<string name="common_rename">Rename</string>
|
||||
<string name="common_retry">Retry</string>
|
||||
<string name="common_save_changes">Save changes</string>
|
||||
<string name="common_search">Search</string>
|
||||
<string name="common_search_tokens">Search tokens</string>
|
||||
|
|
@ -129,6 +137,7 @@
|
|||
<string name="common_understand">I understand</string>
|
||||
<string name="common_unknown_error">There was an error. Please try again.</string>
|
||||
<string name="common_unreachable">Unreachable</string>
|
||||
<string name="common_warning">Warning</string>
|
||||
<string name="common_yes">Yes</string>
|
||||
<string name="contract_address_copied_message">Contract address copied!</string>
|
||||
<string name="currency_subtitle_expanded">Available networks</string>
|
||||
|
|
@ -175,6 +184,7 @@
|
|||
<string name="details_row_title_flip_to_hide">Flip-to-Hide Balances</string>
|
||||
<string name="details_row_title_issuer">Issuer</string>
|
||||
<string name="details_row_title_signed_hashes">Signed</string>
|
||||
<string name="details_security_management_warning">If you forget the code you will lose access to your funds. Code recovery is not possible.</string>
|
||||
<string name="details_title">Details</string>
|
||||
<string name="disclaimer_error_loading">Check your internet connection or switch to a different network</string>
|
||||
<string name="disclaimer_title">Terms of Service</string>
|
||||
|
|
@ -425,8 +435,6 @@
|
|||
<string name="scan_card_settings_message">Scan the card to change its settings. The changes will impact only the card you\'ve scanned and will not affect other cards tied to your wallet.</string>
|
||||
<string name="scan_card_settings_title">Get your card ready!</string>
|
||||
<string name="send_additional_field_already_included">Already included in the entered address</string>
|
||||
<string name="send_alert_fee_coverage_subract_text">Subtract</string>
|
||||
<string name="send_alert_fee_coverage_title">Not enough funds to cover the network fee. Do you want to subtract the amount required to cover the fee?</string>
|
||||
<string name="send_alert_fee_too_high_text">The commission amount is %s times the recommended amount. Make sure that the custom settings are correct.</string>
|
||||
<string name="send_alert_fee_too_low_text">You specified a commission below the recommended amount, which could cause a delay in your transaction. Continue?</string>
|
||||
<string name="send_alert_transaction_failed_text">Reason: %1$s\nCode: %2$s</string>
|
||||
|
|
@ -548,6 +556,7 @@
|
|||
<string name="token_button_unavailability_reason_empty_balance">You do not have funds to send. Top up your account to be able to send funds from it.</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">%s swap is not available. But we are working on adding it.</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">Sell of the %s coin is currently unavailable. But we are working on adding it.</string>
|
||||
<string name="token_details_choose_address">Choose address</string>
|
||||
<string name="token_details_generate_xpub">Generate XPUB</string>
|
||||
<string name="token_details_hide_alert_hide">Hide</string>
|
||||
<string name="token_details_hide_alert_message">You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page.</string>
|
||||
|
|
@ -657,6 +666,10 @@
|
|||
<string name="warning_express_wrong_amount_description">Please change the amount to swap</string>
|
||||
<string name="warning_failed_to_verify_card_message">This card might be a production sample or counterfeit</string>
|
||||
<string name="warning_failed_to_verify_card_title">Authenticity check failed</string>
|
||||
<string name="warning_hedera_missing_token_association_button_title">Associate</string>
|
||||
<string name="warning_hedera_missing_token_association_message">This token must be associated with your Hedera account before you can receive it. Association fee ~%.4f %s</string>
|
||||
<string name="warning_hedera_missing_token_association_message_brief">This token must be associated with your Hedera account before you can receive it</string>
|
||||
<string name="warning_hedera_missing_token_association_title">Associate your token</string>
|
||||
<string name="warning_low_signatures_message">Only %s signatures are left on this card. You must withdraw all of your funds.</string>
|
||||
<string name="warning_low_signatures_title">Low signature count</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Tokens on different networks can have different addresses. Double-check that your address matches the network when you transfer funds.</string>
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ internal sealed class SendAnalyticEvents(
|
|||
params = mapOf(TOKEN to token),
|
||||
)
|
||||
|
||||
data object NoticeFeeCoverage : SendAnalyticEvents(
|
||||
event = "Notice - Network Fee Coverage",
|
||||
)
|
||||
|
||||
/** If error occurs during send transactions */
|
||||
data class TransactionError(val token: String) : SendAnalyticEvents(
|
||||
event = "Error - Transaction Rejected",
|
||||
|
|
|
|||
|
|
@ -68,16 +68,6 @@ internal sealed class SendAlertState {
|
|||
override val confirmButtonText: TextReference = resourceReference(R.string.common_continue)
|
||||
}
|
||||
|
||||
data class FeeCoverage(
|
||||
override val onConfirmClick: (() -> Unit),
|
||||
) : SendAlertState() {
|
||||
override val title: TextReference? = null
|
||||
override val message: TextReference =
|
||||
resourceReference(id = R.string.send_alert_fee_coverage_title)
|
||||
override val confirmButtonText: TextReference =
|
||||
resourceReference(id = R.string.send_alert_fee_coverage_subract_text)
|
||||
}
|
||||
|
||||
data class ReserveAmount(val amount: String) : SendAlertState() {
|
||||
override val title: TextReference =
|
||||
resourceReference(id = R.string.send_notification_invalid_reserve_amount_title, wrappedList(amount))
|
||||
|
|
|
|||
|
|
@ -48,19 +48,6 @@ internal class SendEventStateFactory(
|
|||
)
|
||||
}
|
||||
|
||||
fun getFeeCoverageAlert(onConsume: () -> Unit): SendUiState {
|
||||
return currentStateProvider().copy(
|
||||
event = triggeredEvent(
|
||||
data = SendEvent.ShowAlert(
|
||||
SendAlertState.FeeCoverage(
|
||||
onConfirmClick = clickIntents::onSubtractSelect,
|
||||
),
|
||||
),
|
||||
onConsume = onConsume,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun getFeeUpdatedAlert(fee: TransactionFee, onConsume: () -> Unit, onFeeNotIncreased: () -> Unit): SendUiState {
|
||||
val state = currentStateProvider()
|
||||
val feeSelector = state.feeState?.feeSelectorState as? FeeSelectorState.Content ?: return state
|
||||
|
|
@ -139,9 +126,7 @@ internal class SendEventStateFactory(
|
|||
return state.copy(
|
||||
event = triggeredEvent(
|
||||
data = SendEvent.ShowAlert(
|
||||
SendAlertState.FeeUnreachableError(
|
||||
onConfirmClick = { clickIntents.feeReload(true) },
|
||||
),
|
||||
SendAlertState.FeeUnreachableError(onConfirmClick = clickIntents::feeReload),
|
||||
),
|
||||
onConsume = onConsume,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -42,11 +42,6 @@ internal sealed class SendNotification(val config: NotificationConfig) {
|
|||
),
|
||||
)
|
||||
|
||||
data class ReserveAmountError(val amount: String) : Error(
|
||||
title = resourceReference(R.string.send_notification_invalid_reserve_amount_title, wrappedList(amount)),
|
||||
subtitle = resourceReference(R.string.send_notification_invalid_reserve_amount_text),
|
||||
)
|
||||
|
||||
data class TransactionLimitError(
|
||||
val cryptoCurrency: String,
|
||||
val utxoLimit: String,
|
||||
|
|
@ -153,5 +148,10 @@ internal sealed class SendNotification(val config: NotificationConfig) {
|
|||
onClick = onRefresh,
|
||||
),
|
||||
)
|
||||
|
||||
data object FeeCoverageNotification : Warning(
|
||||
title = resourceReference(R.string.send_network_fee_warning_title),
|
||||
subtitle = resourceReference(R.string.swapping_network_fee_warning_content),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ import com.tangem.domain.wallets.usecase.ValidateWalletMemoUseCase
|
|||
import com.tangem.features.send.impl.R
|
||||
import com.tangem.features.send.impl.presentation.domain.AvailableWallet
|
||||
import com.tangem.features.send.impl.presentation.state.amount.SendAmountStateConverter
|
||||
import com.tangem.features.send.impl.presentation.state.amount.SendAmountSubtractConverter
|
||||
import com.tangem.features.send.impl.presentation.state.confirm.SendConfirmStateConverter
|
||||
import com.tangem.features.send.impl.presentation.state.fee.SendFeeStateConverter
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldConverter
|
||||
|
|
@ -48,12 +47,6 @@ internal class SendStateFactory(
|
|||
appCurrencyProvider = appCurrencyProvider,
|
||||
)
|
||||
}
|
||||
private val amountSubtractConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
SendAmountSubtractConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
)
|
||||
}
|
||||
private val amountStateConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
SendAmountStateConverter(
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
|
|
@ -265,14 +258,6 @@ internal class SendStateFactory(
|
|||
//endregion
|
||||
|
||||
//region send
|
||||
fun onSubtractSelect(isAmountSubtractAvailable: Boolean): SendUiState {
|
||||
val state = currentStateProvider()
|
||||
|
||||
if (!isAmountSubtractAvailable) return state
|
||||
|
||||
return amountSubtractConverter.convert(Unit)
|
||||
}
|
||||
|
||||
fun getSendingStateUpdate(isSending: Boolean): SendUiState {
|
||||
val state = currentStateProvider()
|
||||
return state.copy(
|
||||
|
|
|
|||
|
|
@ -50,10 +50,7 @@ internal sealed class SendStates {
|
|||
val segmentedButtonConfig: PersistentList<SendAmountSegmentedButtonsConfig>,
|
||||
val isSegmentedButtonsEnabled: Boolean,
|
||||
val amountTextField: SendTextField.AmountField,
|
||||
val notifications: ImmutableList<SendNotification>,
|
||||
val appCurrencyCode: String,
|
||||
val isFeeLoading: Boolean,
|
||||
val subtractedFee: BigDecimal?,
|
||||
) : SendStates()
|
||||
|
||||
/** Recipient state */
|
||||
|
|
@ -90,7 +87,6 @@ internal sealed class SendStates {
|
|||
override val isPrimaryButtonEnabled: Boolean = true,
|
||||
val isSending: Boolean,
|
||||
val isSuccess: Boolean,
|
||||
val isSubtract: Boolean,
|
||||
val transactionDate: Long,
|
||||
val txUrl: String,
|
||||
val ignoreAmountReduce: Boolean,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
package com.tangem.features.send.impl.presentation.state.amount
|
||||
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
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.fields.SendAmountFieldChangeConverter
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendAmountFieldMaxAmountConverter
|
||||
import com.tangem.utils.Provider
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
/**
|
||||
* Factory to produce amount state for [SendUiState]
|
||||
|
|
@ -43,18 +41,4 @@ internal class AmountStateFactory(
|
|||
}
|
||||
|
||||
fun getOnCurrencyChangedState(isFiat: Boolean) = amountCurrencyConverter.convert(isFiat)
|
||||
|
||||
fun getAmountNotificationState(notifications: ImmutableList<SendNotification>): SendUiState {
|
||||
val state = currentStateProvider()
|
||||
return state.copy(
|
||||
amountState = state.amountState?.copy(notifications = notifications),
|
||||
)
|
||||
}
|
||||
|
||||
fun getOnAmountFeeLoadingCancel(): SendUiState {
|
||||
val state = currentStateProvider()
|
||||
return state.copy(
|
||||
amountState = state.amountState?.copy(isFeeLoading = false),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -39,10 +39,7 @@ internal class SendAmountStateConverter(
|
|||
tokenIconState = iconStateConverter.convert(status),
|
||||
amountTextField = sendAmountFieldConverter.convert(value),
|
||||
isPrimaryButtonEnabled = false,
|
||||
notifications = persistentListOf(),
|
||||
isFeeLoading = false,
|
||||
appCurrencyCode = appCurrency.code,
|
||||
subtractedFee = null,
|
||||
segmentedButtonConfig = persistentListOf(
|
||||
SendAmountSegmentedButtonsConfig(
|
||||
title = stringReference(status.currency.symbol),
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
package com.tangem.features.send.impl.presentation.state.amount
|
||||
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class SendAmountSubtractConverter(
|
||||
private val currentStateProvider: Provider<SendUiState>,
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
) : Converter<Unit, SendUiState> {
|
||||
override fun convert(value: Unit): SendUiState {
|
||||
val state = currentStateProvider()
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val amountState = state.amountState ?: return state
|
||||
val feeState = state.feeState ?: return state
|
||||
val feeValue = feeState.fee?.amount?.value ?: return state
|
||||
val amountTextField = amountState.amountTextField
|
||||
val amountValue = amountTextField.cryptoAmount.value ?: return state
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: return state
|
||||
val fiatRate = cryptoCurrencyStatus.value.fiatRate
|
||||
val cryptoDecimals = amountTextField.cryptoAmount.decimals
|
||||
val fiatDecimals = amountTextField.fiatAmount.decimals
|
||||
|
||||
val feeDiff = amountState.subtractedFee?.let { feeValue.minus(it) }
|
||||
?: amountValue.minus(balance.minus(feeValue))
|
||||
val decimalCryptoValue = amountValue.minus(feeDiff)
|
||||
|
||||
if (decimalCryptoValue < BigDecimal.ZERO) return state
|
||||
|
||||
val decimalFiatValue = decimalCryptoValue.multiply(fiatRate)
|
||||
val cryptoValue = decimalCryptoValue.parseBigDecimal(cryptoDecimals)
|
||||
val fiatValue = decimalFiatValue.parseBigDecimal(fiatDecimals)
|
||||
|
||||
return state.copy(
|
||||
sendState = state.sendState?.copy(isSubtract = true),
|
||||
amountState = amountState.copy(
|
||||
subtractedFee = feeValue,
|
||||
amountTextField = amountTextField.copy(
|
||||
value = cryptoValue,
|
||||
fiatValue = fiatValue,
|
||||
cryptoAmount = amountTextField.cryptoAmount.copy(value = decimalCryptoValue),
|
||||
fiatAmount = amountTextField.fiatAmount.copy(value = decimalFiatValue),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,6 @@ internal class SendConfirmStateConverter(
|
|||
isPrimaryButtonEnabled = true,
|
||||
isSending = false,
|
||||
isSuccess = false,
|
||||
isSubtract = false,
|
||||
transactionDate = 0L,
|
||||
txUrl = "",
|
||||
ignoreAmountReduce = false,
|
||||
|
|
|
|||
|
|
@ -18,11 +18,10 @@ import com.tangem.domain.wallets.models.UserWallet
|
|||
import com.tangem.features.send.impl.R
|
||||
import com.tangem.features.send.impl.presentation.analytics.SendAnalyticEvents
|
||||
import com.tangem.features.send.impl.presentation.state.*
|
||||
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.state.fee.checkIfFeeTooHigh
|
||||
import com.tangem.features.send.impl.presentation.state.fee.*
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isDogecoin
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isTezos
|
||||
import com.tangem.utils.Provider
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -36,11 +35,11 @@ import java.math.BigDecimal
|
|||
internal class SendNotificationFactory(
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
private val coinCryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
private val feePaidCryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
private val currentStateProvider: Provider<SendUiState>,
|
||||
private val userWalletProvider: Provider<UserWallet>,
|
||||
private val currencyChecksRepository: CurrencyChecksRepository,
|
||||
private val stateRouterProvider: Provider<StateRouter>,
|
||||
private val isSubtractAvailableProvider: Provider<Boolean>,
|
||||
private val clickIntents: SendClickIntents,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase,
|
||||
|
|
@ -52,19 +51,33 @@ internal class SendNotificationFactory(
|
|||
val state = currentStateProvider()
|
||||
val sendState = state.sendState ?: return@map persistentListOf()
|
||||
val feeState = state.feeState ?: return@map persistentListOf()
|
||||
val feeAmount = feeState.fee?.amount?.value ?: BigDecimal.ZERO
|
||||
val balance = cryptoCurrencyStatusProvider().value.amount ?: BigDecimal.ZERO
|
||||
val amountValue = state.amountState?.amountTextField?.cryptoAmount?.value ?: BigDecimal.ZERO
|
||||
val feeValue = feeState.fee?.amount?.value ?: BigDecimal.ZERO
|
||||
val isFeeCoverage = checkFeeCoverage(
|
||||
isSubtractAvailable = isSubtractAvailableProvider(),
|
||||
balance = balance,
|
||||
amountValue = amountValue,
|
||||
feeValue = feeValue,
|
||||
)
|
||||
val sendingAmount = calculateSubtractedAmount(
|
||||
isFeeCoverage = isFeeCoverage,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatusProvider(),
|
||||
amountValue = amountValue,
|
||||
feeValue = feeValue,
|
||||
)
|
||||
buildList {
|
||||
// errors
|
||||
addFeeUnreachableNotification(feeState.feeSelectorState)
|
||||
addExceedBalanceNotification(feeAmount, amountValue)
|
||||
addExceedBalanceNotification(feeValue, sendingAmount)
|
||||
addExceedsBalanceNotification(feeState.fee)
|
||||
addMinimumAmountErrorNotification(feeAmount, amountValue)
|
||||
addDustWarningNotification(feeAmount, amountValue)
|
||||
addTransactionLimitErrorNotification(feeAmount, amountValue)
|
||||
addMinimumAmountErrorNotification(feeValue, sendingAmount)
|
||||
addDustWarningNotification(feeValue, sendingAmount)
|
||||
addTransactionLimitErrorNotification(feeValue, sendingAmount)
|
||||
// warnings
|
||||
addExistentialWarningNotification(feeAmount, amountValue)
|
||||
addHighFeeWarningNotification(feeAmount, amountValue, sendState.ignoreAmountReduce)
|
||||
addExistentialWarningNotification(feeValue, amountValue)
|
||||
addFeeCoverageNotification(isFeeCoverage)
|
||||
addHighFeeWarningNotification(amountValue, sendState.ignoreAmountReduce)
|
||||
addTooHighNotification(feeState.feeSelectorState)
|
||||
addTooLowNotification(feeState)
|
||||
}.toImmutableList()
|
||||
|
|
@ -95,13 +108,11 @@ internal class SendNotificationFactory(
|
|||
receivedAmount: BigDecimal,
|
||||
) {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val feePaidCryptoCurrencyStatus = feePaidCryptoCurrencyStatusProvider()
|
||||
val cryptoAmount = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
|
||||
|
||||
val isCurrentNotFeePaidCurrency = cryptoCurrencyStatus.currency.id != feePaidCryptoCurrencyStatus?.currency?.id
|
||||
if (isCurrentNotFeePaidCurrency) return
|
||||
if (!isSubtractAvailableProvider()) return
|
||||
|
||||
val showNotification = receivedAmount + feeAmount > cryptoAmount
|
||||
val showNotification = receivedAmount + feeAmount > balance
|
||||
if (showNotification) {
|
||||
add(SendNotification.Error.TotalExceedsBalance)
|
||||
}
|
||||
|
|
@ -192,16 +203,22 @@ internal class SendNotificationFactory(
|
|||
}
|
||||
}
|
||||
|
||||
private fun MutableList<SendNotification>.addFeeCoverageNotification(sendingAmount: Boolean) {
|
||||
if (sendingAmount) {
|
||||
analyticsEventHandler.send(SendAnalyticEvents.NoticeFeeCoverage)
|
||||
add(SendNotification.Warning.FeeCoverageNotification)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<SendNotification>.addHighFeeWarningNotification(
|
||||
feeAmount: BigDecimal,
|
||||
sendAmount: BigDecimal,
|
||||
ignoreAmountReduce: Boolean,
|
||||
) {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
|
||||
val isTezos = cryptoCurrencyStatus.currency.network.id.value == Blockchain.Tezos.id
|
||||
val isTezos = isTezos(cryptoCurrencyStatus.currency.network.id.value)
|
||||
val threshold = Blockchain.Tezos.minimalAmount()
|
||||
val isTotalBalance = feeAmount.plus(sendAmount) >= balance && balance > threshold
|
||||
val isTotalBalance = sendAmount >= balance && balance > threshold
|
||||
if (!ignoreAmountReduce && isTotalBalance && isTezos) {
|
||||
add(
|
||||
SendNotification.Warning.HighFeeError(
|
||||
|
|
@ -218,6 +235,7 @@ internal class SendNotificationFactory(
|
|||
}
|
||||
}
|
||||
|
||||
// todo remove in [REDACTED_TASK_KEY]
|
||||
private fun MutableList<SendNotification>.addMinimumAmountErrorNotification(
|
||||
feeAmount: BigDecimal,
|
||||
receivedAmount: BigDecimal,
|
||||
|
|
|
|||
|
|
@ -1,21 +1,73 @@
|
|||
package com.tangem.features.send.impl.presentation.state.fee
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.core.ui.utils.parseToBigDecimal
|
||||
import com.tangem.domain.common.extensions.minimalAmount
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
/**
|
||||
* Check if sending amount with fee is greater than balance
|
||||
* Check and calculates subtracted amount
|
||||
*/
|
||||
internal fun checkFeeCoverage(state: SendUiState, cryptoCurrencyStatus: CryptoCurrencyStatus): Boolean {
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: return false
|
||||
val fee = state.feeState?.fee?.amount?.value ?: return false
|
||||
val amount = state.amountState?.amountTextField?.cryptoAmount?.value ?: return false
|
||||
return balance < amount + fee && balance > fee
|
||||
internal fun checkAndCalculateSubtractedAmount(
|
||||
isAmountSubtractAvailable: Boolean,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
amountValue: BigDecimal,
|
||||
feeValue: BigDecimal,
|
||||
): BigDecimal {
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: return amountValue
|
||||
val isFeeCoverage = checkFeeCoverage(
|
||||
isSubtractAvailable = isAmountSubtractAvailable,
|
||||
balance = balance,
|
||||
amountValue = amountValue,
|
||||
feeValue = feeValue,
|
||||
)
|
||||
return calculateSubtractedAmount(
|
||||
isFeeCoverage = isFeeCoverage,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
amountValue = amountValue,
|
||||
feeValue = feeValue,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if sending amount with fee is greater than balance
|
||||
*/
|
||||
internal fun checkFeeCoverage(
|
||||
isSubtractAvailable: Boolean,
|
||||
balance: BigDecimal,
|
||||
amountValue: BigDecimal,
|
||||
feeValue: BigDecimal,
|
||||
): Boolean {
|
||||
if (!isSubtractAvailable) return false
|
||||
return balance < amountValue + feeValue && balance > feeValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates subtracted amount
|
||||
*/
|
||||
internal fun calculateSubtractedAmount(
|
||||
isFeeCoverage: Boolean,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
amountValue: BigDecimal,
|
||||
feeValue: BigDecimal,
|
||||
): BigDecimal {
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: return amountValue
|
||||
return if (isFeeCoverage) {
|
||||
var subtractedValue = minOf(amountValue, balance.minus(feeValue))
|
||||
if (BlockchainUtils.isTezos(cryptoCurrencyStatus.currency.network.id.value)) {
|
||||
val threshold = Blockchain.Tezos.minimalAmount()
|
||||
subtractedValue = -threshold
|
||||
}
|
||||
subtractedValue
|
||||
} else {
|
||||
amountValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ internal class FeeStateFactory(
|
|||
val state = currentStateProvider()
|
||||
val feeState = state.feeState ?: return state
|
||||
return state.copy(
|
||||
amountState = state.amountState?.copy(isFeeLoading = true),
|
||||
feeState = feeState.copy(
|
||||
feeSelectorState = if (feeState.feeSelectorState is FeeSelectorState.Content) {
|
||||
feeState.feeSelectorState
|
||||
|
|
@ -78,7 +77,6 @@ internal class FeeStateFactory(
|
|||
|
||||
val fee = feeConverter.convert(updatedFeeSelectorState)
|
||||
return state.copy(
|
||||
amountState = state.amountState?.copy(isFeeLoading = false),
|
||||
feeState = feeState.copy(
|
||||
feeSelectorState = updatedFeeSelectorState,
|
||||
fee = fee,
|
||||
|
|
@ -90,7 +88,6 @@ internal class FeeStateFactory(
|
|||
fun onFeeOnErrorState(): SendUiState {
|
||||
val state = currentStateProvider()
|
||||
return state.copy(
|
||||
amountState = state.amountState?.copy(isFeeLoading = false),
|
||||
feeState = state.feeState?.copy(
|
||||
feeSelectorState = FeeSelectorState.Error,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ internal class SendAmountFieldChangeConverter(
|
|||
return state.copy(
|
||||
amountState = amountState.copy(
|
||||
isPrimaryButtonEnabled = !isExceedBalance && !isZero,
|
||||
subtractedFee = null,
|
||||
amountTextField = amountTextField.copy(
|
||||
value = cryptoValue,
|
||||
fiatValue = fiatValue,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ internal class SendAmountFieldMaxAmountConverter(
|
|||
return state.copy(
|
||||
amountState = amountState.copy(
|
||||
isPrimaryButtonEnabled = true,
|
||||
subtractedFee = null,
|
||||
amountTextField = amountTextField.copy(
|
||||
value = cryptoValue,
|
||||
fiatValue = fiatValue,
|
||||
|
|
|
|||
|
|
@ -22,10 +22,7 @@ internal object AmountStatePreviewData {
|
|||
walletBalance = stringReference("123.123"),
|
||||
tokenIconState = TokenIconState.Loading,
|
||||
segmentedButtonConfig = persistentListOf(),
|
||||
notifications = persistentListOf(),
|
||||
isFeeLoading = false,
|
||||
appCurrencyCode = "usd",
|
||||
subtractedFee = null,
|
||||
amountTextField = SendTextField.AmountField(
|
||||
value = "123.123123123123123123",
|
||||
onValueChange = {},
|
||||
|
|
|
|||
|
|
@ -34,14 +34,12 @@ internal object SendClickIntentsStub : SendClickIntents {
|
|||
|
||||
override fun onRecipientMemoValueChange(value: String) {}
|
||||
|
||||
override fun feeReload(isToNextState: Boolean) {}
|
||||
override fun feeReload() {}
|
||||
|
||||
override fun onFeeSelectorClick(feeType: FeeType) {}
|
||||
|
||||
override fun onCustomFeeValueChange(index: Int, value: String) {}
|
||||
|
||||
override fun onSubtractSelect() {}
|
||||
|
||||
override fun onReadMoreClick() {}
|
||||
|
||||
override fun onSendClick() {}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ private fun SendNavigationButton(
|
|||
val isFromConfirmation = currentState.isFromConfirmation
|
||||
val isCorrectScreen = currentState.type == SendUiStateType.Amount || currentState.type == SendUiStateType.Fee
|
||||
val isSendingState = currentState.type == SendUiStateType.Send && !isSuccess && !isSending
|
||||
val showProgress = uiState.amountState?.isFeeLoading == true
|
||||
|
||||
val (buttonTextId, buttonClick) = getButtonData(
|
||||
currentState = currentState,
|
||||
|
|
@ -120,7 +119,7 @@ private fun SendNavigationButton(
|
|||
if (isSendingState) hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
buttonClick()
|
||||
},
|
||||
showProgress = showProgress,
|
||||
showProgress = false,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = TangemButtonsDefaults.primaryButtonColors,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ private const val AMOUNT_BUTTONS_KEY = "amountButtonsKey"
|
|||
internal fun LazyListScope.buttons(
|
||||
segmentedButtonConfig: PersistentList<SendAmountSegmentedButtonsConfig>,
|
||||
clickIntents: SendClickIntents,
|
||||
isMaxButtonEnabled: Boolean,
|
||||
isSegmentedButtonsEnabled: Boolean,
|
||||
) {
|
||||
item(
|
||||
|
|
@ -61,7 +60,6 @@ internal fun LazyListScope.buttons(
|
|||
}
|
||||
SecondaryButton(
|
||||
text = stringResource(R.string.send_max_amount),
|
||||
enabled = isMaxButtonEnabled,
|
||||
onClick = {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
clickIntents.onMaxValueClick()
|
||||
|
|
|
|||
|
|
@ -22,11 +22,10 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.rememberDecimalFormat
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.job
|
||||
|
||||
@Composable
|
||||
internal fun AmountField(sendField: SendTextField.AmountField, isEnabled: Boolean, appCurrencyCode: String) {
|
||||
internal fun AmountField(sendField: SendTextField.AmountField, appCurrencyCode: String) {
|
||||
val decimalFormat = rememberDecimalFormat()
|
||||
val isFiatValue = sendField.isFiatValue
|
||||
val currencyCode = if (isFiatValue) appCurrencyCode else null
|
||||
|
|
@ -36,15 +35,6 @@ internal fun AmountField(sendField: SendTextField.AmountField, isEnabled: Boolea
|
|||
sendField.cryptoAmount to sendField.value
|
||||
}
|
||||
val requester = remember { FocusRequester() }
|
||||
var isEnabledProxy by remember { mutableStateOf(isEnabled) }
|
||||
|
||||
// Fix animation from amount screen to summary screen ([REDACTED_TASK_KEY])
|
||||
LaunchedEffect(key1 = isEnabled) {
|
||||
if (isEnabled) {
|
||||
delay(timeMillis = 700)
|
||||
}
|
||||
isEnabledProxy = isEnabled
|
||||
}
|
||||
|
||||
AmountTextField(
|
||||
value = primaryValue,
|
||||
|
|
@ -62,7 +52,6 @@ internal fun AmountField(sendField: SendTextField.AmountField, isEnabled: Boolea
|
|||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
),
|
||||
isEnabled = isEnabledProxy,
|
||||
isAutoResize = true,
|
||||
modifier = Modifier
|
||||
.focusRequester(requester)
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ internal fun LazyListScope.amountField(
|
|||
)
|
||||
AmountField(
|
||||
sendField = amountState.amountTextField,
|
||||
isEnabled = !amountState.isFeeLoading,
|
||||
appCurrencyCode = amountState.appCurrencyCode,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
import com.tangem.features.send.impl.presentation.state.SendStates
|
||||
import com.tangem.features.send.impl.presentation.state.previewdata.AmountStatePreviewData
|
||||
import com.tangem.features.send.impl.presentation.state.previewdata.SendClickIntentsStub
|
||||
import com.tangem.features.send.impl.presentation.ui.common.notifications
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
|
||||
@Composable
|
||||
|
|
@ -35,10 +34,8 @@ internal fun SendAmountContent(
|
|||
buttons(
|
||||
segmentedButtonConfig = amountState.segmentedButtonConfig,
|
||||
clickIntents = clickIntents,
|
||||
isMaxButtonEnabled = !amountState.isFeeLoading,
|
||||
isSegmentedButtonsEnabled = amountState.isSegmentedButtonsEnabled,
|
||||
)
|
||||
notifications(amountState.notifications)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,14 +39,12 @@ internal interface SendClickIntents {
|
|||
// endregion
|
||||
|
||||
// region Fee
|
||||
fun feeReload(isToNextState: Boolean = false)
|
||||
fun feeReload()
|
||||
|
||||
fun onFeeSelectorClick(feeType: FeeType)
|
||||
|
||||
fun onCustomFeeValueChange(index: Int, value: String)
|
||||
|
||||
fun onSubtractSelect()
|
||||
|
||||
fun onReadMoreClick()
|
||||
// endregion
|
||||
|
||||
|
|
|
|||
|
|
@ -157,10 +157,10 @@ internal class SendViewModel @Inject constructor(
|
|||
private val sendNotificationFactory = SendNotificationFactory(
|
||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||
coinCryptoCurrencyStatusProvider = Provider { coinCryptoCurrencyStatus },
|
||||
feePaidCryptoCurrencyStatusProvider = Provider { feeCryptoCurrencyStatus },
|
||||
currentStateProvider = Provider { uiState },
|
||||
userWalletProvider = Provider { userWallet },
|
||||
stateRouterProvider = Provider { stateRouter },
|
||||
isSubtractAvailableProvider = Provider { isAmountSubtractAvailable },
|
||||
currencyChecksRepository = currencyChecksRepository,
|
||||
clickIntents = this,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
|
|
@ -192,7 +192,6 @@ internal class SendViewModel @Inject constructor(
|
|||
private var qrScannerJobHolder = JobHolder()
|
||||
|
||||
private var sendIdleTimer = 0L
|
||||
private var feeIdleTimer = 0L
|
||||
|
||||
init {
|
||||
subscribeOnCurrencyStatusUpdates()
|
||||
|
|
@ -488,12 +487,7 @@ internal class SendViewModel @Inject constructor(
|
|||
if (onFeeNext()) return
|
||||
}
|
||||
SendUiStateType.Amount -> {
|
||||
if (uiState.feeState?.feeSelectorState is FeeSelectorState.Content) {
|
||||
if (onFeeCoverageAlert()) return
|
||||
} else {
|
||||
loadFee(isToNextState = true)
|
||||
return
|
||||
}
|
||||
loadFee()
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
|
@ -519,7 +513,6 @@ internal class SendViewModel @Inject constructor(
|
|||
innerRouter.openTokenDetails(userWalletId, currency)
|
||||
|
||||
private fun onFeeNext(): Boolean {
|
||||
if (onFeeCoverageAlert()) return true
|
||||
if (checkIfFeeTooLow(uiState)) {
|
||||
uiState = eventStateFactory.getFeeTooLowAlert(
|
||||
onConsume = { uiState = eventStateFactory.onConsumeEventState() },
|
||||
|
|
@ -538,19 +531,6 @@ internal class SendViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun onFeeCoverageAlert(): Boolean {
|
||||
val isFeeCoverage = checkFeeCoverage(uiState, cryptoCurrencyStatus)
|
||||
return if (isAmountSubtractAvailable && isFeeCoverage) {
|
||||
uiState = eventStateFactory.getFeeCoverageAlert(
|
||||
onConsume = { uiState = eventStateFactory.onConsumeEventState() },
|
||||
)
|
||||
true
|
||||
} else {
|
||||
analyticsEventHandler.send(SendAnalyticEvents.SubtractFromAmount(false))
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelFeeRequest() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
feeJobHolder.cancel()
|
||||
|
|
@ -652,7 +632,7 @@ internal class SendViewModel @Inject constructor(
|
|||
// endregion
|
||||
|
||||
// region fee
|
||||
override fun feeReload(isToNextState: Boolean) = loadFee(isToNextState = isToNextState)
|
||||
override fun feeReload() = loadFee()
|
||||
|
||||
override fun onFeeSelectorClick(feeType: FeeType) {
|
||||
uiState = feeStateFactory.onFeeSelectedState(feeType)
|
||||
|
|
@ -667,12 +647,6 @@ internal class SendViewModel @Inject constructor(
|
|||
updateFeeNotifications()
|
||||
}
|
||||
|
||||
override fun onSubtractSelect() {
|
||||
uiState = stateFactory.onSubtractSelect(isAmountSubtractAvailable)
|
||||
stateRouter.showSend()
|
||||
analyticsEventHandler.send(SendAnalyticEvents.SubtractFromAmount(true))
|
||||
}
|
||||
|
||||
override fun onReadMoreClick() {
|
||||
val locale = if (Locale.getDefault().language == RU_LOCALE) RU_LOCALE else EN_LOCALE
|
||||
val url = buildString {
|
||||
|
|
@ -683,10 +657,7 @@ internal class SendViewModel @Inject constructor(
|
|||
innerRouter.openUrl(url)
|
||||
}
|
||||
|
||||
private fun loadFee(isToNextState: Boolean = false) {
|
||||
// debouncing fee request
|
||||
if (SystemClock.elapsedRealtime() - feeIdleTimer < FEE_UPDATE_DELAY) return
|
||||
|
||||
private fun loadFee() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
val isShowStatus = uiState.feeState?.fee == null
|
||||
if (isShowStatus) {
|
||||
|
|
@ -694,36 +665,25 @@ internal class SendViewModel @Inject constructor(
|
|||
}
|
||||
val result = callFeeUseCase()?.fold(
|
||||
ifRight = {
|
||||
feeIdleTimer = SystemClock.elapsedRealtime()
|
||||
uiState = feeStateFactory.onFeeOnLoadedState(it)
|
||||
if (isToNextState && !onFeeCoverageAlert()) {
|
||||
stateRouter.showSend()
|
||||
}
|
||||
},
|
||||
ifLeft = {
|
||||
onFeeLoadFailed(isShowStatus, isToNextState)
|
||||
onFeeLoadFailed(isShowStatus)
|
||||
},
|
||||
)
|
||||
if (result == null) {
|
||||
onFeeLoadFailed(isShowStatus, isToNextState)
|
||||
onFeeLoadFailed(isShowStatus)
|
||||
}
|
||||
updateNotifications()
|
||||
updateFeeNotifications()
|
||||
}.saveIn(feeJobHolder)
|
||||
.invokeOnCompletion {
|
||||
uiState = amountStateFactory.getOnAmountFeeLoadingCancel()
|
||||
// todo
|
||||
}
|
||||
}
|
||||
|
||||
private fun onFeeLoadFailed(isShowStatus: Boolean, isToNextState: Boolean) {
|
||||
when {
|
||||
isToNextState -> {
|
||||
uiState = eventStateFactory.getFeeUnreachableErrorState {
|
||||
uiState = eventStateFactory.onConsumeEventState()
|
||||
}
|
||||
}
|
||||
isShowStatus -> uiState = feeStateFactory.onFeeOnErrorState()
|
||||
}
|
||||
private fun onFeeLoadFailed(isShowStatus: Boolean) {
|
||||
if (isShowStatus) uiState = feeStateFactory.onFeeOnErrorState()
|
||||
}
|
||||
|
||||
private suspend fun checkIfSubtractAvailable() {
|
||||
|
|
@ -757,7 +717,6 @@ internal class SendViewModel @Inject constructor(
|
|||
verifyAndSendTransaction()
|
||||
} else {
|
||||
onCheckFeeUpdate()
|
||||
feeIdleTimer = SystemClock.elapsedRealtime()
|
||||
sendIdleTimer = SystemClock.elapsedRealtime()
|
||||
}
|
||||
}
|
||||
|
|
@ -798,7 +757,7 @@ internal class SendViewModel @Inject constructor(
|
|||
override fun onAmountReduceClick(reducedAmount: BigDecimal, clazz: Class<out SendNotification>) {
|
||||
uiState = amountStateFactory.getOnAmountValueChange(reducedAmount.parseBigDecimal(cryptoCurrency.decimals))
|
||||
uiState = sendNotificationFactory.dismissNotificationState(clazz)
|
||||
updateNotifications()
|
||||
feeReload()
|
||||
}
|
||||
|
||||
override fun onNotificationCancel(clazz: Class<out SendNotification>) {
|
||||
|
|
@ -811,10 +770,18 @@ internal class SendViewModel @Inject constructor(
|
|||
val fee = feeState.fee ?: return
|
||||
val memo = uiState.recipientState?.memoTextField?.value
|
||||
val amountValue = uiState.amountState?.amountTextField?.cryptoAmount?.value ?: return
|
||||
val feeValue = fee.amount.value ?: return
|
||||
|
||||
val receivingAmount = checkAndCalculateSubtractedAmount(
|
||||
isAmountSubtractAvailable = isAmountSubtractAvailable,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
amountValue = amountValue,
|
||||
feeValue = feeValue,
|
||||
)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
createTransactionUseCase(
|
||||
amount = amountValue.convertToAmount(cryptoCurrency),
|
||||
amount = receivingAmount.convertToAmount(cryptoCurrency),
|
||||
fee = fee,
|
||||
memo = memo,
|
||||
destination = recipient,
|
||||
|
|
@ -927,7 +894,6 @@ internal class SendViewModel @Inject constructor(
|
|||
|
||||
private companion object {
|
||||
const val CHECK_FEE_UPDATE_DELAY = 60_000L
|
||||
const val FEE_UPDATE_DELAY = 10_000L
|
||||
const val BALANCE_UPDATE_DELAY = 10_000L
|
||||
|
||||
const val RU_LOCALE = "ru"
|
||||
|
|
|
|||
|
|
@ -33,8 +33,15 @@ object BlockchainUtils {
|
|||
return blockchain == Blockchain.Bitcoin || blockchain == Blockchain.BitcoinTestnet
|
||||
}
|
||||
|
||||
/** If current [networkId] is Dogecoin */
|
||||
fun isDogecoin(networkId: String): Boolean {
|
||||
val blockchain = Blockchain.fromId(networkId)
|
||||
return blockchain == Blockchain.Dogecoin
|
||||
}
|
||||
|
||||
/** If current [networkId] is Tezos */
|
||||
fun isTezos(networkId: String): Boolean {
|
||||
val blockchain = Blockchain.fromId(networkId)
|
||||
return blockchain == Blockchain.Tezos
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue