From a8185c24985bb0461618cf1598ba9ff75c7bf0c0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 13 Sep 2024 20:56:48 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../field/AmountFieldChangeTransformer.kt | 4 +- .../converters/field/AmountFieldConverter.kt | 4 +- .../amountScreen/models/AmountFieldModel.kt | 1 + .../preview/AmountStatePreviewData.kt | 1 + .../common/ui/amountScreen/ui/AmountField.kt | 21 +++- core/res/src/main/res/values-de/strings.xml | 25 ++-- core/res/src/main/res/values-fr/strings.xml | 2 +- core/res/src/main/res/values-ja/strings.xml | 13 +++ core/res/src/main/res/values-ru/strings.xml | 4 + .../src/main/res/values-uk-rUA/strings.xml | 15 ++- core/res/src/main/res/values/strings.xml | 8 +- .../amount/AmountChangeStateTransformer.kt | 14 +-- .../amount/AmountMaxValueStateTransformer.kt | 17 +-- .../AmountRequirementStateTransformer.kt | 109 +++++++++++++----- .../amount/AmountRoundToIntegerTransformer.kt | 40 +++++++ .../state/utils/FeeCalculation.kt | 13 ++- .../viewmodel/StakingViewModel.kt | 12 +- 17 files changed, 228 insertions(+), 75 deletions(-) create mode 100644 features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRoundToIntegerTransformer.kt diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldChangeTransformer.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldChangeTransformer.kt index 528d288023..8de99b1fc5 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldChangeTransformer.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldChangeTransformer.kt @@ -9,6 +9,7 @@ import com.tangem.common.ui.amountScreen.utils.checkExceedBalance import com.tangem.common.ui.amountScreen.utils.getCryptoValue import com.tangem.common.ui.amountScreen.utils.getFiatValue import com.tangem.common.ui.amountScreen.utils.getKeyboardAction +import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.utils.parseToBigDecimal import com.tangem.domain.tokens.model.CryptoCurrencyStatus @@ -62,7 +63,8 @@ class AmountFieldChangeTransformer( value = cryptoValue, fiatValue = fiatValue, isError = isExceedBalance, - error = resourceReference(R.string.send_validation_amount_exceeds_balance), + error = resourceReference(R.string.send_validation_amount_exceeds_balance).takeIf { isExceedBalance } + ?: TextReference.EMPTY, cryptoAmount = amountTextField.cryptoAmount.copy(value = decimalCryptoValue), fiatAmount = amountTextField.fiatAmount.copy(value = decimalFiatValue), keyboardOptions = KeyboardOptions( diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldConverter.kt index bfe5259127..d460c0ca5d 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldConverter.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType -import com.tangem.common.ui.R import com.tangem.common.ui.amountScreen.AmountScreenClickIntents import com.tangem.common.ui.amountScreen.models.AmountFieldModel import com.tangem.core.ui.extensions.TextReference @@ -62,7 +61,8 @@ class AmountFieldConverter( cryptoAmount = cryptoAmount, fiatAmount = getAppCurrencyAmount(fiatDecimal, appCurrencyProvider()), isError = false, - error = TextReference.Res(R.string.send_validation_amount_exceeds_balance), + isWarning = false, + error = TextReference.EMPTY, isFiatUnavailable = fiatRate == null, isValuePasted = false, onValuePastedTriggerDismiss = clickIntents::onAmountPasteTriggerDismiss, diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/models/AmountFieldModel.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/models/AmountFieldModel.kt index 572239504d..995852df94 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/models/AmountFieldModel.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/models/AmountFieldModel.kt @@ -35,5 +35,6 @@ data class AmountFieldModel( val isValuePasted: Boolean, val onValuePastedTriggerDismiss: () -> Unit, val isError: Boolean, + val isWarning: Boolean, val error: TextReference, ) \ No newline at end of file diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/preview/AmountStatePreviewData.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/preview/AmountStatePreviewData.kt index 91951b4220..a622f752c9 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/preview/AmountStatePreviewData.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/preview/AmountStatePreviewData.kt @@ -53,6 +53,7 @@ object AmountStatePreviewData { fiatValue = "123.123", isFiatUnavailable = false, isError = false, + isWarning = false, error = TextReference.EMPTY, isValuePasted = false, onValuePastedTriggerDismiss = {}, diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountField.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountField.kt index f190cea1db..d8347d67af 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountField.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountField.kt @@ -4,7 +4,10 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateContentSize import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeightIn import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -112,6 +115,7 @@ private fun AmountSecondary(amountField: AmountFieldModel, appCurrencyCode: Stri ) AmountFieldError( isError = amountField.isError, + isWarning = amountField.isWarning, error = amountField.error, modifier = Modifier .align(BottomCenter) @@ -124,17 +128,24 @@ private fun AmountSecondary(amountField: AmountFieldModel, appCurrencyCode: Stri } @Composable -private fun AmountFieldError(isError: Boolean, error: TextReference, modifier: Modifier = Modifier) { +private fun AmountFieldError( + isError: Boolean, + isWarning: Boolean, + error: TextReference, + modifier: Modifier = Modifier, +) { AnimatedVisibility( - visible = isError, + visible = isError || isWarning, enter = fadeIn(), exit = fadeOut(), modifier = modifier, ) { + val errorText = remember(this) { error } + val color = if (isError) TangemTheme.colors.text.warning else TangemTheme.colors.text.attention Text( - text = error.resolveReference(), + text = errorText.resolveReference(), style = TangemTheme.typography.caption2, - color = TangemTheme.colors.text.warning, + color = color, textAlign = TextAlign.Center, ) } diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index eee487a5c1..ef2d858a71 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -297,6 +297,7 @@ Unbegrenzt Karte bestellen Karte scannen + Diese Information ist KI generiert Um den Zugangscode zu ändern, halte die Karte wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs. Um den Passcode zu ändern, halte die Karte wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs. Um die Wallet zu erstellen, halte die Karte wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs. @@ -350,6 +351,7 @@ Mein Portfolio Markt Um Adressen für ausgewählte Netzwerke zu generieren, musst du eine Tangem-Karte scannen + Um Token hinzuzufügen, rufe dies auf oder tippe auf die Suchleiste Die Daten dieses Abschnitts stammen aus den folgenden Netzwerken: %s Die Daten konnten nicht geladen werden... Keine Daten @@ -388,7 +390,6 @@ Vollständig verwässerte Bewertung Der theoretische Gesamtwert einer Kryptowährung, wenn alle Coins, die existieren könnten, im Umlauf sind, einschließlich derjenigen, die derzeit nicht im Umlauf sind Entstehungsdatum - Leer Hoch Inhaber/ Halter Die Änderung der Anzahl der Token-Inhaber innerhalb eines bestimmten Zeitraums @@ -399,8 +400,8 @@ Liquiditätsindex Leer Niedrig - Marktkapitalisierung - Das MCap eines Assets, errechnet sich durch Multiplikation des aktuellen Preises mit der Gesamtzahl der im Umlauf befindlichen Coins + MarketCap + Der Gesamtmarktwert einer Kryptowährung, berechnet durch Multiplikation des aktuellen Preises des Coins mit der Gesamtzahl der im Umlauf befindlichen Coins. Marktbewertung Position im Krypto-Rating zwischen allen Coins basierend auf der Marktkapitalisierung Maximale Versorgung @@ -410,7 +411,6 @@ Preisleistung Aufbewahrungsort Sicherheitsbewertung - Leer Soziales Gesamtangebot Die maximale Anzahl von Coins oder Tokens, die jemals für eine bestimmte Kryptowährung existieren können @@ -462,12 +462,12 @@ Backups anlegen Lese mehr über die Seed-Phrase - leer + Schreibe diese %d-Wörter in der unten angegebenen Reihenfolge auf und bewahre sie an einem sicheren und geheimen Ort auf. Deine Seed-Phrase - leer + %d Wörter Um deine Wallets zu importieren, gib bitte deine Seed-Phrase in das folgende Feld ein @@ -637,8 +637,8 @@ Du sendest **%1$s** inklusive der Netzwerkgebühr %2$s Du sendest **%1$s** und %2$s Du sendest **%1$s** - Die Netzwerkgebühr wird durch die Nutzung von %1$s %2$s gedeckt. - Die Netzwerkgebühr wird durch das Ausgeben von %1$s %2$s reduziert. + Die Netzwerkgebühr wird durch die Nutzung von %1$s Energieträgern gedeckt. + Die Netzwerkgebühr wird durch das Ausgeben von %1$s Energieträgern reduziert. inklusive einer Netzgebühr von %1$s Die Transaktion wurde erfolgreich signiert und an den Blockchain-Knoten gesendet. Die Walletbilanz wird aktualisiert %1$s ist ein Vermögenswert im Tron-Netzwerk. Um die Gebühr zu berechnen und eine Transaktion durchzuführen, musst du etwas Tron (TRX) auf deinem Konto einzahlen. @@ -648,6 +648,7 @@ Hiermit wird die Wallet aus der Anwendung entfernt. Die Wallet selbst kann wieder hinzugefügt werden. Name Die Anzahl der zu stakenden Krypros muss mindesten %s betragen + Der Stakingbetrag wird aufgrund der Netzwerkregeln auf %1$s TRX aufgerundet. Nicht gestakte beanspruche Jährliche prozentuale Rendite Die jährliche prozentuale Rendite, die du durch die Teilnahme am Staking erzielen kannst. @@ -675,17 +676,23 @@ Gesperrt Migrieren Natives Staking - Verdiente Prämien werden direkt an Deine Adresse gesendet. Sobald Du diese eingefordert hast, stehen Dir die Mittel zur Verfügung. + Verdiente Belohnungen werden an deine Wallet gesendet und stehen sofort zur Verwendung zur Verfügung + Sicher staken und tägliche Belohnungen verdienen. + Sicher staken und stündliche Belohnungen verdienen. + Sicher staken und monatliche Belohnungen verdienen. Mit dem Staking kannst Du %1$s verdienen. Deine Staking-Belohnungen erhältst Du jeden tag. Mit dem Staking kannst Du %1$s verdienen. Deine Staking-Belohnungen erhältst Du jede Stunde. Mit dem Staking kannst Du %1$s verdienen. Deine Staking-Belohnungen erhältst Du jeden Monat. Mit dem Staking kannst Du %1$s verdienen. Deine Staking-Belohnungen erhältst Du jede Woche. + Sicher staken und wöchentliche Belohnungen verdienen. Verdiene Staking-Belohnungen Beim Staking im %1$s -Netzwerk mit einem neuen Validator werden alle zuvor eingesetzten Kryptos automatisch an diesen Validator übertragen Reinvestiert Deine verdienten Prämien in Deinen Einsatzbetrag und erhöht so den potenziellen Gewinn. + Entsperre dein Geld, um es aus dem Staking-Prozess abzuheben. Das Freischalten nimmt %s. Nach Ablauf der 21-tägigen Bindungsfrist kannst Du über Dein Guthaben verfügen. Die Prämie wird zusammen mit dem ungestaketen Guthaben abgehoben. Deine Assets steht Dir nach Ablauf der Frist für die Aufhebung der Bindung %s zur Verfügung. Du kannst Dein Guthaben jetzt abheben. Es steht Dir sofort zur Verfügung. + Wenn du im Tron-Netzwerk mit einem neuen Validator stakest, werden alle zuvor eingesetzten Assets automatisch an diesen Validator übertragen. Vorbereitung Bereit zum Abheben Erneut binden diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index ca8c7cf4f2..be874b7bdb 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -363,7 +363,7 @@ 24 heures 3 mois 6 mois - 7 jours + 7j Tout Acheteurs expérimentés Évaluation diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 3d5a19d86e..9c10dc67c2 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -295,6 +295,7 @@ 無制限 カードを注文 スキャン + この情報はAIによって生成されました アクセスコードを変更するには、上図のようにカードをタップし、操作が終了するまで取り外さないでください。 パスコードを変更するには、上記のようにカードをタップし、操作が終了するまで取り外さないでください。 ウォレットを作成するには、上記のようにカードをタップし、操作が終了するまで取り外さないでください。 @@ -624,6 +625,10 @@ %sを送金する **%1$s** を送金する (ネットワーク手数料%2$sを含む) **%1$s** と %2$s を送金しています。 + ** %1$s ** を送信しています + ネットワーク手数料は%1$sエネルギーを使用してカバーされます + %1$sを使用するとネットワーク手数料が減額されます + ネットワーク手数料%1$sを含む 取引は正常に署名され、ブロックチェーンノードに送信されました。ウォレットの残高はしばらくして更新されます。 %1$sはTronネットワークのアセットです。手数料を計算して取引を行うには、アカウントにTron(TRX)を入金する必要があります。 取引が送信されました @@ -660,14 +665,22 @@ 移行 ネイティブステーキング 獲得した報酬はあなたのアドレスに直接送られ、すぐ使用可能です。 + 安全にステーキングして、報酬を毎日獲得しましょう + 安全にステーキングして、報酬を毎時間獲得しましょう + 安全にステーキングして、報酬を毎月獲得しましょう ステーキングにより%1$sを獲得できます。ステーキング報酬は毎日受け取れます。 ステーキングにより%1$sを獲得できます。ステーキング報酬は毎時間受け取れます。 ステーキングにより%1$sを獲得できます。ステーキング報酬は毎月受け取れます。 ステーキングにより%1$sを獲得できます。ステーキング報酬は毎週受け取れます。 + 安全にステーキングして、報酬を毎週獲得しましょう ステーキング報酬を獲得 + 新しいバリデーターで%1$sネットワークにステーキングすると、以前にステーキングされた資金はすべてこのバリデーターに自動的に転送されます。 獲得した報酬をステーキングに再投資し、潜在的な収益を増やします。 + 資金をステーキングから引き出すには、ロックを解除してください。ロック解除には%sかかります。 + 資金は、21日間のロック解除期間後に使用可能になります。報酬は、ロック解除後の資金とともに引き出されます。 %sのステーキング解除期間後、資金はすぐ利用可能となります。 資金を引き出すことができ、すぐに使用できます + Tronネットワークに新しいバリデーターでステーキングすると、以前にステーキングされた資金はすべてこのバリデーターに自動的に転送されます。 準備中 引き出し準備完了 再結束 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 567496ce4d..ce509bfb41 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -177,6 +177,7 @@ Адрес контракта Адрес контракта некорректен Пожалуйста, выберите сеть + Токен уже существует Десятичное число должно быть действительным целым числом, до %d Своя деривация Например m/00\'/0000\'/0\'/0/0 @@ -642,6 +643,8 @@ Отправка %s Вы отправляете **%1$s**, включая комиссию сети %2$s Вы отправляете **%1$s** и %2$s + Вы отправляете **%1$s** + включая комиссию сети в размере %1$s Транзакция успешно подписана и отправлена в блокчейн. Баланс будет обновлен через некоторое время %1$s — это монета в сети Tron. Чтобы рассчитать комиссию и совершить транзакцию, вам необходимо внести немного Tron (TRX) на свой адрес. Транзакция отправлена @@ -682,6 +685,7 @@ Стейкинг дает возможность вам получать %1$s. Награда будет зачисляться каждый месяц. Стейкинг дает возможность вам получать %1$s. Награда будет зачисляться каждую неделю. Получите награду за стейкинг + Разблокируйте свои средства, чтобы вывести их из стейкинга. Разблокировка займёт %s. Ваши средства будут доступны после %s периода отзыва. Вы можете вывести свои средства из стейкинга, они будут доступны для использования незамедлительно. Сменить валидатора diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index f0517e2467..9ef0e3fb24 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -301,6 +301,7 @@ Необмежено Купити Сканувати + Ця інформація була створена за допомогою ШІ Щоб змінити код доступу, прикладіть картку, як показано вище, і не прибирайте її до закінчення операції Щоб змінити пароль, прикладіть картку, як показано вище, і не прибирайте її до закінчення операції Щоб створити гаманець, прикладіть картку, як показано вище, і не прибирайте її до завершення операції @@ -371,7 +372,7 @@ 24 год. 3 міс. 6 міс. - 7 днів + Увесь Досвідчені покупці За рейтингом @@ -648,6 +649,10 @@ Надіслати %s Ви надсилаєте **%1$s**, включно з комісію мережі %2$s Ви надсилаєте **%1$s** і %2$s + Ви надсилаєте **%1$s** + комісія мережі буде покрита, використовуючи %1$s енергію + комісія мережі буде зменшена, витрачаючи %1$s + включно з комісією мережі %1$s Транзакція успішно підписана і відправлена до блокчейну. Баланс гаманця буде оновлено через деякий час %1$s — це монета у мережі Tron. Щоб розрахувати комісію та здійснити транзакцію, вам необхідно внести певну кількість Tron (TRX) на свій рахунок. Трансакцію надіслано @@ -684,14 +689,22 @@ Перемістити Нативний стейкінг Зароблені винагороди будуть надіслані на ваш гаманець і доступні для використання відразу + Стейкайте безпечно та почніть отримувати винагороди щоденно + Стейкайте безпечно та почніть отримувати винагороди щогодини + Стейкайте безпечно та почніть отримувати винагороди щомісяця Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються щодня. Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються кожну годину. Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються щомісяця. Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються щотиждня. + Стейкайте безпечно та почніть отримувати винагороди щотижня Отримуйте винагороду за стейкінг + Стейкінг в мережі %1$s з новим валідатором автоматично переведе всі раніше застейкані кошти до цього валідатора Реінвестуйте зароблені винагороди у суму стейкінгу, щоб збільшити потенційний прибуток. + Розблокуйте свої кошти, щоб вивести їх зі стейкінгу. Розблокування займе %s. + Ваші кошти будуть доступні для використання після закінчення 21-денного періоду розблокування. Винагорода буде отримана разом з вашими незастейканими коштами. Ваші кошти будуть доступні після %s періоду розблокування. Тепер ви можете вивести свої кошти, вони будуть доступні для використання відразу + Стейкінг в мережі Tron з новим валідатором автоматично переведе всі раніше застейкані кошти до цього валідатора Підготовка Готова до виведення Зʼєднати ще раз diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 03805641a9..9582c22d5f 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -175,7 +175,7 @@ Contract address Contract address is invalid Please select the network - This token has already been added to the list + This token has already been added to the list Token already exists Decimal must be a valid integer, up to %d Custom derivation @@ -351,6 +351,7 @@ My portfolio Market To generate addresses for selected networks, you must scan your Tangem Wallet card + To add tokens pull this up or tap the search bar This section’s data is sourced from the following networks: %s Unable to load the data… No data @@ -634,8 +635,8 @@ You are sending **%1$s** including a network fee of %2$s You are sending **%1$s** and %2$s You are sending **%1$s** - network fee will be covered by using %1$s %2$s - network fee will be reduced by spending %1$s %2$s + network fee will be covered by using %1$s energy + network fee will be reduced by spending %1$s energy including a network fee of %1$s Transaction has been successfully signed and sent to the blockchain node. Wallet balance will be updated in a while %1$s is an asset in the Tron network. To calculate the fee and make a transaction you need to deposit some Tron (TRX) in your account. @@ -645,6 +646,7 @@ This will remove the wallet from the application. The wallet itself can be added again. Name The amount to stake must be at least %s + Staking amount will be rounded to %1$s TRX due to network rules. Claim unstaked Annual percentage rate The annual percentage return you can earn from participating in staking. diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountChangeStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountChangeStateTransformer.kt index 098e959f7c..f91d878456 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountChangeStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountChangeStateTransformer.kt @@ -9,15 +9,9 @@ import com.tangem.utils.transformer.Transformer internal class AmountChangeStateTransformer( private val cryptoCurrencyStatus: CryptoCurrencyStatus, private val value: String, - yield: Yield, + private val yield: Yield, ) : Transformer { - private val amountRequirementStateTransformer = AmountRequirementStateTransformer( - cryptoCurrencyStatus, - yield, - value, - ) - override fun transform(prevState: StakingUiState): StakingUiState { val updatedAmountState = AmountFieldChangeTransformer( cryptoCurrencyStatus, @@ -25,7 +19,11 @@ internal class AmountChangeStateTransformer( ).transform(prevState.amountState) return prevState.copy( - amountState = amountRequirementStateTransformer.transform(updatedAmountState), + amountState = AmountRequirementStateTransformer( + cryptoCurrencyStatus = cryptoCurrencyStatus, + yield = yield, + actionType = prevState.actionType, + ).transform(updatedAmountState), ) } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountMaxValueStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountMaxValueStateTransformer.kt index 6314597d0d..088528794d 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountMaxValueStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountMaxValueStateTransformer.kt @@ -1,7 +1,6 @@ package com.tangem.features.staking.impl.presentation.state.transformers.amount import com.tangem.common.ui.amountScreen.converters.field.AmountFieldMaxAmountTransformer -import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.staking.impl.presentation.state.StakingUiState @@ -9,21 +8,17 @@ import com.tangem.utils.transformer.Transformer internal class AmountMaxValueStateTransformer( private val cryptoCurrencyStatus: CryptoCurrencyStatus, - yield: Yield, + private val yield: Yield, ) : Transformer { - private val amountRequirementStateTransformer = AmountRequirementStateTransformer( - cryptoCurrencyStatus = cryptoCurrencyStatus, - yield = yield, - value = cryptoCurrencyStatus.value.amount - ?.parseBigDecimal(cryptoCurrencyStatus.currency.decimals) - .orEmpty(), - ) - override fun transform(prevState: StakingUiState): StakingUiState { val updatedAmountState = AmountFieldMaxAmountTransformer(cryptoCurrencyStatus).transform(prevState.amountState) return prevState.copy( - amountState = amountRequirementStateTransformer.transform(updatedAmountState), + amountState = AmountRequirementStateTransformer( + cryptoCurrencyStatus = cryptoCurrencyStatus, + yield = yield, + actionType = prevState.actionType, + ).transform(updatedAmountState), ) } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRequirementStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRequirementStateTransformer.kt index 59d4adfaf7..d669d5a7e9 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRequirementStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRequirementStateTransformer.kt @@ -3,60 +3,91 @@ package com.tangem.features.staking.impl.presentation.state.transformers.amount import androidx.compose.ui.text.input.ImeAction import com.tangem.common.extensions.isZero import com.tangem.common.ui.amountScreen.models.AmountState +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.isNullOrEmpty import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.utils.BigDecimalFormatter -import com.tangem.core.ui.utils.parseToBigDecimal +import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.domain.staking.model.stakekit.AddressArgument import com.tangem.domain.staking.model.stakekit.Yield +import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.staking.impl.R +import com.tangem.lib.crypto.BlockchainUtils.isTron import com.tangem.utils.transformer.Transformer +import java.math.BigDecimal +import java.math.RoundingMode internal class AmountRequirementStateTransformer( private val cryptoCurrencyStatus: CryptoCurrencyStatus, private val yield: Yield, - private val value: String, + private val actionType: StakingActionCommonType, ) : Transformer { override fun transform(prevState: AmountState): AmountState { val amountRequirements = yield.args.enter.args[Yield.Args.ArgType.AMOUNT] - return if (prevState !is AmountState.Data || amountRequirements == null) { - prevState - } else { - updateWithError(prevState, amountRequirements) - } - } - - private fun updateWithError(prevState: AmountState.Data, amountRequirements: AddressArgument): AmountState { - val isRequirementError = isRequirementError(prevState, amountRequirements) - return if (isRequirementError) { - prevState.copy( - isPrimaryButtonEnabled = false, - amountTextField = prevState.amountTextField.copy( - isError = true, - error = resourceReference( - R.string.staking_amount_requirement_error, - wrappedList( - BigDecimalFormatter.formatCryptoAmount( - amountRequirements.minimum, - cryptoCurrencyStatus.currency.symbol, - cryptoCurrencyStatus.currency.decimals, - ), - ), - ), - keyboardOptions = prevState.amountTextField.keyboardOptions.copy( - imeAction = ImeAction.None, - ), - ), + return if (prevState is AmountState.Data && amountRequirements != null) { + updateWithError( + prevState, + actionType, + amountRequirements, ) } else { prevState } } + private fun updateWithError( + amountState: AmountState.Data, + actionType: StakingActionCommonType, + amountRequirements: AddressArgument, + ): AmountState { + val isRequirementError = isRequirementError(amountState, amountRequirements) + val isIntegerOnlyError = isIntegerOnlyError(amountState, actionType) + + val cryptoAmount = amountState.amountTextField.cryptoAmount + val roundedDownCrypto = cryptoAmount.value?.setScale(0, RoundingMode.DOWN) + val value = roundedDownCrypto?.parseBigDecimal(0).orEmpty() + + val errorText = when { + amountState.amountTextField.isError -> amountState.amountTextField.error + isRequirementError -> resourceReference( + R.string.staking_amount_requirement_error, + wrappedList( + BigDecimalFormatter.formatCryptoAmount( + amountRequirements.minimum, + cryptoCurrencyStatus.currency.symbol, + cryptoCurrencyStatus.currency.decimals, + ), + ), + ) + isIntegerOnlyError -> resourceReference( + R.string.staking_amount_tron_integer_error, + wrappedList(value), + ) + else -> TextReference.EMPTY + } + val isError = amountState.amountTextField.isError || isRequirementError + return if (!errorText.isNullOrEmpty()) { + amountState.copy( + isPrimaryButtonEnabled = !isError, + amountTextField = amountState.amountTextField.copy( + isError = isError, + isWarning = isIntegerOnlyError, + error = errorText, + keyboardOptions = amountState.amountTextField.keyboardOptions.copy( + imeAction = ImeAction.None, + ), + ), + ) + } else { + amountState + } + } + private fun isRequirementError(prevState: AmountState.Data, amountRequirements: AddressArgument): Boolean { - val amountDecimal = value.parseToBigDecimal(cryptoCurrencyStatus.currency.decimals) + val amountDecimal = prevState.amountTextField.cryptoAmount.value ?: return false val isAlreadyErrorState = prevState.amountTextField.isError val isAmountRequired = amountRequirements.required @@ -67,4 +98,20 @@ internal class AmountRequirementStateTransformer( return !isAmountZero && isAmountRequired && isExceedsRequirements && !isAlreadyErrorState } + + private fun isIntegerOnlyError(amountState: AmountState.Data, actionType: StakingActionCommonType): Boolean { + val cryptoAmountValue = amountState.amountTextField.cryptoAmount.value ?: return false + + val isEnter = actionType == StakingActionCommonType.ENTER + val isTron = isTron(cryptoCurrencyStatus.currency.network.id.value) + + val isIntegerOnly = cryptoAmountValue.isZero() || cryptoAmountValue.remainder(BigDecimal.ONE).isZero() + + return isEnter && isTron && !isIntegerOnly + } + + data class Data( + val amountState: AmountState, + val actionType: StakingActionCommonType, + ) } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRoundToIntegerTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRoundToIntegerTransformer.kt new file mode 100644 index 0000000000..d2b2e7fe50 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/amount/AmountRoundToIntegerTransformer.kt @@ -0,0 +1,40 @@ +package com.tangem.features.staking.impl.presentation.state.transformers.amount + +import com.tangem.common.ui.amountScreen.models.AmountState +import com.tangem.core.ui.utils.parseBigDecimal +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.features.staking.impl.presentation.state.StakingUiState +import com.tangem.utils.transformer.Transformer +import java.math.RoundingMode + +internal class AmountRoundToIntegerTransformer( + private val cryptoCurrencyStatus: CryptoCurrencyStatus, +) : Transformer { + override fun transform(prevState: StakingUiState): StakingUiState { + val amountState = prevState.amountState as? AmountState.Data ?: return prevState + val amountTextField = amountState.amountTextField + if (amountTextField.value.isEmpty()) return prevState + + val cryptoAmount = amountState.amountTextField.cryptoAmount + val fiatAmount = amountState.amountTextField.fiatAmount + val fiatDecimals = fiatAmount.decimals + + val roundedDownCrypto = cryptoAmount.value?.setScale(0, RoundingMode.DOWN) + val roundedDownFiat = roundedDownCrypto?.multiply(cryptoCurrencyStatus.value.fiatRate) + + val value = roundedDownCrypto?.parseBigDecimal(0).orEmpty() + val fiatValue = roundedDownFiat?.parseBigDecimal(fiatDecimals, RoundingMode.HALF_UP).orEmpty() + + return prevState.copy( + amountState = amountState.copy( + amountTextField = amountState.amountTextField.copy( + cryptoAmount = cryptoAmount.copy(value = roundedDownCrypto), + fiatAmount = fiatAmount.copy(value = roundedDownFiat), + value = value, + fiatValue = fiatValue, + isWarning = false, + ), + ), + ) + } +} \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/FeeCalculation.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/FeeCalculation.kt index 21e95ed465..0f1857c60b 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/FeeCalculation.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/FeeCalculation.kt @@ -1,7 +1,10 @@ package com.tangem.features.staking.impl.presentation.state.utils import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.lib.crypto.BlockchainUtils.isTron import java.math.BigDecimal +import java.math.MathContext +import java.math.RoundingMode /** * Check and calculates subtracted amount @@ -14,15 +17,21 @@ internal fun checkAndCalculateSubtractedAmount( reduceAmountBy: BigDecimal, ): BigDecimal { val balance = cryptoCurrencyStatus.value.amount ?: return amountValue + val isTron = isTron(cryptoCurrencyStatus.currency.network.id.value) + val feeValueRounded = if (isTron) { + feeValue.round(MathContext(0, RoundingMode.UP)) + } else { + feeValue + } val isFeeCoverage = checkFeeCoverage( isSubtractAvailable = isAmountSubtractAvailable, balance = balance, amountValue = amountValue, - feeValue = feeValue, + feeValue = feeValueRounded, reduceAmountBy = reduceAmountBy, ) return if (isFeeCoverage) { - balance.minus(reduceAmountBy).minus(feeValue) + balance.minus(reduceAmountBy).minus(feeValueRounded) } else { amountValue } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt index 966e5d3693..b283511af9 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt @@ -197,7 +197,17 @@ internal class StakingViewModel @Inject constructor( stateController.update(SetConfirmationStateLoadingTransformer(yield, appCurrency)) onRefreshSwipe(isRefreshing = false) } - isAssentState() -> getFee(pendingAction) + isAssentState() -> { + getFee(pendingAction) + val amountState = value.amountState as? AmountState.Data + if (amountState?.amountTextField?.isWarning == true) { + stateController.update( + AmountRoundToIntegerTransformer( + cryptoCurrencyStatus = cryptoCurrencyStatus, + ), + ) + } + } } }