Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-13 20:56:48 +05:00
parent 7e3556f0df
commit a8185c2498
17 changed files with 228 additions and 75 deletions

View file

@ -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(

View file

@ -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,

View file

@ -35,5 +35,6 @@ data class AmountFieldModel(
val isValuePasted: Boolean,
val onValuePastedTriggerDismiss: () -> Unit,
val isError: Boolean,
val isWarning: Boolean,
val error: TextReference,
)

View file

@ -53,6 +53,7 @@ object AmountStatePreviewData {
fiatValue = "123.123",
isFiatUnavailable = false,
isError = false,
isWarning = false,
error = TextReference.EMPTY,
isValuePasted = false,
onValuePastedTriggerDismiss = {},

View file

@ -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,
)
}

View file

@ -297,6 +297,7 @@
<string name="give_permission_unlimited">Unbegrenzt</string>
<string name="home_button_order">Karte bestellen</string>
<string name="home_button_scan">Karte scannen</string>
<string name="information_generated_with_ai">Diese Information ist KI generiert</string>
<string name="initial_message_change_access_code_body">Um den Zugangscode zu ändern, halte die Karte wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs.</string>
<string name="initial_message_change_passcode_body">Um den Passcode zu ändern, halte die Karte wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs.</string>
<string name="initial_message_create_wallet_body">Um die Wallet zu erstellen, halte die Karte wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs.</string>
@ -350,6 +351,7 @@
<string name="markets_common_my_portfolio">Mein Portfolio</string>
<string name="markets_common_title">Markt</string>
<string name="markets_generate_addresses_notification">Um Adressen für ausgewählte Netzwerke zu generieren, musst du eine Tangem-Karte scannen</string>
<string name="markets_hint">Um Token hinzuzufügen, rufe dies auf oder tippe auf die Suchleiste</string>
<string name="markets_insights_info_description_message">Die Daten dieses Abschnitts stammen aus den folgenden Netzwerken: %s</string>
<string name="markets_loading_error_title">Die Daten konnten nicht geladen werden...</string>
<string name="markets_loading_no_data_title">Keine Daten</string>
@ -388,7 +390,6 @@
<string name="markets_token_details_fully_diluted_valuation">Vollständig verwässerte Bewertung</string>
<string name="markets_token_details_fully_diluted_valuation_description">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</string>
<string name="markets_token_details_genesis_date">Entstehungsdatum</string>
<string name="markets_token_details_genesis_date_description">Leer</string>
<string name="markets_token_details_high">Hoch</string>
<string name="markets_token_details_holders">Inhaber/ Halter</string>
<string name="markets_token_details_holders_description">Die Änderung der Anzahl der Token-Inhaber innerhalb eines bestimmten Zeitraums</string>
@ -399,8 +400,8 @@
<string name="markets_token_details_liquidity_index">Liquiditätsindex</string>
<string name="markets_token_details_liquidity_index_description">Leer</string>
<string name="markets_token_details_low">Niedrig</string>
<string name="markets_token_details_market_capitalization">Marktkapitalisierung</string>
<string name="markets_token_details_market_capitalization_description">Das MCap eines Assets, errechnet sich durch Multiplikation des aktuellen Preises mit der Gesamtzahl der im Umlauf befindlichen Coins</string>
<string name="markets_token_details_market_capitalization">MarketCap</string>
<string name="markets_token_details_market_capitalization_description">Der Gesamtmarktwert einer Kryptowährung, berechnet durch Multiplikation des aktuellen Preises des Coins mit der Gesamtzahl der im Umlauf befindlichen Coins.</string>
<string name="markets_token_details_market_rating">Marktbewertung</string>
<string name="markets_token_details_market_rating_description">Position im Krypto-Rating zwischen allen Coins basierend auf der Marktkapitalisierung</string>
<string name="markets_token_details_max_supply">Maximale Versorgung</string>
@ -410,7 +411,6 @@
<string name="markets_token_details_price_performance">Preisleistung</string>
<string name="markets_token_details_repository">Aufbewahrungsort</string>
<string name="markets_token_details_security_score">Sicherheitsbewertung</string>
<string name="markets_token_details_security_score_description">Leer</string>
<string name="markets_token_details_social">Soziales</string>
<string name="markets_token_details_total_supply">Gesamtangebot</string>
<string name="markets_token_details_total_supply_description">Die maximale Anzahl von Coins oder Tokens, die jemals für eine bestimmte Kryptowährung existieren können</string>
@ -462,12 +462,12 @@
<string name="onboarding_navbar_title_creating_backup">Backups anlegen</string>
<string name="onboarding_seed_button_read_more">Lese mehr über die Seed-Phrase</string>
<plurals name="onboarding_seed_generate_message_words_count">
<item quantity="one">leer</item>
<item quantity="one"></item>
<item quantity="other">Schreibe diese %d-Wörter in der unten angegebenen Reihenfolge auf und bewahre sie an einem sicheren und geheimen Ort auf.</item>
</plurals>
<string name="onboarding_seed_generate_title">Deine Seed-Phrase</string>
<plurals name="onboarding_seed_generate_words_count">
<item quantity="one">leer</item>
<item quantity="one"></item>
<item quantity="other">%d Wörter</item>
</plurals>
<string name="onboarding_seed_import_message">Um deine Wallets zu importieren, gib bitte deine Seed-Phrase in das folgende Feld ein</string>
@ -637,8 +637,8 @@
<string name="send_summary_transaction_description">Du sendest **%1$s** inklusive der Netzwerkgebühr %2$s</string>
<string name="send_summary_transaction_description_no_fiat_fee">Du sendest **%1$s** und %2$s</string>
<string name="send_summary_transaction_description_prefix">Du sendest **%1$s**</string>
<string name="send_summary_transaction_description_suffix_fee_covered">Die Netzwerkgebühr wird durch die Nutzung von %1$s %2$s gedeckt.</string>
<string name="send_summary_transaction_description_suffix_fee_reduced">Die Netzwerkgebühr wird durch das Ausgeben von %1$s %2$s reduziert.</string>
<string name="send_summary_transaction_description_suffix_fee_covered">Die Netzwerkgebühr wird durch die Nutzung von %1$s Energieträgern gedeckt.</string>
<string name="send_summary_transaction_description_suffix_fee_reduced">Die Netzwerkgebühr wird durch das Ausgeben von %1$s Energieträgern reduziert.</string>
<string name="send_summary_transaction_description_suffix_including">inklusive einer Netzgebühr von %1$s</string>
<string name="send_transaction_success">Die Transaktion wurde erfolgreich signiert und an den Blockchain-Knoten gesendet. Die Walletbilanz wird aktualisiert</string>
<string name="send_tron_account_activation_error">%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.</string>
@ -648,6 +648,7 @@
<string name="settings_forget_wallet_footer">Hiermit wird die Wallet aus der Anwendung entfernt. Die Wallet selbst kann wieder hinzugefügt werden.</string>
<string name="settings_wallet_name_title">Name</string>
<string name="staking_amount_requirement_error">Die Anzahl der zu stakenden Krypros muss mindesten %s betragen</string>
<string name="staking_amount_tron_integer_error">Der Stakingbetrag wird aufgrund der Netzwerkregeln auf %1$s TRX aufgerundet.</string>
<string name="staking_claim_unstaked">Nicht gestakte beanspruche</string>
<string name="staking_details_annual_percentage_rate">Jährliche prozentuale Rendite</string>
<string name="staking_details_annual_percentage_rate_info">Die jährliche prozentuale Rendite, die du durch die Teilnahme am Staking erzielen kannst.</string>
@ -675,17 +676,23 @@
<string name="staking_locked">Gesperrt</string>
<string name="staking_migrate">Migrieren</string>
<string name="staking_native">Natives Staking</string>
<string name="staking_notification_claim_rewards_text">Verdiente Prämien werden direkt an Deine Adresse gesendet. Sobald Du diese eingefordert hast, stehen Dir die Mittel zur Verfügung.</string>
<string name="staking_notification_claim_rewards_text">Verdiente Belohnungen werden an deine Wallet gesendet und stehen sofort zur Verwendung zur Verfügung</string>
<string name="staking_notification_earn_rewards_text_daily">Sicher staken und tägliche Belohnungen verdienen.</string>
<string name="staking_notification_earn_rewards_text_hourly">Sicher staken und stündliche Belohnungen verdienen.</string>
<string name="staking_notification_earn_rewards_text_monthly">Sicher staken und monatliche Belohnungen verdienen.</string>
<string name="staking_notification_earn_rewards_text_period_day">Mit dem Staking kannst Du %1$s verdienen. Deine Staking-Belohnungen erhältst Du jeden tag.</string>
<string name="staking_notification_earn_rewards_text_period_hour">Mit dem Staking kannst Du %1$s verdienen. Deine Staking-Belohnungen erhältst Du jede Stunde.</string>
<string name="staking_notification_earn_rewards_text_period_month">Mit dem Staking kannst Du %1$s verdienen. Deine Staking-Belohnungen erhältst Du jeden Monat.</string>
<string name="staking_notification_earn_rewards_text_period_week">Mit dem Staking kannst Du %1$s verdienen. Deine Staking-Belohnungen erhältst Du jede Woche.</string>
<string name="staking_notification_earn_rewards_text_weekly">Sicher staken und wöchentliche Belohnungen verdienen.</string>
<string name="staking_notification_earn_rewards_title">Verdiene Staking-Belohnungen</string>
<string name="staking_notification_new_validator_funds_transfer">Beim Staking im %1$s -Netzwerk mit einem neuen Validator werden alle zuvor eingesetzten Kryptos automatisch an diesen Validator übertragen</string>
<string name="staking_notification_restake_rewards_text">Reinvestiert Deine verdienten Prämien in Deinen Einsatzbetrag und erhöht so den potenziellen Gewinn.</string>
<string name="staking_notification_unlock_text">Entsperre dein Geld, um es aus dem Staking-Prozess abzuheben. Das Freischalten nimmt %s.</string>
<string name="staking_notification_unstake_cosmos_text">Nach Ablauf der 21-tägigen Bindungsfrist kannst Du über Dein Guthaben verfügen. Die Prämie wird zusammen mit dem ungestaketen Guthaben abgehoben.</string>
<string name="staking_notification_unstake_text">Deine Assets steht Dir nach Ablauf der Frist für die Aufhebung der Bindung %s zur Verfügung.</string>
<string name="staking_notification_withdraw_text">Du kannst Dein Guthaben jetzt abheben. Es steht Dir sofort zur Verfügung.</string>
<string name="staking_notifications_revote_tron_text">Wenn du im Tron-Netzwerk mit einem neuen Validator stakest, werden alle zuvor eingesetzten Assets automatisch an diesen Validator übertragen.</string>
<string name="staking_preparing">Vorbereitung</string>
<string name="staking_ready_to_withdraw">Bereit zum Abheben</string>
<string name="staking_rebond">Erneut binden</string>

