Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-09 18:54:51 +05:00
commit d64a36a2a8
29 changed files with 531 additions and 80 deletions

View file

@ -81,6 +81,12 @@ sealed class AnalyticsParam {
override val feeType: FeeType,
) : TxSentFrom("Swap"), TxData
data class Staking(
override val blockchain: String,
override val token: String,
override val feeType: FeeType,
) : TxSentFrom("Staking"), TxData
data class Approve(
override val blockchain: String,
override val token: String,

View file

@ -84,6 +84,7 @@
<string name="common_camera_denied_alert_message">D hast keinen Zugang zur Kamera erteilt, bitte passe deine Datenschutzeinstellungen an</string>
<string name="common_cancel">Abbrechen</string>
<string name="common_choose_action">Aktion wählen</string>
<string name="common_claim">Beanspruchen</string>
<string name="common_claim_rewards">Stakingbelohnungen beanstpruchen</string>
<string name="common_close">Schließen</string>
<string name="common_continue">Weiter</string>
@ -115,7 +116,9 @@
<string name="common_go_to_provider">Zum Anbieter gehen</string>
<string name="common_go_to_token">Zum Token</string>
<string name="common_import">Importieren</string>
<string name="common_in_progress">In Arbeit</string>
<string name="common_later">Später</string>
<string name="common_left">%1$s übrig</string>
<string name="common_locked">Gesperrt</string>
<string name="common_main_network">Hauptnetz</string>
<string name="common_network_fee_title">Netzgebühr</string>
@ -413,6 +416,9 @@
<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>
<string name="markets_token_details_trading_volume">Handelsvolumen (24h)</string>
<string name="markets_token_details_trading_volume_24h_description">Der Gesamtbetrag einer Kryptowährung, der innerhalb der letzten 24 Stunden gehandelt wurde, wobei das Aktivitäts- und Liquiditätsniveau auf dem Markt angegeben wird</string>
<string name="markets_tooltip_message">Rufe dies auf oder tippe auf die Suchleiste, um Token direkt vom Markt hinzuzufügen</string>
<string name="markets_tooltip_title">Token hinzufügen</string>
<string name="nfc_error_unavailable">NFC ist auf deinem Gerät nicht verfügbar</string>
<string name="onboarding_access_code_feature_1_description">Du musst einen einzigen Zugangscode einrichten, um alle deine Karten zu schützen</string>
<string name="onboarding_access_code_feature_1_title">Schützen</string>
<string name="onboarding_access_code_feature_2_description">Du kannst später auf jeder Karte einen individuellen Zugangscode einrichten</string>
@ -661,15 +667,18 @@
<string name="staking_details_unbonding_period_info">Der Zeitraum, den du nach der Beantragung der Abhebung von Geldern aus dem Staking warten musst, bevor die Token verfügbar werden.</string>
<string name="staking_details_warmup_period">Aufwärmphase</string>
<string name="staking_details_warmup_period_info">Die zugewiesene Zeit für die Aktivierung der Teilnahme am Staking.</string>
<string name="staking_legal">Indem Du die Staking-Funktionalität nutzen, stimmst Du den %1$s und %2$s des Anbieters zu.</string>
<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_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_title">Verdiene Staking-Belohnungen</string>
<string name="staking_notification_unstake_text">Die Belohnungen werden sofort nach dem unstaken gestoppt. Der unstakingprozess dauert %s.</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_unstake_text">Die Belohnungen werden sofort nach dem start des unstaken gestoppt. Der unstakingprozess dauert %s.</string>
<string name="staking_notification_withdraw_text">Dein Guthaben wurde freigegeben. Du kannst es jetzt zusammen mit deinen verdienten Prämien auszahlen.</string>
<string name="staking_preparing">Vorbereitung</string>
<string name="staking_ready_to_withdraw">Bereit zum Abheben</string>
@ -691,17 +700,22 @@
<string name="staking_rewards">Belohnungen</string>
<string name="staking_stake_locked">Stake gesperrt</string>
<string name="staking_stake_more">Mehr staken</string>
<string name="staking_summary_description_text">Du setzt %1$s ein und erhältst jährlich ~ %2$s</string>
<string name="staking_tap_to_unlock">Zum Entsperren antippen</string>
<string name="staking_tap_to_withdraw">Zum abheben antippen</string>
<string name="staking_title_stake">Stake %s</string>
<string name="staking_title_unstake">Staking beenden%s</string>
<string name="staking_unbonding">Lösen der Bindungen</string>
<string name="staking_unlocked_locked">Gelocktes unlocken</string>
<string name="staking_unstaked">Unstaken</string>
<string name="staking_unstaking">Staking beenden</string>
<string name="staking_unstaking_item_name">Unstake Assets %s</string>
<string name="staking_validator">Validator/ Prüfer</string>
<string name="staking_validators">Validatoren</string>
<string name="staking_vote">Abstimmung</string>
<string name="staking_vote_locked">Abstimmung gesperrt</string>
<string name="staking_withdraw">Zurückziehen</string>
<string name="staking_your_stakes">Deine Einsätze</string>
<string name="story_awe_description">Bewahre deine Krypto-Assets sicher auf, während die privaten Schlüssel auf deiner Karte bleiben</string>
<string name="story_awe_title">Revolutionäre Hardware-Wallet</string>
<string name="story_backup_description">Bis zu 3 physische Karten pro Wallet</string>
@ -725,7 +739,6 @@
<string name="swapping_high_price_impact_description">Der Tausch dieser Menge ausgewählter Token hat erhebliche Auswirkungen auf den Preis und verringert dein Ergebnis.</string>
<string name="swapping_insufficient_funds">Unzureichende Mittel</string>
<string name="swapping_permission_header">Erlaubnis erteilen</string>
<string name="swapping_success_view_title">In Arbeit</string>
<string name="swapping_swap_action">Tauschen</string>
<string name="swapping_to_title">Du erhältst</string>
<string name="swapping_token_list_title">Token auswählen</string>

View file

@ -115,10 +115,7 @@
<string name="common_go_to_provider">Ir al proveedor</string>
<string name="common_go_to_token">Ir al token</string>
<string name="common_import">Importe</string>
<plurals name="common_in_days">
<item quantity="one">en %d día</item>
<item quantity="other">en %d días</item>
</plurals>
<string name="common_in_progress">En progreso</string>
<string name="common_later">Más tarde</string>
<string name="common_locked">Bloqueado</string>
<string name="common_main_network">Red principal</string>
@ -132,6 +129,7 @@
<string name="common_origin_card">Tarjeta principal</string>
<string name="common_passphrase">Frase de contraseña</string>
<string name="common_paste">Pegar</string>
<string name="common_privacy_policy">Política de privacidad</string>
<string name="common_range">%1$s-%2$s</string>
<string name="common_range_with_space">%1$s — %2$s</string>
<string name="common_read_more">Leer más</string>
@ -159,6 +157,7 @@
<string name="common_support">Soporte</string>
<string name="common_swap">Intercambiar</string>
<string name="common_terms_and_conditions">términos y condiciones</string>
<string name="common_terms_of_use">Condiciones de uso</string>
<string name="common_today">Hoy</string>
<string name="common_transaction_failed">Transacción fallida</string>
<string name="common_transactions">Transacciones</string>
@ -264,7 +263,6 @@
<string name="express_legal_one_placeholder">Al utilizar la función de intercambio, acepta el %s</string>
<string name="express_legal_two_placeholders">Al utilizar la función de intercambio, aceptas las condiciones de %1$s y %2$s del proveedor</string>
<string name="express_more_providers_soon">Próximamente habrá más proveedores.\n¡Estén atentos!</string>
<string name="express_privacy_policy">Política de privacidad</string>
<string name="express_provider">Proveedor</string>
<string name="express_provider_best_rate">Mejor tarifa</string>
<string name="express_provider_max_amount">Disponible hasta %s</string>
@ -272,7 +270,6 @@
<string name="express_provider_not_available">No disponible para este par</string>
<string name="express_provider_permission_needed">Permiso requerido</string>
<string name="express_provider_recommended">Recomendado</string>
<string name="express_terms_of_use">Condiciones de uso</string>
<string name="express_token_list_empty_search">No se encontraron fichas. Por favor intenta con otra solicitud</string>
<string name="express_transaction_id">ID : %s</string>
<string name="express_transaction_id_copied">ID de transacción copiado</string>
@ -413,6 +410,8 @@
<string name="markets_token_details_total_supply_description">La cantidad máxima de monedas o tokens que pueden existir para una criptomoneda en particular</string>
<string name="markets_token_details_trading_volume">Volumen de operaciones (24 horas)</string>
<string name="markets_token_details_trading_volume_24h_description">La cantidad total de una criptomoneda que se ha negociado en las últimas 24 horas, lo que indica el nivel de actividad y liquidez en el mercado.</string>
<string name="markets_tooltip_message">Tire hacia arriba o toque la barra de búsqueda para agregar tokens directamente desde el mercado</string>
<string name="markets_tooltip_title">Agregar tokens</string>
<string name="onboarding_access_code_feature_1_description">Deba configurar un único código de acceso para proteger todas sus tarjetas</string>
<string name="onboarding_access_code_feature_1_title">Proteger</string>
<string name="onboarding_access_code_feature_2_description">Puede configurar un código de acceso individual en cada tarjeta más tarde</string>
@ -637,8 +636,6 @@
<string name="settings_forget_wallet">Olvidar la billetera</string>
<string name="settings_forget_wallet_footer">Esto eliminará la wallet de la aplicación. La wallet en sí puede\nañadirse de nuevo.</string>
<string name="settings_wallet_name_title">Nombre</string>
<string name="staking_active">Activo</string>
<string name="staking_active_footer">Para eliminar el staking de sus activos, presione el bloque de arriba</string>
<string name="staking_amount_requirement_error">El monto del staking debe ser al menos %s</string>
<string name="staking_claim_unstaked">Unstaking de la reclamación</string>
<string name="staking_details_annual_percentage_rate">Porcentaje de rendimiento anual</string>
@ -697,7 +694,6 @@
<string name="staking_unbonding">Desunión</string>
<string name="staking_unlocked_locked">Desbloquear</string>
<string name="staking_unstaked">Sin staking</string>
<string name="staking_unstaked_footer">Marque activos sin staking para reclamarlos</string>
<string name="staking_unstaking">Unstaking</string>
<string name="staking_validator">Validador</string>
<string name="staking_validators">Validadores</string>
@ -727,7 +723,6 @@
<string name="swapping_high_price_impact_description">Hacer swap de esta cantidad de tokens seleccionados causará un impacto significativo en el precio y reducirá su resultado.</string>
<string name="swapping_insufficient_funds">Fondos insuficientes</string>
<string name="swapping_permission_header">Dar autorización</string>
<string name="swapping_success_view_title">En progreso</string>
<string name="swapping_swap_action">Intercambie</string>
<string name="swapping_to_title">Usted recibe</string>
<string name="swapping_token_list_title">Elige token</string>
@ -808,7 +803,7 @@
<string name="wallet_connect_error_with_framework_message">Hemos encontrado un error desconocido. Mensaje de error: %s. Si el problema persiste, no duda en contactar con nuestro soporte</string>
<string name="wallet_connect_error_wrong_card_selected">Tarjeta incorrecta seleccionada en Tangem App</string>
<string name="wallet_connect_failed_to_build_tx">Error al crear la transacción a partir de los datos de la dApp. Código: %s</string>
<string name="wallet_connect_generic_error_with_code">Hemos encontrado un error desconocido. Mensaje de error: %s. Si el problema persiste, contacte con nuestro soporte</string>
<string name="wallet_connect_generic_error_with_code">Hemos encontrado un error desconocido. Mensaje de error: %d. Si el problema persiste, contacte con nuestro soporte</string>
<string name="wallet_connect_no_sessions_message">No hay sesiones abiertas de WalletConnect</string>
<string name="wallet_connect_no_sessions_title">¡Qué lástima! No hay sesiones.</string>
<string name="wallet_connect_pairing_error">Error al emparejar la sesión de WalletConnect: %1$s</string>

View file

@ -115,6 +115,7 @@
<string name="common_go_to_provider">Aller au fournisseur</string>
<string name="common_go_to_token">Aller au jeton</string>
<string name="common_import">Importez</string>
<string name="common_in_progress">En cours</string>
<string name="common_later">Plus tard</string>
<string name="common_locked">Verrouillé</string>
<string name="common_main_network">Réseau principal</string>
@ -409,6 +410,8 @@
<string name="markets_token_details_total_supply_description">Le nombre maximal de pièces ou de jetons pouvant exister pour une crypto-monnaie particulière</string>
<string name="markets_token_details_trading_volume">Volume des échanges (24h)</string>
<string name="markets_token_details_trading_volume_24h_description">Le montant total d\'une crypto-monnaie qui a été échangé au cours des dernières 24 heures, indiquant le niveau d\'activité et de liquidité du marché</string>
<string name="markets_tooltip_message">Tirez vers le haut ou appuyez sur la barre de recherche pour ajouter des jetons directement depuis le marché</string>
<string name="markets_tooltip_title">Ajouter des jetons</string>
<string name="onboarding_access_code_feature_1_description">Vous devez définir un seul code d\'accès pour protéger toutes vos cartes</string>
<string name="onboarding_access_code_feature_1_title">Protéger</string>
<string name="onboarding_access_code_feature_2_description">Vous pourrez définir un code d\'accès individuel sur chaque carte plus tard</string>
@ -452,7 +455,7 @@
<string name="onboarding_navbar_title_creating_backup">Sauvegarde en cours</string>
<string name="onboarding_seed_button_read_more">En savoir plus sur les seed phrases</string>
<plurals name="onboarding_seed_generate_message_words_count">
<item quantity="one">Vide</item>
<item quantity="one"></item>
<item quantity="other">Écrivez ces %d mots dans l\'ordre indiqué ci-dessous et conservez-les dans un endroit sûr et secret.</item>
</plurals>
<string name="onboarding_seed_generate_title">Votre seed phrase</string>
@ -720,7 +723,6 @@
<string name="swapping_high_price_impact_description">Échanger ce montant de jetons sélectionnés aura un impact significatif sur les prix et réduira votre résultat.</string>
<string name="swapping_insufficient_funds">Fonds insuffisants</string>
<string name="swapping_permission_header">Donner l\'autorisation</string>
<string name="swapping_success_view_title">En cours</string>
<string name="swapping_swap_action">Échangez</string>
<string name="swapping_to_title">Vous recevez</string>
<string name="swapping_token_list_title">Choisir le jeton</string>

View file

@ -114,7 +114,9 @@
<string name="common_go_to_provider">プロバイダーへ移動</string>
<string name="common_go_to_token">トークンへ移動</string>
<string name="common_import">インポート</string>
<string name="common_in_progress">進行中</string>
<string name="common_later">後で</string>
<string name="common_left">残り%1$s</string>
<string name="common_locked">ロックされています</string>
<string name="common_main_network">メインネットワーク</string>
<string name="common_network_fee_title">ネットワーク手数料</string>
@ -406,6 +408,9 @@
<string name="markets_token_details_total_supply_description">特定の暗号資産に存在しうるコインまたはトークンの最大数</string>
<string name="markets_token_details_trading_volume">取引量24時間</string>
<string name="markets_token_details_trading_volume_24h_description">過去24時間以内に取引された暗号資産の合計額。市場の活発さと流動性を示します。</string>
<string name="markets_tooltip_message">これをドラッグするか、検索窓をタップして、マーケットから直接トークンを追加します</string>
<string name="markets_tooltip_title">トークンを追加</string>
<string name="nfc_error_unavailable">お使いのデバイスではNFCが使用できません</string>
<string name="onboarding_access_code_feature_1_description">すべてのカードを保護するには、単一のアクセスコードを設定する必要があります</string>
<string name="onboarding_access_code_feature_1_title">保護する</string>
<string name="onboarding_access_code_feature_2_description">後で各カードに個別のアクセスコードを設定できます</string>
@ -684,6 +689,8 @@
<string name="staking_stake_locked">ステーキングはロックされています</string>
<string name="staking_stake_more">もっとステーキングする</string>
<string name="staking_summary_description_text">%1$sをステーキングし、年間 ~ %2$sを受け取ります</string>
<string name="staking_tap_to_unlock">タップしてロック解除</string>
<string name="staking_tap_to_withdraw">タップして引き出す</string>
<string name="staking_title_stake">%sをステーキングする</string>
<string name="staking_title_unstake">%sのステーキング解除</string>
<string name="staking_unbonding">ステーキング解約中</string>
@ -696,6 +703,7 @@
<string name="staking_vote">投票する</string>
<string name="staking_vote_locked">投票はロックされています</string>
<string name="staking_withdraw">引き出す</string>
<string name="staking_your_stakes">あなたのステーキング</string>
<string name="story_awe_description">カード内に秘密鍵を保管しながら暗号資産を安全に保管します</string>
<string name="story_awe_title">革新的なハードウェアウォレット</string>
<string name="story_backup_description">1つのウォレットに最大3枚のカード</string>
@ -719,7 +727,6 @@
<string name="swapping_high_price_impact_description">選択したトークンをこの量を交換すると、価格に大きな影響が生じ、結果が減少します。</string>
<string name="swapping_insufficient_funds">残高不足</string>
<string name="swapping_permission_header">許可を与える</string>
<string name="swapping_success_view_title">進行中</string>
<string name="swapping_swap_action">スワップ</string>
<string name="swapping_to_title">受け取る</string>
<string name="swapping_token_list_title">トークンを選択</string>

View file

@ -84,6 +84,7 @@
<string name="common_buy_currency">Перейти на %1$s</string>
<string name="common_camera_denied_alert_message">Вы не предоставили доступ к камере, пожалуйста, измените настройки конфиденциальности.</string>
<string name="common_cancel">Отмена</string>
<string name="common_claim">Получить</string>
<string name="common_claim_rewards">Вывести награду</string>
<string name="common_close">Закрыть</string>
<string name="common_continue">Продолжить</string>
@ -117,7 +118,9 @@
<string name="common_go_to_provider">К провайдеру</string>
<string name="common_go_to_token">Перейти в токен</string>
<string name="common_import">Импортировать</string>
<string name="common_in_progress">В процессе</string>
<string name="common_later">Позже</string>
<string name="common_left">Осталось %1$s</string>
<string name="common_locked">Заблокирован</string>
<string name="common_main_network">Основная сеть</string>
<string name="common_network_fee_title">Сетевая комиссия</string>
@ -363,7 +366,7 @@
<string name="markets_selector_interval_6m_title"></string>
<string name="markets_selector_interval_7d_title"></string>
<string name="markets_selector_interval_all_title">Все</string>
<string name="markets_sort_by_experienced_buyers_title">Опытные покупатели</string>
<string name="markets_sort_by_experienced_buyers_title">Опытные трейдеры</string>
<string name="markets_sort_by_rating_title">Рейтинг</string>
<string name="markets_sort_by_title">Сортировать по</string>
<string name="markets_sort_by_top_gainers_title">Лидеры роста</string>
@ -377,12 +380,12 @@
<item quantity="other">На основе %d оценок</item>
</plurals>
<string name="markets_token_details_blockchain_site">Веб-сайт</string>
<string name="markets_token_details_buy_pressure">Покупательское предпочтение</string>
<string name="markets_token_details_buy_pressure">Покуп. предпочтение</string>
<string name="markets_token_details_buy_pressure_description">Разница между объемом покупателей и продавцов</string>
<string name="markets_token_details_circulating_supply">Циркулирующее предложение</string>
<string name="markets_token_details_circulating_supply">Циркулир. предл.</string>
<string name="markets_token_details_circulating_supply_description">Общее количество монет, доступных для торговли и находящихся в обращении на рынке</string>
<string name="markets_token_details_experienced_buyers">Опытные покупкатели</string>
<string name="markets_token_details_fully_diluted_valuation">Полностью разбавленная капитализация</string>
<string name="markets_token_details_fully_diluted_valuation">Полн. разб. кап.</string>
<string name="markets_token_details_fully_diluted_valuation_description">Общая теоретическая стоимость криптовалюты, если все монеты, которые могут существовать, находятся в обращении, включая те, которые в настоящее время не обращаются</string>
<string name="markets_token_details_genesis_date">Дата создания</string>
<string name="markets_token_details_high">Высокий</string>
@ -394,9 +397,9 @@
<string name="markets_token_details_liquidity_description">Изменение объема ликвидности, доступной для токена в течение указанного периода времени.</string>
<string name="markets_token_details_liquidity_index">Индекс ликвидности</string>
<string name="markets_token_details_low">Низкий</string>
<string name="markets_token_details_market_capitalization">Рыночная капитализация</string>
<string name="markets_token_details_market_capitalization">Рын. кап.</string>
<string name="markets_token_details_market_capitalization_description">Общая рыночная стоимость криптовалюты, рассчитываемая путем умножения текущей цены монеты на общее количество монет в обращении.</string>
<string name="markets_token_details_market_rating">Рыночный рейтинг</string>
<string name="markets_token_details_market_rating">Рейтинг</string>
<string name="markets_token_details_max_supply">Максимальный объем</string>
<string name="markets_token_details_metrics">Метрики</string>
<string name="markets_token_details_official_links">Официальные ссылки</string>
@ -408,6 +411,9 @@
<string name="markets_token_details_total_supply_description">Максимальное количество монет или токенов, которое может когда-либо существовать для выбранной криптовалюты.</string>
<string name="markets_token_details_trading_volume">Объем торгов (24ч)</string>
<string name="markets_token_details_trading_volume_24h_description">Общая сумма криптовалюты, которая была продана за последние 24 часа, показывающая уровень активности и ликвидности на рынке.</string>
<string name="markets_tooltip_message">Потяните вверх или коснитесь поисковой строки, чтобы добавить токены напрямую из маркета</string>
<string name="markets_tooltip_title">Добавить токены</string>
<string name="nfc_error_unavailable">Функция NFC недоступна на вашем устройстве</string>
<string name="onboarding_access_code_feature_1_description">Вам необходимо установить единый код доступа для защиты всех ваших карт</string>
<string name="onboarding_access_code_feature_1_title">Защита</string>
<string name="onboarding_access_code_feature_2_description">Позже вы сможете установить индивидуальный код доступа для каждой карты</string>
@ -652,9 +658,9 @@
<string name="staking_details_metrics_block_header">Метрики</string>
<string name="staking_details_minimum_requirement">Минимальное количество</string>
<string name="staking_details_no_rewards_to_claim">Нет вознаграждений к получению</string>
<string name="staking_details_reward_claiming">Способ возраграждения</string>
<string name="staking_details_reward_claiming">Способ вознаграждения</string>
<string name="staking_details_reward_claiming_info">Способ получения вознаграждений за стейкинг. Он может быть автоматическим, при котором вознаграждение само зачисляется вам на адрес или в ручную, когда вознаграждение нужно вывести, создав транзакцию на её получение.</string>
<string name="staking_details_reward_schedule">Период возрагражения</string>
<string name="staking_details_reward_schedule">Период вознагражения</string>
<string name="staking_details_reward_schedule_info">Это период, определяющий, когда участники стейкинга получат свои вознаграждения.</string>
<string name="staking_details_rewards_to_claim">Вознаграждение для получения: %s</string>
<string name="staking_details_title">Стейкинг %s</string>
@ -662,15 +668,18 @@
<string name="staking_details_unbonding_period_info">Период, который необходимо подождать после запроса на вывод средств из стейкинга, прежде чем токены станут доступны.</string>
<string name="staking_details_warmup_period">Период прогрева</string>
<string name="staking_details_warmup_period_info">Время, необходимое для начала процесса стейкинга и активации процесса начисления наград</string>
<string name="staking_legal">Пользуясь стейкинг сервисом, вы соглашаетесь с %1$s и %2$s</string>
<string name="staking_locked">Заблокировано</string>
<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_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_title">Получите награду за стейкинг</string>
<string name="staking_notification_unstake_text">Награда перестанет начисляться сразу после того, как вы начнете процесс завершения стейкинга. Процесс завершения длится %s.</string>
<string name="staking_notification_unstake_text">Ваши средства будут доступны после %s периода отзыва.</string>
<string name="staking_notification_withdraw_text">Вы можете вывести свои средства из стейкинга, они будут доступны для использования незамедлительно.</string>
<string name="staking_restake">Сменить валидатора</string>
<string name="staking_restake_rewards">Застейкать вознаграждения</string>
<string name="staking_revoke">Отозвать</string>
@ -688,6 +697,8 @@
<string name="staking_rewards">Вознаграждения</string>
<string name="staking_stake_locked">Стейкинг закрыт</string>
<string name="staking_stake_more">Застейкать еще</string>
<string name="staking_tap_to_unlock">Нажмите для разблокировки</string>
<string name="staking_tap_to_withdraw">Нажмите для вывода</string>
<string name="staking_title_stake">Застейкать %s</string>
<string name="staking_title_unstake">Вывести %s</string>
<string name="staking_unbonding">Отзыв</string>
@ -723,7 +734,6 @@
<string name="swapping_high_price_impact_description">Обмен этой суммы выбранных токенов может вызвать значительные колебания цены и уменьшить получаемую сумму.</string>
<string name="swapping_insufficient_funds">Недостаточно средств</string>
<string name="swapping_permission_header">Дать разрешение</string>
<string name="swapping_success_view_title">В процессе</string>
<string name="swapping_swap_action">Обменять</string>
<string name="swapping_to_title">Вы получите</string>
<string name="swapping_token_list_title">Выберите токен</string>
@ -805,7 +815,7 @@
<string name="wallet_connect_error_with_framework_message">Произошла непредвиденная ошибка. Сообщение ошибки: %s Попробуйте, пожалуйста, позже. Если проблема будет продолжать возникать - обратитесь в службу поддержки.</string>
<string name="wallet_connect_error_wrong_card_selected">Неверная карта выбрана в приложении Tangem</string>
<string name="wallet_connect_failed_to_build_tx">Не удалось создать транзакцию из данных Dapp. Код: %s</string>
<string name="wallet_connect_generic_error_with_code">Произошла непредвиденная ошибка. Код ошибки: %d Попробуйте, пожалуйста, позже. Если проблема будет продолжать возникать - обратитесь в службу поддержки.</string>
<string name="wallet_connect_generic_error_with_code">Произошла непредвиденная ошибка. Код ошибки: %d. Попробуйте, пожалуйста, позже. Если проблема будет продолжать возникать - обратитесь в службу поддержки.</string>
<string name="wallet_connect_no_sessions_message">Нет открытых сессий WalletConnect</string>
<string name="wallet_connect_no_sessions_title">Упс. Нет сессий.</string>
<string name="wallet_connect_pairing_error">Не удалось создать пару WalletConnect: %1$s</string>

View file

@ -116,6 +116,7 @@
<string name="common_go_to_provider">Перейти до провайдера</string>
<string name="common_go_to_token">Перейти до токену</string>
<string name="common_import">Імпортувати</string>
<string name="common_in_progress">процесі</string>
<string name="common_later">Пізніше</string>
<string name="common_locked">Заблокований</string>
<string name="common_main_network">Основна мережа</string>
@ -397,7 +398,7 @@
<string name="markets_token_details_low">Низький</string>
<string name="markets_token_details_market_capitalization">Ринкова капіталізація</string>
<string name="markets_token_details_market_capitalization_description">Загальна ринкова вартість криптовалюти, що розраховується шляхом множення поточної ціни монети на загальну кількість монет в обігу</string>
<string name="markets_token_details_market_rating">Рейтинг ринку</string>
<string name="markets_token_details_market_rating">Рейтинг</string>
<string name="markets_token_details_market_rating_description">Позиція в крипторейтингу між усіма монетами на основі ринкової капіталізації</string>
<string name="markets_token_details_max_supply">Максимальна пропозиція</string>
<string name="markets_token_details_metrics">Метрики</string>
@ -722,7 +723,6 @@
<string name="swapping_high_price_impact_description">Обмін цієї кількості обраних токенів призведе до значного впливу на ціну і зменшить вашу кінцеву суму.</string>
<string name="swapping_insufficient_funds">Недостатньо коштів</string>
<string name="swapping_permission_header">Надати дозвіл</string>
<string name="swapping_success_view_title">В процесі</string>
<string name="swapping_swap_action">Обміняти</string>
<string name="swapping_to_title">Ви отримаєте</string>
<string name="swapping_token_list_title">Оберіть токен</string>

View file

@ -58,6 +58,7 @@
<string name="common_enabled">啟用</string>
<string name="common_error">錯誤</string>
<string name="common_import">導入</string>
<string name="common_in_progress">進行中</string>
<string name="common_network_fee_title">網路費</string>
<string name="common_no"></string>
<string name="common_ok">OK</string>
@ -271,7 +272,6 @@
<string name="swapping_high_price_impact_description">在此代幣交換的數量將對價格產生重大影響,並降低您收到的數量</string>
<string name="swapping_insufficient_funds">餘額不足</string>
<string name="swapping_permission_header">賦予權限</string>
<string name="swapping_success_view_title">進行中</string>
<string name="swapping_swap_action">交易</string>
<string name="swapping_token_list_title">選擇代幣</string>
<string name="swapping_token_not_available">無法使用</string>

View file

@ -116,6 +116,7 @@
<string name="common_go_to_provider">Go to provider</string>
<string name="common_go_to_token">Go to token</string>
<string name="common_import">Import</string>
<string name="common_in_progress">In progress</string>
<string name="common_later">Later</string>
<string name="common_left">%1$s left</string>
<string name="common_locked">Locked</string>
@ -396,7 +397,7 @@
<string name="markets_token_details_liquidity_description">The change in how much liquidity is available for the token during the specified timeframe</string>
<string name="markets_token_details_liquidity_index">Liquidity index</string>
<string name="markets_token_details_low">Low</string>
<string name="markets_token_details_market_capitalization">Market capitalization</string>
<string name="markets_token_details_market_capitalization">Market cap</string>
<string name="markets_token_details_market_capitalization_description">The total market value of a cryptocurrency, calculated by multiplying the current price of the coin by the total number of coins in circulation</string>
<string name="markets_token_details_market_rating">Market rating</string>
<string name="markets_token_details_market_rating_description">Position in crypto rating between all coins based on market capitalization</string>
@ -666,15 +667,15 @@
<string name="staking_locked">Locked</string>
<string name="staking_migrate">Migrate</string>
<string name="staking_native">Native staking</string>
<string name="staking_notification_claim_rewards_text">Earned rewards are sent directly to your address. Once claimed, the funds are available for use.</string>
<string name="staking_notification_claim_rewards_text">Earned rewards will be sent to your wallet and available for use immediately</string>
<string name="staking_notification_earn_rewards_text_period_day">Staking allows you to earn %1$s. Your staking rewards arrive every day.</string>
<string name="staking_notification_earn_rewards_text_period_hour">Staking allows you to earn %1$s. Your staking rewards arrive every hour.</string>
<string name="staking_notification_earn_rewards_text_period_month">Staking allows you to earn %1$s. Your staking rewards arrive every month.</string>
<string name="staking_notification_earn_rewards_text_period_week">Staking allows you to earn %1$s. Your staking rewards arrive every week.</string>
<string name="staking_notification_earn_rewards_title">Earn staking rewards</string>
<string name="staking_notification_restake_rewards_text">Reinvests your earned rewards in your staked amount, increasing potential earnings.</string>
<string name="staking_notification_unstake_text">Rewards stop accruing immediately after you start unstaking. The unstaking process takes %s.</string>
<string name="staking_notification_withdraw_text">Your funds have been unstaked. You can now withdraw them along with your earned rewards.</string>
<string name="staking_notification_unstake_text">Your funds will be available for use after the %s unbonding period.</string>
<string name="staking_notification_withdraw_text">You can now withdraw your funds, it will be available to use immediatly</string>
<string name="staking_preparing">Preparing</string>
<string name="staking_ready_to_withdraw">Ready to withdraw</string>
<string name="staking_rebond">Rebond</string>
@ -700,6 +701,7 @@
<string name="staking_tap_to_withdraw">Tap to withdraw</string>
<string name="staking_title_stake">Stake %s</string>
<string name="staking_title_unstake">Unstake %s</string>
<string name="staking_transaction_in_progress_text">The transaction is being processed! Validation is currently underway in the blockchain. This may take a few minutes.</string>
<string name="staking_unbonding">Unbonding</string>
<string name="staking_unlocked_locked">Unlock locked</string>
<string name="staking_unstaked">Unstaked</string>
@ -734,7 +736,6 @@
<string name="swapping_high_price_impact_description">Swapping this amount of selected tokens will cause a significant price impact and reduce your outcome.</string>
<string name="swapping_insufficient_funds">Insufficient funds</string>
<string name="swapping_permission_header">Give Permission</string>
<string name="swapping_success_view_title">In progress</string>
<string name="swapping_swap_action">Swap</string>
<string name="swapping_to_title">You receive</string>
<string name="swapping_token_list_title">Choose token</string>

View file

@ -1,7 +1,6 @@
package com.tangem.core.ui.components.transactions
import android.content.res.Configuration
import androidx.annotation.StringRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
@ -13,22 +12,24 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.R
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.core.ui.res.TangemThemePreview
/**
* Common transaction done screen title
*
* @param titleRes title resource
* @param date transaction timestamp in millis
* @param title title resource
* @param subtitle subtitle text
*/
@Composable
fun TransactionDoneTitle(@StringRes titleRes: Int, date: Long, modifier: Modifier = Modifier) {
fun TransactionDoneTitle(title: TextReference, subtitle: TextReference, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxWidth(),
@ -41,20 +42,17 @@ fun TransactionDoneTitle(@StringRes titleRes: Int, date: Long, modifier: Modifie
.size(TangemTheme.dimens.size64),
)
Text(
text = stringResource(id = titleRes),
text = title.resolveReference(),
style = TangemTheme.typography.h3,
color = TangemTheme.colors.text.primary1,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing16),
)
Text(
text = stringResource(
id = R.string.send_date_format,
date.toTimeFormat(DateTimeFormatters.dateFormatter),
date.toTimeFormat(),
),
text = subtitle.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing4),
)
@ -68,8 +66,8 @@ fun TransactionDoneTitle(@StringRes titleRes: Int, date: Long, modifier: Modifie
private fun TransactionDoneTitlePreview() {
TangemThemePreview {
TransactionDoneTitle(
titleRes = R.string.sent_transaction_sent_title,
date = 0,
title = resourceReference(R.string.sent_transaction_sent_title),
subtitle = stringReference("0"),
modifier = Modifier
.background(TangemTheme.colors.background.tertiary)
.padding(TangemTheme.dimens.spacing16),

View file

@ -25,6 +25,13 @@ sealed class YieldBalance {
.filter { it.type == BalanceType.REWARDS }
.sumOf { it.amount }
}
fun getValidatorsCount(): Int {
return balance.items
.filterNot { it.validatorAddress.isNullOrBlank() }
.distinctBy { it.validatorAddress }
.size
}
}
data object Empty : YieldBalance()

View file

@ -77,4 +77,9 @@ sealed class TokenScreenAnalyticsEvent(
event = "Button - Token Trustline",
params = mapOf("Token" to tokenSymbol, "Blockchain" to blockchain),
)
data class StakingClicked(val token: String) : TokenScreenAnalyticsEvent(
event = "Staking Clicked",
params = mapOf("Token" to token),
)
}

View file

@ -26,8 +26,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.tangem.common.ui.amountScreen.ui.AmountBlock
import com.tangem.core.ui.components.transactions.TransactionDoneTitle
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.features.send.impl.R
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.state.previewdata.ConfirmStatePreviewData
@ -69,8 +73,14 @@ private fun LazyListScope.blocks(uiState: SendUiState) {
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing12),
) {
TransactionDoneTitle(
titleRes = R.string.sent_transaction_sent_title,
date = timestamp,
title = resourceReference(R.string.sent_transaction_sent_title),
subtitle = resourceReference(
R.string.send_date_format,
wrappedList(
timestamp.toTimeFormat(DateTimeFormatters.dateFormatter),
timestamp.toTimeFormat(),
),
),
)
}
RecipientBlock(

View file

@ -0,0 +1,157 @@
package com.tangem.features.staking.impl.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
internal sealed class StakingAnalyticsEvents(
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent(
category = "Staking",
event = event,
params = params,
) {
data class StakingInfoScreenOpened(
val validatorsCount: Int,
val token: String,
) : StakingAnalyticsEvents(
event = "Staking Info Screen Opened",
params = mapOf(
"Validators Count" to validatorsCount.toString(),
AnalyticsParam.TOKEN_PARAM to token,
),
)
data class WhatIsStaking(val token: String) : StakingAnalyticsEvents(
event = "Link - What Is Staking",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
),
)
data class AmountScreenOpened(val token: String) : StakingAnalyticsEvents(
event = "Amount Screen Opened",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
),
)
data class ConfirmationScreenOpened(
val token: String,
val validator: String,
val action: StakingActionType,
) : StakingAnalyticsEvents(
event = "Confirmation Screen Opened",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
"Validator" to validator,
"Action" to action.name,
),
)
data class StakeInProgressScreenOpened(
val validator: String,
val token: String,
) : StakingAnalyticsEvents(
event = "Stake In Progress Screen Opened",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
"Validator" to validator,
),
)
data class RewardScreenOpened(val token: String) : StakingAnalyticsEvents(
event = "Reward Screen Opened",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
),
)
data class AmountSelectCurrency(
val token: String,
val isAppCurrency: Boolean,
) : StakingAnalyticsEvents(
event = "Selected Currency",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
AnalyticsParam.TYPE to if (isAppCurrency) "App Currency" else "Token",
),
)
data class ButtonMax(val token: String) : StakingAnalyticsEvents(
event = "Button - Max",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
),
)
data class ButtonCancel(
val source: StakeScreenSource,
val token: String,
) : StakingAnalyticsEvents(
event = "Button - Cancel",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
AnalyticsParam.SOURCE to source.name,
),
)
data class ButtonValidator(
val source: StakeScreenSource,
val token: String,
) : StakingAnalyticsEvents(
event = "Button - Validator",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
AnalyticsParam.SOURCE to source.name,
),
)
data class ButtonRewards(
val token: String,
) : StakingAnalyticsEvents(
event = "Button - Rewards",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
),
)
data class ButtonAction(
val action: String,
val token: String,
val validator: String,
) : StakingAnalyticsEvents(
event = "Button - $action",
params = mapOf(
AnalyticsParam.TOKEN_PARAM to token,
"Validator" to validator,
),
)
data object ButtonShare : StakingAnalyticsEvents(event = "Button - Share")
data object ButtonExplore : StakingAnalyticsEvents(event = "Button - Explore")
data class StakingError(
val token: String,
) : StakingAnalyticsEvents(
event = "Errors",
params = mapOf(AnalyticsParam.TOKEN_PARAM to token),
)
data class TransactionError(
val token: String,
) : StakingAnalyticsEvents(
event = "Error - Transaction Rejected",
params = mapOf(AnalyticsParam.TOKEN_PARAM to token),
)
}
enum class StakeScreenSource {
Info,
Amount,
Confirmation,
Validators,
}