View file

@ -363,7 +363,7 @@
<string name="markets_selector_interval_24h_title">24 heures</string>
<string name="markets_selector_interval_3m_title">3 mois</string>
<string name="markets_selector_interval_6m_title">6 mois</string>
<string name="markets_selector_interval_7d_title">7 jours</string>
<string name="markets_selector_interval_7d_title">7j</string>
<string name="markets_selector_interval_all_title">Tout</string>
<string name="markets_sort_by_experienced_buyers_title">Acheteurs expérimentés</string>
<string name="markets_sort_by_rating_title">Évaluation</string>

View file

@ -295,6 +295,7 @@
<string name="give_permission_unlimited">無制限</string>
<string name="home_button_order">カードを注文</string>
<string name="home_button_scan">スキャン</string>
<string name="information_generated_with_ai">この情報はAIによって生成されました</string>
<string name="initial_message_change_access_code_body">アクセスコードを変更するには、上図のようにカードをタップし、操作が終了するまで取り外さないでください。</string>
<string name="initial_message_change_passcode_body">パスコードを変更するには、上記のようにカードをタップし、操作が終了するまで取り外さないでください。</string>
<string name="initial_message_create_wallet_body">ウォレットを作成するには、上記のようにカードをタップし、操作が終了するまで取り外さないでください。</string>
@ -624,6 +625,10 @@
<string name="send_summary_title">%sを送金する</string>
<string name="send_summary_transaction_description">**%1$s** を送金する (ネットワーク手数料%2$sを含む)</string>
<string name="send_summary_transaction_description_no_fiat_fee">**%1$s** と %2$s を送金しています。</string>
<string name="send_summary_transaction_description_prefix">** %1$s ** を送信しています</string>
<string name="send_summary_transaction_description_suffix_fee_covered">ネットワーク手数料は%1$sエネルギーを使用してカバーされます</string>
<string name="send_summary_transaction_description_suffix_fee_reduced">%1$sを使用するとネットワーク手数料が減額されます</string>
<string name="send_summary_transaction_description_suffix_including">ネットワーク手数料%1$sを含む</string>
<string name="send_transaction_success">取引は正常に署名され、ブロックチェーンノードに送信されました。ウォレットの残高はしばらくして更新されます。</string>
<string name="send_tron_account_activation_error">%1$sはTronネットワークのアセットです。手数料を計算して取引を行うには、アカウントにTronTRXを入金する必要があります。</string>
<string name="sent_transaction_sent_title">取引が送信されました</string>
@ -660,14 +665,22 @@
<string name="staking_migrate">移行</string>
<string name="staking_native">ネイティブステーキング</string>
<string name="staking_notification_claim_rewards_text">獲得した報酬はあなたのアドレスに直接送られ、すぐ使用可能です。</string>
<string name="staking_notification_earn_rewards_text_daily">安全にステーキングして、報酬を毎日獲得しましょう</string>
<string name="staking_notification_earn_rewards_text_hourly">安全にステーキングして、報酬を毎時間獲得しましょう</string>
<string name="staking_notification_earn_rewards_text_monthly">安全にステーキングして、報酬を毎月獲得しましょう</string>
<string name="staking_notification_earn_rewards_text_period_day">ステーキングにより%1$sを獲得できます。ステーキング報酬は毎日受け取れます。</string>
<string name="staking_notification_earn_rewards_text_period_hour">ステーキングにより%1$sを獲得できます。ステーキング報酬は毎時間受け取れます。</string>
<string name="staking_notification_earn_rewards_text_period_month">ステーキングにより%1$sを獲得できます。ステーキング報酬は毎月受け取れます。</string>
<string name="staking_notification_earn_rewards_text_period_week">ステーキングにより%1$sを獲得できます。ステーキング報酬は毎週受け取れます。</string>
<string name="staking_notification_earn_rewards_text_weekly">安全にステーキングして、報酬を毎週獲得しましょう</string>
<string name="staking_notification_earn_rewards_title">ステーキング報酬を獲得</string>
<string name="staking_notification_new_validator_funds_transfer">新しいバリデーターで%1$sネットワークにステーキングすると、以前にステーキングされた資金はすべてこのバリデーターに自動的に転送されます。</string>
<string name="staking_notification_restake_rewards_text">獲得した報酬をステーキングに再投資し、潜在的な収益を増やします。</string>
<string name="staking_notification_unlock_text">資金をステーキングから引き出すには、ロックを解除してください。ロック解除には%sかかります。</string>
<string name="staking_notification_unstake_cosmos_text">資金は、21日間のロック解除期間後に使用可能になります。報酬は、ロック解除後の資金とともに引き出されます。</string>
<string name="staking_notification_unstake_text">%sのステーキング解除期間後、資金はすぐ利用可能となります。</string>
<string name="staking_notification_withdraw_text">資金を引き出すことができ、すぐに使用できます</string>
<string name="staking_notifications_revote_tron_text">Tronネットワークに新しいバリデーターでステーキングすると、以前にステーキングされた資金はすべてこのバリデーターに自動的に転送されます。</string>
<string name="staking_preparing">準備中</string>
<string name="staking_ready_to_withdraw">引き出し準備完了</string>
<string name="staking_rebond">再結束</string>

View file

@ -177,6 +177,7 @@
<string name="custom_token_contract_address_input_title">Адрес контракта</string>
<string name="custom_token_creation_error_invalid_contract_address">Адрес контракта некорректен</string>
<string name="custom_token_creation_error_network_not_selected">Пожалуйста, выберите сеть</string>
<string name="custom_token_creation_error_token_already_exist_title">Токен уже существует</string>
<string name="custom_token_creation_error_wrong_decimals">Десятичное число должно быть действительным целым числом, до %d</string>
<string name="custom_token_custom_derivation">Своя деривация</string>
<string name="custom_token_custom_derivation_placeholder">Например m/00\'/0000\'/0\'/0/0</string>
@ -642,6 +643,8 @@
<string name="send_summary_title">Отправка %s</string>
<string name="send_summary_transaction_description">Вы отправляете **%1$s**, включая комиссию сети %2$s</string>
<string name="send_summary_transaction_description_no_fiat_fee">Вы отправляете **%1$s** и %2$s</string>
<string name="send_summary_transaction_description_prefix">Вы отправляете **%1$s**</string>
<string name="send_summary_transaction_description_suffix_including">включая комиссию сети в размере %1$s</string>
<string name="send_transaction_success">Транзакция успешно подписана и отправлена в блокчейн. Баланс будет обновлен через некоторое время</string>
<string name="send_tron_account_activation_error">%1$s — это монета в сети Tron. Чтобы рассчитать комиссию и совершить транзакцию, вам необходимо внести немного Tron (TRX) на свой адрес.</string>
<string name="sent_transaction_sent_title">Транзакция отправлена</string>
@ -682,6 +685,7 @@
<string name="staking_notification_earn_rewards_text_period_month">Стейкинг дает возможность вам получать %1$s. Награда будет зачисляться каждый месяц.</string>
<string name="staking_notification_earn_rewards_text_period_week">Стейкинг дает возможность вам получать %1$s. Награда будет зачисляться каждую неделю.</string>
<string name="staking_notification_earn_rewards_title">Получите награду за стейкинг</string>
<string name="staking_notification_unlock_text">Разблокируйте свои средства, чтобы вывести их из стейкинга. Разблокировка займёт %s.</string>
<string name="staking_notification_unstake_text">Ваши средства будут доступны после %s периода отзыва.</string>
<string name="staking_notification_withdraw_text">Вы можете вывести свои средства из стейкинга, они будут доступны для использования незамедлительно.</string>
<string name="staking_restake">Сменить валидатора</string>