View file

@ -0,0 +1,104 @@
package com.tangem.features.staking.impl.analytics.utils
import com.tangem.common.ui.bottomsheet.permission.state.ApproveType
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.staking.impl.analytics.StakeScreenSource
import com.tangem.features.staking.impl.analytics.StakingAnalyticsEvents
import com.tangem.features.staking.impl.presentation.state.*
internal class StakingAnalyticSender(
private val analyticsEventHandler: AnalyticsEventHandler,
) {
fun initialInfoScreen(value: StakingUiState) {
val initialInfoState = value.initialInfoState as? StakingStates.InitialInfoState.Data
val validatorState = initialInfoState?.yieldBalance as? InnerYieldBalanceState.Data
val validatorCount = validatorState?.balance
?.filterNot { it.validator?.address.isNullOrBlank() }
?.distinctBy { it.validator?.address }
?.size ?: 0
analyticsEventHandler.send(
StakingAnalyticsEvents.StakingInfoScreenOpened(
validatorsCount = validatorCount,
token = value.cryptoCurrencySymbol,
),
)
}
fun confirmationScreen(value: StakingUiState) {
val confirmationState = value.confirmationState as? StakingStates.ConfirmationState.Data
val validatorState = confirmationState?.validatorState as? ValidatorState.Content
val validatorName = validatorState?.chosenValidator?.name ?: return
if (confirmationState.innerState == InnerConfirmationStakingState.COMPLETED) return
analyticsEventHandler.send(
StakingAnalyticsEvents.ConfirmationScreenOpened(
token = value.cryptoCurrencySymbol,
validator = validatorName,
action = when (value.actionType) {
StakingActionCommonType.ENTER -> StakingActionType.STAKE
StakingActionCommonType.EXIT -> StakingActionType.UNSTAKE
StakingActionCommonType.PENDING_REWARDS,
StakingActionCommonType.PENDING_OTHER,
-> confirmationState.pendingAction?.type ?: StakingActionType.UNKNOWN
},
),
)
}
fun screenCancel(value: StakingUiState) {
analyticsEventHandler.send(
StakingAnalyticsEvents.ButtonCancel(
source = when (value.currentStep) {
StakingStep.InitialInfo -> StakeScreenSource.Info
StakingStep.Amount -> StakeScreenSource.Amount
StakingStep.Confirmation -> StakeScreenSource.Confirmation
StakingStep.Validators,
StakingStep.RewardsValidators,
-> StakeScreenSource.Validators
},
token = value.cryptoCurrencyName,
),
)
}
fun sendTransactionApprovalAnalytics(tokenCryptoCurrency: CryptoCurrency) {
analyticsEventHandler.send(
Basic.TransactionSent(
sentFrom = AnalyticsParam.TxSentFrom.Approve(
blockchain = tokenCryptoCurrency.network.name,
token = tokenCryptoCurrency.symbol,
feeType = AnalyticsParam.FeeType.Normal,
permissionType = ApproveType.LIMITED.name,
),
memoType = Basic.TransactionSent.MemoType.Null,
),
)
}
fun sendTransactionStakingAnalytics(cryptoCurrency: CryptoCurrency, validator: String) {
analyticsEventHandler.send(
Basic.TransactionSent(
sentFrom = AnalyticsParam.TxSentFrom.Staking(
blockchain = cryptoCurrency.network.name,
token = cryptoCurrency.symbol,
feeType = AnalyticsParam.FeeType.Normal,
),
memoType = Basic.TransactionSent.MemoType.Null,
),
)
analyticsEventHandler.send(
StakingAnalyticsEvents.StakeInProgressScreenOpened(
validator = validator,
token = cryptoCurrency.symbol,
),
)
}
}