View file

@ -301,6 +301,7 @@
<string name="give_permission_unlimited">Необмежено</string>
<string name="home_button_order">Купити</string>
<string name="home_button_scan">Сканувати</string>
<string name="information_generated_with_ai">Ця інформація була створена за допомогою ШІ</string>
<string name="initial_message_change_access_code_body">Щоб змінити код доступу, прикладіть картку, як показано вище, і не прибирайте її до закінчення операції</string>
<string name="initial_message_change_passcode_body">Щоб змінити пароль, прикладіть картку, як показано вище, і не прибирайте її до закінчення операції</string>
<string name="initial_message_create_wallet_body">Щоб створити гаманець, прикладіть картку, як показано вище, і не прибирайте її до завершення операції</string>
@ -371,7 +372,7 @@
<string name="markets_selector_interval_24h_title">24 год.</string>
<string name="markets_selector_interval_3m_title">3 міс.</string>
<string name="markets_selector_interval_6m_title">6 міс.</string>
<string name="markets_selector_interval_7d_title">7 днів</string>
<string name="markets_selector_interval_7d_title">7д</string>
<string name="markets_selector_interval_all_title">Увесь</string>
<string name="markets_sort_by_experienced_buyers_title">Досвідчені покупці</string>
<string name="markets_sort_by_rating_title">За рейтингом</string>
@ -648,6 +649,10 @@
<string name="send_summary_title">Надіслати %s</string>
<string name="send_summary_transaction_description">Ви надсилаєте **%1$s**, включно з комісію мережі %2$s</string>
<string name="send_summary_transaction_description_no_fiat_fee">Ви надсилаєте **%1$s** і %2$s</string>
<string name="send_summary_transaction_description_prefix">Ви надсилаєте **%1$s**</string>
<string name="send_summary_transaction_description_suffix_fee_covered">комісія мережі буде покрита, використовуючи %1$s енергію</string>
<string name="send_summary_transaction_description_suffix_fee_reduced">комісія мережі буде зменшена, витрачаючи %1$s</string>
<string name="send_summary_transaction_description_suffix_including">включно з комісією мережі %1$s</string>
<string name="send_transaction_success">Транзакція успішно підписана і відправлена до блокчейну. Баланс гаманця буде оновлено через деякий час</string>
<string name="send_tron_account_activation_error">%1$s — це монета у мережі Tron. Щоб розрахувати комісію та здійснити транзакцію, вам необхідно внести певну кількість Tron (TRX) на свій рахунок.</string>
<string name="sent_transaction_sent_title">Трансакцію надіслано</string>
@ -684,14 +689,22 @@
<string name="staking_migrate">Перемістити</string>
<string name="staking_native">Нативний стейкінг</string>
<string name="staking_notification_claim_rewards_text">Зароблені винагороди будуть надіслані на ваш гаманець і доступні для використання відразу</string>
<string name="staking_notification_earn_rewards_text_daily">Стейкайте безпечно та почніть отримувати винагороди щоденно</string>
<string name="staking_notification_earn_rewards_text_hourly">Стейкайте безпечно та почніть отримувати винагороди щогодини</string>
<string name="staking_notification_earn_rewards_text_monthly">Стейкайте безпечно та почніть отримувати винагороди щомісяця</string>
<string name="staking_notification_earn_rewards_text_period_day">Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються щодня.</string>
<string name="staking_notification_earn_rewards_text_period_hour">Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються кожну годину.</string>
<string name="staking_notification_earn_rewards_text_period_month">Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються щомісяця.</string>
<string name="staking_notification_earn_rewards_text_period_week">Стейкінг дозволяє заробляти %1$s. Ваші винагороди за стейкінг зараховуються щотиждня.</string>
<string name="staking_notification_earn_rewards_text_weekly">Стейкайте безпечно та почніть отримувати винагороди щотижня</string>
<string name="staking_notification_earn_rewards_title">Отримуйте винагороду за стейкінг</string>
<string name="staking_notification_new_validator_funds_transfer">Стейкінг в мережі %1$s з новим валідатором автоматично переведе всі раніше застейкані кошти до цього валідатора</string>
<string name="staking_notification_restake_rewards_text">Реінвестуйте зароблені винагороди у суму стейкінгу, щоб збільшити потенційний прибуток.</string>
<string name="staking_notification_unlock_text">Розблокуйте свої кошти, щоб вивести їх зі стейкінгу. Розблокування займе %s.</string>
<string name="staking_notification_unstake_cosmos_text">Ваші кошти будуть доступні для використання після закінчення 21-денного періоду розблокування. Винагорода буде отримана разом з вашими незастейканими коштами.</string>
<string name="staking_notification_unstake_text">Ваші кошти будуть доступні після %s періоду розблокування.</string>
<string name="staking_notification_withdraw_text">Тепер ви можете вивести свої кошти, вони будуть доступні для використання відразу</string>
<string name="staking_notifications_revote_tron_text">Стейкінг в мережі Tron з новим валідатором автоматично переведе всі раніше застейкані кошти до цього валідатора</string>
<string name="staking_preparing">Підготовка</string>
<string name="staking_ready_to_withdraw">Готова до виведення</string>
<string name="staking_rebond">Зʼєднати ще раз</string>