View file

@ -54,6 +54,7 @@ internal class StakingFragment : ComposeFragment() {
StakingStateRouter(
appRouter = appRouter,
stateController = stateController,
analyticsEventsHandler = analyticsEventsHandler,
),
)
}

View file

@ -68,6 +68,7 @@ internal class StakingStateController @Inject constructor(
clickIntents = StakingClickIntentsStub,
walletName = "",
cryptoCurrencyName = "",
cryptoCurrencySymbol = "",
currentStep = StakingStep.InitialInfo,
initialInfoState = StakingStates.InitialInfoState.Empty(),
amountState = AmountState.Empty(),

View file

@ -1,14 +1,21 @@
package com.tangem.features.staking.impl.presentation.state
import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
import com.tangem.features.staking.impl.analytics.StakingAnalyticsEvents
import com.tangem.features.staking.impl.analytics.utils.StakingAnalyticSender
internal class StakingStateRouter(
private val appRouter: AppRouter,
private val stateController: StakingStateController,
private val analyticsEventsHandler: AnalyticsEventHandler,
) {
private val analyticSender = StakingAnalyticSender(analyticsEventsHandler)
fun onBackClick() {
analyticSender.screenCancel(stateController.value)
appRouter.pop()
stateController.clear()
}
@ -48,14 +55,21 @@ internal class StakingStateRouter(
}
private fun showInitial() {
analyticSender.initialInfoScreen(stateController.value)
stateController.update { it.copy(currentStep = StakingStep.InitialInfo) }
}
fun showRewardsValidators() {
private fun showRewardsValidators() {
analyticsEventsHandler.send(
StakingAnalyticsEvents.RewardScreenOpened(stateController.value.cryptoCurrencySymbol),
)
stateController.update { it.copy(currentStep = StakingStep.RewardsValidators) }
}
fun showAmount() {
private fun showAmount() {
analyticsEventsHandler.send(
StakingAnalyticsEvents.AmountScreenOpened(stateController.value.cryptoCurrencySymbol),
)
stateController.update { it.copy(currentStep = StakingStep.Amount) }
}
@ -63,7 +77,8 @@ internal class StakingStateRouter(
stateController.update { it.copy(currentStep = StakingStep.Validators) }
}
fun showConfirmation() {
private fun showConfirmation() {
analyticSender.confirmationScreen(stateController.value)
stateController.update { it.copy(currentStep = StakingStep.Confirmation) }
}
}

View file

@ -27,6 +27,7 @@ internal data class StakingUiState(
val clickIntents: StakingClickIntents,
val walletName: String,
val cryptoCurrencyName: String,
val cryptoCurrencySymbol: String,
val currentStep: StakingStep,
val initialInfoState: StakingStates.InitialInfoState,
val amountState: AmountState,

View file

@ -69,4 +69,6 @@ internal object StakingClickIntentsStub : StakingClickIntents {
override fun onNotificationCancel(notification: Class<out NotificationUM>) {}
override fun openTokenDetails(cryptoCurrency: CryptoCurrency) {}
override fun onActiveStakeAnalytic() {}
}

View file

@ -104,7 +104,9 @@ internal class AddStakingNotificationsTransformer(
return prevState.copy(
confirmationState = confirmationState.copy(
notifications = notifications.toImmutableList(),
isPrimaryButtonEnabled = notifications.any { it is StakingNotification.Error },
isPrimaryButtonEnabled = notifications.none {
it is StakingNotification.Error || it is NotificationUM.Error
},
),
)
}

View file

@ -56,16 +56,19 @@ internal class SetInitialDataStateTransformer(
}
private val yieldBalancesConverter by lazy(LazyThreadSafetyMode.NONE) {
YieldBalancesConverter(cryptoCurrencyStatusProvider, appCurrencyProvider, yield)
YieldBalancesConverter(
cryptoCurrencyStatusProvider,
appCurrencyProvider,
yield,
)
}
override fun transform(prevState: StakingUiState): StakingUiState {
val cryptoCurrencyName = cryptoCurrencyStatusProvider().currency.name
val cryptoCurrency = cryptoCurrencyStatusProvider().currency
return prevState.copy(
title = TextReference.EMPTY,
walletName = userWalletProvider.invoke().name,
cryptoCurrencyName = cryptoCurrencyName,
cryptoCurrencyName = cryptoCurrency.name,
cryptoCurrencySymbol = cryptoCurrency.symbol,
clickIntents = clickIntents,
currentStep = StakingStep.InitialInfo,
initialInfoState = createInitialInfoState(),

View file

@ -9,13 +9,13 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData
import com.tangem.common.ui.amountScreen.ui.AmountBlock
import com.tangem.core.ui.components.transactions.TransactionDoneTitle
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
@ -52,10 +52,9 @@ internal fun StakingConfirmationContent(
visible = doneState is TransactionDoneState.Content,
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing12),
) {
val transactionDoneStateContent = remember(this) { doneState as TransactionDoneState.Content }
TransactionDoneTitle(
titleRes = R.string.sent_transaction_sent_title,
date = transactionDoneStateContent.timestamp,
title = resourceReference(R.string.common_in_progress),
subtitle = resourceReference(R.string.staking_transaction_in_progress_text),
)
}
AmountBlock(

View file

@ -173,8 +173,9 @@ private fun LazyListScope.activeStakingBlock(
) { balance ->
ActiveStakingBlock(
balance = balance,
onClick = clickIntents::onActiveStake,
isBalanceHidden = isBalanceHidden,
onClick = clickIntents::onActiveStake,
onAnalytic = clickIntents::onActiveStakeAnalytic,
modifier = Modifier
.animateItemPlacement()
.then(
@ -268,8 +269,9 @@ private fun StakingRewardBlock(
@Composable
private fun ActiveStakingBlock(
balance: BalanceState,
onClick: (BalanceState) -> Unit,
isBalanceHidden: Boolean,
onClick: (BalanceState) -> Unit,
onAnalytic: () -> Unit,
modifier: Modifier = Modifier,
) {
val (icon, iconTint) = balance.type.getIcon()
@ -287,7 +289,10 @@ private fun ActiveStakingBlock(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(),
enabled = balance.isClickable,
onClick = { onClick(balance) },
onClick = {
onAnalytic()
onClick(balance)
},
),
)
}

View file

@ -55,10 +55,9 @@ internal fun StakingFeeBlock(feeState: FeeState, isTransactionSent: Boolean) {
when (feeState) {
is FeeState.Content -> {
val feeAmount = feeState.fee?.amount
val (title, icon) = R.string.common_fee_selector_option_market to R.drawable.ic_bird_24
SelectorRowItem(
titleRes = title,
iconRes = icon,
titleRes = R.string.common_fee_selector_option_market,
iconRes = R.drawable.ic_bird_24,
preDot = stringReference(
BigDecimalFormatter.formatCryptoFeeAmount(
cryptoAmount = feeAmount?.value,
@ -80,9 +79,19 @@ internal fun StakingFeeBlock(feeState: FeeState, isTransactionSent: Boolean) {
)
}
is FeeState.Loading -> {
SelectorRowItem(
titleRes = R.string.common_fee_selector_option_market,
iconRes = R.drawable.ic_bird_24,
paddingValues = PaddingValues(),
)
FeeLoading(feeState)
}
is FeeState.Error -> {
SelectorRowItem(
titleRes = R.string.common_fee_selector_option_market,
iconRes = R.drawable.ic_bird_24,
paddingValues = PaddingValues(),
)
FeeError(feeState)
}
}

View file

@ -39,6 +39,8 @@ internal interface StakingClickIntents : AmountScreenClickIntents {
fun onActiveStake(activeStake: BalanceState)
fun onActiveStakeAnalytic()
fun showApprovalBottomSheet()
fun onApprovalClick()

View file

@ -15,6 +15,7 @@ import com.tangem.common.routing.bundle.unbundle
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.haptic.VibratorHapticManager
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
@ -29,7 +30,9 @@ import com.tangem.domain.staking.*
import com.tangem.domain.staking.model.StakingApproval
import com.tangem.domain.staking.model.stakekit.PendingAction
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransactionType
@ -45,6 +48,9 @@ import com.tangem.domain.utils.convertToSdkAmount
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.staking.impl.analytics.StakeScreenSource
import com.tangem.features.staking.impl.analytics.StakingAnalyticsEvents
import com.tangem.features.staking.impl.analytics.utils.StakingAnalyticSender
import com.tangem.features.staking.impl.navigation.InnerStakingRouter
import com.tangem.features.staking.impl.presentation.state.*
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
@ -106,6 +112,7 @@ internal class StakingViewModel @Inject constructor(
private val getCurrencyCheckUseCase: GetCurrencyCheckUseCase,
private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase,
private val isAnyTokenStakedUseCase: IsAnyTokenStakedUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
@DelayedWork private val coroutineScope: CoroutineScope,
savedStateHandle: SavedStateHandle,
) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents {
@ -135,6 +142,8 @@ internal class StakingViewModel @Inject constructor(
private var userWallet: UserWallet by Delegates.notNull()
private var appCurrency: AppCurrency by Delegates.notNull()
private var isInitialInfoAnalyticSent: Boolean = false
private val stakingEventFactory: StakingEventFactory
get() = StakingEventFactory(
stateController = stateController,
@ -142,6 +151,10 @@ internal class StakingViewModel @Inject constructor(
onFailedTxEmailClick = ::onFailedTxEmailClick,
)
private val stakingAnalyticSender = StakingAnalyticSender(
analyticsEventHandler = analyticsEventHandler,
)
private var stakingApproval: StakingApproval = StakingApproval.Empty
private var isAmountSubtractAvailable: Boolean = false
private val allowanceTaskScheduler = SingleTaskScheduler<BigDecimal>()
@ -270,6 +283,7 @@ internal class StakingViewModel @Inject constructor(
),
).getOrElse {
Timber.e(it.toString())
analyticsEventHandler.send(StakingAnalyticsEvents.StakingError(value.cryptoCurrencyName))
stakingEventFactory.createStakingErrorAlert(it)
stateController.update(SetConfirmationStateResetAssentTransformer)
return@launch
@ -284,6 +298,7 @@ internal class StakingViewModel @Inject constructor(
transactionId = transaction.id,
).getOrElse {
Timber.e(it.toString())
analyticsEventHandler.send(StakingAnalyticsEvents.StakingError(value.cryptoCurrencyName))
stakingEventFactory.createStakingErrorAlert(it)
stateController.update(SetConfirmationStateResetAssentTransformer)
return@launch
@ -301,6 +316,7 @@ internal class StakingViewModel @Inject constructor(
fullTransactionsData = fullTransactionsData,
fee = fee,
pendingAction = confirmationState.pendingAction,
validator = validatorState.chosenValidator.name,
)
}
}
@ -326,6 +342,7 @@ internal class StakingViewModel @Inject constructor(
type = pendingAction?.type,
),
).getOrElse {
analyticsEventHandler.send(StakingAnalyticsEvents.StakingError(value.cryptoCurrencyName))
stateController.update(AddStakingErrorTransformer())
updateNotifications(GetFeeError.UnknownError)
return
@ -365,6 +382,7 @@ internal class StakingViewModel @Inject constructor(
updateNotifications()
},
ifLeft = {
analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencyName))
stateController.update(AddStakingErrorTransformer())
updateNotifications(it)
},
@ -405,6 +423,7 @@ internal class StakingViewModel @Inject constructor(
}
override fun onInitialInfoBannerClick() {
analyticsEventHandler.send(StakingAnalyticsEvents.WhatIsStaking(cryptoCurrencyStatus.currency.symbol))
innerRouter.openUrl(WHAT_IS_STAKING_ARTICLE_URL)
}
@ -425,26 +444,47 @@ internal class StakingViewModel @Inject constructor(
}
override fun onMaxValueClick() {
analyticsEventHandler.send(StakingAnalyticsEvents.ButtonMax(cryptoCurrencyStatus.currency.symbol))
stateController.update(AmountMaxValueStateTransformer(cryptoCurrencyStatus, yield))
}
override fun onCurrencyChangeClick(isFiat: Boolean) {
analyticsEventHandler.send(
StakingAnalyticsEvents.AmountSelectCurrency(cryptoCurrencyStatus.currency.symbol, isFiat),
)
stateController.update(AmountCurrencyChangeStateTransformer(cryptoCurrencyStatus, isFiat))
}
override fun openValidators() = stakingStateRouter.showValidators()
override fun openValidators() {
analyticsEventHandler.send(
StakingAnalyticsEvents.ButtonValidator(
source = StakeScreenSource.Confirmation,
token = cryptoCurrencyStatus.currency.symbol,
),
)
stakingStateRouter.showValidators()
}
override fun onValidatorSelect(validator: Yield.Validator) {
stateController.update(ValidatorSelectChangeTransformer(validator))
}
override fun openRewardsValidators() {
analyticsEventHandler.send(
StakingAnalyticsEvents.ButtonRewards(value.cryptoCurrencyName),
)
val rewardsValidators =
stateController.value.rewardsValidatorsState as? StakingStates.RewardsValidatorsState.Data
val rewards = rewardsValidators?.rewards
if (rewards != null && rewards.isSingleItem()) {
onActiveStake(rewards.first())
} else {
analyticsEventHandler.send(
StakingAnalyticsEvents.ButtonValidator(
source = StakeScreenSource.Info,
token = cryptoCurrencyStatus.currency.symbol,
),
)
onNextClick(actionTypeToOverwrite = StakingActionCommonType.PENDING_REWARDS)
}
}
@ -479,6 +519,15 @@ internal class StakingViewModel @Inject constructor(
}
}
override fun onActiveStakeAnalytic() {
analyticsEventHandler.send(
StakingAnalyticsEvents.ButtonValidator(
source = StakeScreenSource.Info,
token = cryptoCurrencyStatus.currency.symbol,
),
)
}
override fun showApprovalBottomSheet() {
stateController.update(
ShowApprovalBottomSheetTransformer(
@ -519,6 +568,7 @@ internal class StakingViewModel @Inject constructor(
).fold(
ifLeft = { error ->
Timber.e(error.toString())
analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencyName))
stateController.update(
SetConfirmationStateAssentApprovalTransformer(
appCurrencyProvider = Provider { appCurrency },
@ -540,6 +590,7 @@ internal class StakingViewModel @Inject constructor(
).fold(
ifLeft = { error ->
Timber.e(error.toString())
analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencyName))
stateController.update(
SetConfirmationStateAssentApprovalTransformer(
appCurrencyProvider = Provider { appCurrency },
@ -551,6 +602,7 @@ internal class StakingViewModel @Inject constructor(
stateController.update(SetConfirmationStateResetAssentTransformer)
},
ifRight = {
stakingAnalyticSender.sendTransactionApprovalAnalytics(tokenCryptoCurrency)
stateController.update(SetApprovalInProgressTransformer)
stateController.update(DismissBottomSheetStateTransformer())
awaitForAllowance(confirmationState.pendingAction)
@ -668,10 +720,10 @@ internal class StakingViewModel @Inject constructor(
}
override fun onExploreClick() {
analyticsEventHandler.send(StakingAnalyticsEvents.ButtonExplore)
val confirmationDataState = uiState.value.confirmationState as? StakingStates.ConfirmationState.Data
val transactionDoneState = confirmationDataState?.transactionDoneState as? TransactionDoneState.Content
val txUrl = transactionDoneState?.txUrl
if (txUrl != null) {
innerRouter.openUrl(txUrl)
}
@ -682,12 +734,11 @@ internal class StakingViewModel @Inject constructor(
val transactionDoneState = confirmationDataState?.transactionDoneState as? TransactionDoneState.Content
val txUrl = transactionDoneState?.txUrl
analyticsEventHandler.send(StakingAnalyticsEvents.ButtonShare)
if (txUrl != null) {
vibratorHapticManager.performOneTime(TangemHapticEffect.OneTime.Click)
stakingEventFactory.createShareDialog(txUrl = txUrl)
}
// TODO staking [REDACTED_TASK_KEY]
}
override fun onFailedTxEmailClick(errorMessage: String) {
@ -758,6 +809,17 @@ internal class StakingViewModel @Inject constructor(
.onEach { maybeStatus ->
maybeStatus.fold(
ifRight = { status ->
if (!isInitialInfoAnalyticSent) {
isInitialInfoAnalyticSent = true
val balances = status.value.yieldBalance as? YieldBalance.Data
analyticsEventHandler.send(
StakingAnalyticsEvents.StakingInfoScreenOpened(
validatorsCount = balances?.getValidatorsCount() ?: 0,
token = status.currency.symbol,
),
)
}
feeCryptoCurrencyStatus =
getFeePaidCryptoCurrencyStatusSyncUseCase(userWalletId, status).getOrNull()
cryptoCurrencyStatus = status
@ -816,14 +878,33 @@ internal class StakingViewModel @Inject constructor(
fullTransactionsData: List<FullTransactionData>,
fee: Fee,
pendingAction: PendingAction?,
validator: String,
) {
val cryptoCurrency = cryptoCurrencyStatus.currency
val action = when (value.actionType) {
StakingActionCommonType.ENTER -> StakingActionType.STAKE
StakingActionCommonType.EXIT -> StakingActionType.UNSTAKE
StakingActionCommonType.PENDING_REWARDS,
StakingActionCommonType.PENDING_OTHER,
-> pendingAction?.type
}
action?.let {
analyticsEventHandler.send(
StakingAnalyticsEvents.ButtonAction(
action = it.name,
token = value.cryptoCurrencyName,
validator = validator,
),
)
}
sendMultipleTransactionUseCase(
txsData = fullTransactionsData.map { it.tangemTransaction },
userWallet = userWallet,
network = cryptoCurrencyStatus.currency.network,
network = cryptoCurrency.network,
).fold(
ifLeft = { error ->
Timber.e(error.toString())
analyticsEventHandler.send(StakingAnalyticsEvents.StakingError(value.cryptoCurrencyName))
stateController.update(
SetConfirmationStateAssentTransformer(
appCurrencyProvider = Provider { appCurrency },
@ -836,6 +917,7 @@ internal class StakingViewModel @Inject constructor(
stateController.update(SetConfirmationStateResetAssentTransformer)
},
ifRight = { transactionHashes ->
stakingAnalyticSender.sendTransactionStakingAnalytics(cryptoCurrency, validator)
transactionsInProgress.clear()
submitHash(
transactionIds = fullTransactionsData.map { it.stakeKitTransaction.id },
@ -844,9 +926,8 @@ internal class StakingViewModel @Inject constructor(
scheduleUpdates()
val txUrl = getExplorerTransactionUrlUseCase(
txHash = transactionHashes.last(),
networkId = cryptoCurrencyStatus.currency.network.id,
networkId = cryptoCurrency.network.id,
).getOrElse { "" }
stateController.update(
SetConfirmationStateCompletedTransformer(
appCurrencyProvider = Provider { appCurrency },
@ -868,6 +949,7 @@ internal class StakingViewModel @Inject constructor(
transactionHash = transactionHash,
)
.onLeft {
analyticsEventHandler.send(StakingAnalyticsEvents.StakingError(value.cryptoCurrencyName))
saveUnsubmittedHashUseCase.invoke(
transactionId = transactionId,
transactionHash = transactionHash,

View file

@ -18,8 +18,12 @@ import com.tangem.core.ui.components.inputrow.InputRowDefault
import com.tangem.core.ui.components.inputrow.InputRowImage
import com.tangem.core.ui.components.transactions.TransactionDoneTitle
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.feature.swap.domain.models.domain.ExchangeProviderType
import com.tangem.feature.swap.models.SwapSuccessStateHolder
import com.tangem.feature.swap.presentation.R
@ -60,7 +64,16 @@ private fun SwapSuccessScreenContent(state: SwapSuccessStateHolder, padding: Pad
.background(TangemTheme.colors.background.secondary)
.padding(horizontal = TangemTheme.dimens.spacing16),
) {
TransactionDoneTitle(titleRes = R.string.swapping_success_view_title, date = state.timestamp)
TransactionDoneTitle(
title = resourceReference(R.string.common_in_progress),
subtitle = resourceReference(
R.string.send_date_format,
wrappedList(
state.timestamp.toTimeFormat(DateTimeFormatters.dateFormatter),
state.timestamp.toTimeFormat(),
),
),
)
SpacerH16()
InputRowImage(
title = TextReference.Res(R.string.swapping_from_title),

View file

@ -466,6 +466,7 @@ internal class TokenDetailsViewModel @Inject constructor(
}
override fun onStakeBannerClick() {
analyticsEventsHandler.send(TokenScreenAnalyticsEvent.StakingClicked(cryptoCurrency.symbol))
openStaking()
}