View file

@ -175,7 +175,7 @@
<string name="custom_token_contract_address_input_title">Contract address</string>
<string name="custom_token_creation_error_invalid_contract_address">Contract address is invalid</string>
<string name="custom_token_creation_error_network_not_selected">Please select the network</string>
<string name="custom_token_creation_error_token_already_exist_message">This token has already been added to the list</string>
<string name="custom_token_creation_error_token_already_exist_message">This token has already been added to the list</string>
<string name="custom_token_creation_error_token_already_exist_title">Token already exists</string>
<string name="custom_token_creation_error_wrong_decimals">Decimal must be a valid integer, up to %d</string>
<string name="custom_token_custom_derivation">Custom derivation</string>
@ -351,6 +351,7 @@
<string name="markets_common_my_portfolio">My portfolio</string>
<string name="markets_common_title">Market</string>
<string name="markets_generate_addresses_notification">To generate addresses for selected networks, you must scan your Tangem Wallet card</string>
<string name="markets_hint">To add tokens pull this up or tap the search bar</string>
<string name="markets_insights_info_description_message">This sections data is sourced from the following networks: %s</string>
<string name="markets_loading_error_title">Unable to load the data…</string>
<string name="markets_loading_no_data_title">No data</string>
@ -634,8 +635,8 @@
<string name="send_summary_transaction_description">You are sending **%1$s** including a network fee of %2$s</string>
<string name="send_summary_transaction_description_no_fiat_fee">You are sending **%1$s** and %2$s</string>
<string name="send_summary_transaction_description_prefix">You are sending **%1$s**</string>
<string name="send_summary_transaction_description_suffix_fee_covered">network fee will be covered by using %1$s %2$s</string>
<string name="send_summary_transaction_description_suffix_fee_reduced">network fee will be reduced by spending %1$s %2$s</string>
<string name="send_summary_transaction_description_suffix_fee_covered">network fee will be covered by using %1$s energy</string>
<string name="send_summary_transaction_description_suffix_fee_reduced">network fee will be reduced by spending %1$s energy</string>
<string name="send_summary_transaction_description_suffix_including">including a network fee of %1$s</string>
<string name="send_transaction_success">Transaction has been successfully signed and sent to the blockchain node. Wallet balance will be updated in a while</string>
<string name="send_tron_account_activation_error">%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.</string>
@ -645,6 +646,7 @@
<string name="settings_forget_wallet_footer">This will remove the wallet from the application. The wallet itself can be added again.</string>
<string name="settings_wallet_name_title">Name</string>
<string name="staking_amount_requirement_error">The amount to stake must be at least %s</string>
<string name="staking_amount_tron_integer_error">Staking amount will be rounded to %1$s TRX due to network rules.</string>
<string name="staking_claim_unstaked">Claim unstaked</string>
<string name="staking_details_annual_percentage_rate">Annual percentage rate</string>
<string name="staking_details_annual_percentage_rate_info">The annual percentage return you can earn from participating in staking.</string>

View file

@ -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<StakingUiState> {
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),
)
}
}

View file

@ -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<StakingUiState> {
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),
)
}
}

View file

@ -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<AmountState> {
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,
)
}

View file

@ -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<StakingUiState> {
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,
),
),
)
}
}

View file

@ -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
}

View file

@ -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,
),
)
}
}
}
}