Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-18 17:00:05 +05:00
commit f08991988d
16 changed files with 722 additions and 8 deletions

View file

@ -50,7 +50,6 @@
<string name="app_settings_theme_selector_title">Thème</string>
<string name="app_settings_title">Paramètres de l\'application</string>
<string name="backup_complete_seed_description">Ces mots ne peuvent pas être récupérés en cas de perte. Assurez-vous de les conserver en lieu sûr.</string>
<string name="backup_seed_caution">Ne partagez jamais ces mots. Quiconque les apprend peut voler toutes vos cryptomonnaies. Tangem ne vous les demandera jamais. Les %s mots ci-dessous constituent la phrase de récupération de votre portefeuille. Cette phrase vous permet de récupérer votre portefeuille en cas de perte de votre appareil.</string>
<string name="balance_hidden_description">Pour masquer ou afficher vos soldes, il suffit de retourner l\'écran de votre appareil vers le bas ou de le désactiver dans les paramètres</string>
<string name="balance_hidden_do_not_show_button">Ne plus afficher</string>
<string name="balance_hidden_got_it_button">Compris</string>
@ -118,6 +117,7 @@
<string name="common_close">Fermer</string>
<string name="common_confirm">Confirmez</string>
<string name="common_continue">Continuer</string>
<string name="common_convert">Convertir</string>
<string name="common_copy">Copier</string>
<string name="common_copy_address">Copier l\'adresse</string>
<string name="common_create">Créer</string>
@ -702,6 +702,11 @@
<string name="organize_tokens_sort_by_balance">Par solde</string>
<string name="organize_tokens_title">Organiser les jetons</string>
<string name="organize_tokens_ungroup">Dégrouper</string>
<string name="push_notifications_more_info">Plus d\'infos</string>
<string name="push_notifications_permission_alert_description">Vous pouvez activer les notifications pour Tangem dans les paramètres.</string>
<string name="push_notifications_permission_alert_negative_button">Activer plus tard</string>
<string name="push_notifications_permission_alert_positive_button">Paramètres</string>
<string name="push_notifications_permission_alert_title">Activer les notifications</string>
<string name="push_transactions_notifications_description">Recevez des alertes pour les transactions entrantes sur les réseaux pris en charge.</string>
<string name="qr_scanner_camera_denied_gallery_button">Sélectionnez dans la galerie</string>
<string name="qr_scanner_camera_denied_settings_button">Paramètres</string>
@ -775,7 +780,9 @@
<string name="send_alert_fee_too_low_text">Vous avez spécifié une commission inférieure au montant recommandé, ce qui pourrait entraîner un retard dans votre transaction. Continuer?</string>
<string name="send_alert_transaction_failed_text">Raison : %1$s\nCode : %2$s</string>
<string name="send_alert_transaction_failed_title">La transaction est incomplète</string>
<string name="send_amount_convert_to_another_token">Convertir en un autre jeton</string>
<string name="send_amount_label">Montant</string>
<string name="send_amount_receive_token_subtitle">Sera envoyé au destinataire</string>
<string name="send_bitcoin_custom_fee_footer">Vous pouvez définir vos frais de transaction en ajustant la valeur dans le champ Satoshi par vByte.</string>
<string name="send_custom_amount_fee_footer">Les frais qui seront facturés pour votre transaction. Vous pouvez définir votre propre valeur.</string>
<string name="send_custom_evm_max_fee">Frais maximum</string>
@ -799,6 +806,7 @@
<string name="send_fee_unreachable_error_text">Vérifiez votre connexion réseau</string>
<string name="send_fee_unreachable_error_title">Informations sur les frais de réseau inaccessibles</string>
<string name="send_from_wallet_android">De</string>
<string name="send_from_wallet_name">De %s</string>
<string name="send_gas_limit">Limite de gaz</string>
<string name="send_gas_limit_footer">Il s\'agit du montant maximal de gaz qui sera dépensé pour effectuer une transaction ou un contrat. Une limite de gaz empêche des frais imprévus ou illimités lors de l\'exécution d\'une transaction.</string>
<string name="send_gas_price">Prix du gaz</string>
@ -806,6 +814,7 @@
<string name="send_max_amount">Max</string>
<string name="send_max_amount_label">Somme maximale</string>
<string name="send_max_fee">Frais jusqu\'à</string>
<string name="send_memo">Mémo : %s</string>
<string name="send_memo_destination_tag_error">Mémo invalide</string>
<string name="send_network_fee_warning_title">Couverture des frais de réseau</string>
<string name="send_notification_exceed_balance_text">Fonds insuffisants pour le transfert, car le total des frais et du montant du transfert dépasse le solde existant</string>
@ -816,6 +825,7 @@
<string name="send_notification_fee_too_high_title">Les frais de douane sont élevés</string>
<string name="send_notification_high_fee_text">En raison des particularités du réseau %1$s, les frais de transfert de la totalité du solde sont plus élevés. Pour réduire la commission, vous pouvez en laisser %2$s.</string>
<string name="send_notification_high_fee_title">Les frais sont plus élevés</string>
<string name="send_notification_invalid_amount_rent_destination">Le compte du bénéficiaire n\'est pas activé. Le montant minimum du transfert doit être égal ou supérieur au solde exonéré de loyer : %1$s.</string>
<string name="send_notification_invalid_amount_rent_fee">Le solde de votre compte ne peut pas être inférieur au montant du loyer. Veuillez conserver au moins %1$s sur votre compte ou retirer tous les fonds.</string>
<string name="send_notification_invalid_amount_text">La commission incluse dépasse le montant du transfert, ce qui entraîne une valeur négative</string>
<string name="send_notification_invalid_amount_title">Montant invalide</string>
@ -835,6 +845,7 @@
<string name="send_recipient">Destinataire</string>
<string name="send_recipient_address_error">Adresse non valide</string>
<string name="send_recipient_address_footer">Assurez-vous que l\'adresse du portefeuille de réception est sur le réseau %s pour éviter de perdre vos jetons</string>
<string name="send_recipient_address_footer_highlighted_part">envoyer à %s</string>
<string name="send_recipient_label">Envoyer à</string>
<string name="send_recipient_memo_footer">Un Memo/Destination Tag est un identifiant unique permettant de différencier les transactions envoyées au même destinataire sur le même réseau. Attention : L\'omission d\'un mémo peut entraîner des fonds mal placés</string>
<string name="send_recipient_memo_footer_v2">Le Memo / Destination Tag est un code qui distingue les transactions envoyées à un destinataire partagé sur un réseau crypto.</string>
@ -851,6 +862,7 @@
<string name="send_summary_transaction_description_suffix_fee_covered">les frais de réseau seront couverts en utilisant %1$s énergie</string>
<string name="send_summary_transaction_description_suffix_fee_reduced">les frais de réseau seront réduits en utilisant %1$s énergie</string>
<string name="send_summary_transaction_description_suffix_including">y compris des frais de réseau de %1$s</string>
<string name="send_to_address">À l\'adresse</string>
<string name="send_transaction_success">La transaction a été signée avec succès et envoyée au nœud de blockchain. Le solde du portefeuille sera mis à jour après un certain temps</string>
<string name="send_tron_account_activation_error">%1$s est un actif du réseau Tron. Pour calculer les frais et effectuer une transaction, déposez du Tron (TRX) sur votre compte.</string>
<string name="send_validation_amount_exceeds_balance">Le montant dépasse le solde</string>
@ -860,6 +872,7 @@
<string name="send_validation_invalid_fee">Les frais de commissions dépassent le solde</string>
<string name="send_validation_invalid_total">Le total dépasse le solde</string>
<string name="send_with_swap_confirm_title">Échanger et envoyer</string>
<string name="send_with_swap_recipient_amount_title">Montant à recevoir</string>
<string name="sent_transaction_sent_title">Transaction envoyée</string>
<string name="settings_card_settings_footer">Scannez la carte/ bague que vous souhaitez configurer.</string>
<string name="settings_forget_wallet">Oublier le portefeuille</string>
@ -1013,6 +1026,7 @@
<string name="swap_story_second_title">Meilleurs Tarifs</string>
<string name="swap_story_third_subtitle">Simple et intuitif, vous permettant d\'échanger des jetons en quelques clics</string>
<string name="swap_story_third_title">Plus Simple Que Jamais</string>
<string name="swap_via_provider">Échange via le fournisseur</string>
<string name="swapping_alert_cex_description">Le montant comprend :\n• les frais du fournisseur de services\n• les frais de réseau pour l\'envoi de %s depuis l\'échange vers l\'adresse de l\'utilisateur.</string>
<string name="swapping_alert_cex_description_with_slippage">Le montant comprend :\n• les frais du fournisseur de services\n• les frais de réseau pour l\'envoi de %1$s depuis l\'échange vers l\'adresse de l\'utilisateur. \n\nLe slippage du fournisseur peut atteindre %2$s</string>
<string name="swapping_alert_dex_description">Le montant comprend les frais du fournisseur de services.</string>
@ -1164,6 +1178,7 @@
<string name="wallet_promo_banner_description">Accédez à plus de 13 000 cryptomonnaies. Achetez, vendez, échangez et stakez en un seul clic.\nAssociez jusqu\'à trois cartes pour une sauvegarde.</string>
<string name="wallet_promo_banner_title">Découvrez le Portefeuille Tangem</string>
<string name="wallet_settings_push_notifications_description">Recevez des notifications sur les transactions entrantes du portefeuille et les mises à jour de Tangem.</string>
<string name="wallet_settings_push_notifications_title">Notifications de transaction</string>
<string name="wallet_settings_title">Paramètres du portefeuille</string>
<string name="wallet_title">Tangem</string>
<string name="warning_access_denied_message">Utilisez %s ou scannez une carte/bague pour déverrouiller l\'accès à votre portefeuille</string>
@ -1255,6 +1270,7 @@
<string name="warning_testnet_card_title">À des fins de test uniquement</string>
<string name="warning_token_balance_not_updated">Le solde peut être obsolète. Rafraîchissez la page.</string>
<string name="wc_alert_audit_malicious_domain">Domaine malveillant</string>
<string name="wc_alert_unknown_error_description_no_error_code">Si le problème persiste, nhésitez pas à contacter notre support.</string>
<string name="wc_alert_unsupported_dapps_description">Le portefeuille Tangem ne prend actuellement pas en charge %ss</string>
<string name="wc_alert_unsupported_dapps_title">dApp non prise en charge</string>
<string name="wc_connections">Connexions</string>

View file

@ -1253,6 +1253,7 @@
<string name="warning_rate_app_message">Ваш отзыв мотивирует нас сделать кошелек Tangem еще лучше</string>
<string name="warning_rate_app_title">Нравится Tangem?</string>
<string name="warning_receive_blocked_hedera_token_association_required_message">Вам необходимо провести ассоциацию токена для того, чтобы иметь возможность принимать его</string>
<string name="warning_receive_blocked_token_trustline_required_message">Вы должны открыть трастлайн для своего токена, чтобы иметь возможность получить на него средства.</string>
<string name="warning_rent_fee_title">Необходима плата за аренду сети</string>
<string name="warning_seedphrase_action_required_title">Требуется действие</string>
<string name="warning_seedphrase_contacted_support">Вы обращались в службу поддержки через приложение в течение 7 дней после создания кошелька? Если обращались или не уверены, нажмите «Да» и следуйте инструкциям.</string>
@ -1268,26 +1269,71 @@
<string name="warning_some_networks_unreachable_message">Свайпните вниз для обновления или попробуйте позже.</string>
<string name="warning_some_networks_unreachable_title">Некоторые сети недоступны</string>
<string name="warning_some_token_balances_not_updated">Некоторые балансы токенов не удалось обновить</string>
<string name="warning_stellar_token_trustline_not_enough_xlm">Недостаточно %s. Пополните свой XLM аккаунт чтобы открыть трастлайн.</string>
<string name="warning_testnet_card_message">Это Testnet карта. Он не может обрабатывать транзакции и используется только в целях тестирования и разработки.</string>
<string name="warning_testnet_card_title">Только для целей тестирования</string>
<string name="warning_token_balance_not_updated">Возможно, баланс устарел. Обновите страницу.</string>
<string name="warning_token_trustline_button_title">Открыть Trustline</string>
<string name="warning_token_trustline_subtitle">Согласно правилам сети, чтобы пополнить этот токен, необходимо сначала открыть Trustline — это позволит вашему кошельку принимать и хранить этот актив.</string>
<string name="warning_token_trustline_title">Откройте Trustline</string>
<string name="warning_token_trustline_title">Требуется трастлайн</string>
<string name="wc_alert_audit_malicious_domain">Вредоносный домен</string>
<string name="wc_alert_audit_unknown_domain">Неизвестный домен</string>
<string name="wc_alert_connect_anyway">Подключиться всё равно</string>
<string name="wc_alert_connection_timeout_description">Ошибка тайм-аута. Пожалуйста, попробуйте позже.</string>
<string name="wc_alert_connection_timeout_title">Не удалось подключиться через Wallet Connect</string>
<string name="wc_alert_domain_issues_description">Этот домен не может быть верифицирован. Внимательно проверьте запрос перед одобрением.</string>
<string name="wc_alert_session_disconnected_description">Пожалуйста, вернитесь в браузер и выполните повторное подключение через WalletConnect.</string>
<string name="wc_alert_session_disconnected_title">Сессия Wallet Connect была завершена</string>
<string name="wc_alert_sign_anyway">Подписать всё равно</string>
<string name="wc_alert_unknown_error_description">Код ошибки: %s. Если проблема сохраняется, обратитесь в нашу службу поддержки.</string>
<string name="wc_alert_unknown_error_description_no_error_code">Если проблема сохраняется, обратитесь в нашу службу поддержки</string>
<string name="wc_alert_unknown_error_title">Мы обнаружили неизвестную ошибку</string>
<string name="wc_alert_unsupported_dapps_description">Кошелек Tangem.в настоящий момент не поддерживает %s</string>
<string name="wc_alert_unsupported_dapps_title">Неподдерживаемый dApp</string>
<string name="wc_alert_unsupported_method_title">Мы обнаружили неизвестную ошибку</string>
<string name="wc_alert_unsupported_networks_description">Tangem в настоящее время не поддерживает необходимую сеть для %s</string>
<string name="wc_alert_unsupported_networks_title">Неподдерживаемые сети</string>
<string name="wc_alert_verified_domain_description">Tangem поддерживает сеть, необходимую для %s</string>
<string name="wc_alert_verified_domain_title">Верифицированный домен</string>
<string name="wc_alert_wrong_card_description">Выбрана не верная карта или кольцо</string>
<string name="wc_alert_wrong_card_title">Похоже, возникла проблема</string>
<string name="wc_allow_to_spend">Разрешение на использование</string>
<string name="wc_common_address">Адрес</string>
<string name="wc_common_connect">Подключение</string>
<string name="wc_common_loading">Загрузка</string>
<string name="wc_common_network">Сеть</string>
<string name="wc_common_networks">Сети</string>
<string name="wc_common_unlimited">Безлимитно</string>
<string name="wc_common_wallet">Кошелек</string>
<string name="wc_connected_networks">Подключенные сети</string>
<string name="wc_connection_reqeust_can_view_balance">Посмотреть баланс кошелька и его активность</string>
<string name="wc_connection_reqeust_cant_sign">Подписать транзакцию без вашего участия</string>
<string name="wc_connection_reqeust_request_approval">Запрос разрешения на транзакцию</string>
<string name="wc_connection_reqeust_will_not">Не имеет возможности</string>
<string name="wc_connection_reqeust_would_like">Хотели бы</string>
<string name="wc_connection_request">Запрос на подключение</string>
<string name="wc_connections">Подключения</string>
<string name="wc_contents">Вложение</string>
<string name="wc_copy_data_button_text">Копировать данные</string>
<string name="wc_custom_allowance_title">Настраиваемый лимит</string>
<string name="wc_disconnect_all">Отключить все</string>
<string name="wc_disconnect_all_alert_title">Отключить все dApp</string>
<string name="wc_estimated_wallet_changes">Предварительные изменения</string>
<string name="wc_estimated_wallet_changes_not_simulated">Не удалось выполнить симуляцию транзакции. Пожалуйста, действуйте с осторожностью.</string>
<string name="wc_malicious_transaction">Вредоносная транзакция</string>
<string name="wc_missing_required_network_description">Добавьте сеть %s в ваш портфель для выбранного кошелька</string>
<string name="wc_missing_required_network_title">В кошельке не добавлены необходимые сети</string>
<string name="wc_new_connection">Новое подключение</string>
<string name="wc_no_sessions_desc">Подключите свой кошелек к различным dApp</string>
<string name="wc_no_sessions_title">Нет подключений</string>
<string name="wc_notification_security_risk_subtitle">Этот домен помечен как небезопасный несколькими поставщиками систем безопасности. Немедленно покиньте его, чтобы защитить свои активы.</string>
<string name="wc_notification_security_risk_title">Известный риск безопасности</string>
<string name="wc_request_from">Запрос от</string>
<string name="wc_signature_type">Тип подписи</string>
<string name="wc_transaction_info_to_title">На</string>
<string name="wc_transaction_request">Запрос транзакции</string>
<string name="wc_transaction_request_title">Запрос транзакции</string>
<string name="wc_unlimited_amount">Безлимитное количество</string>
<string name="wc_wallet_connect">Подключение кошелька</string>
<string name="welcome_interrupted_backup_alert_discard">Отказаться</string>
<string name="welcome_interrupted_backup_alert_message">Вы не закончили резервное копирование. Хотите продолжить?</string>

View file

@ -722,6 +722,9 @@
<string name="organize_tokens_title">Сортування токенів</string>
<string name="organize_tokens_ungroup">Список</string>
<string name="push_notifications_more_info">Більше</string>
<string name="push_notifications_permission_alert_description">Ви можете ввімкнути сповіщення у налаштуваннях</string>
<string name="push_notifications_permission_alert_negative_button">Увімкнути пізніше</string>
<string name="push_notifications_permission_alert_positive_button">Налаштування</string>
<string name="push_notifications_permission_alert_title">Увімкнути сповіщення</string>
<string name="push_transactions_notifications_description">Отримуйте сповіщення про вхідні транзакції в підтримуваних мережах.</string>
<string name="qr_scanner_camera_denied_gallery_button">Виберіть з галереї</string>

View file

@ -948,6 +948,7 @@
<string name="send_validation_invalid_total">Total amount exceeds balance</string>
<string name="send_with_swap_confirm_title">Swap and send</string>
<string name="send_with_swap_notification_text">Send any token, and well convert it on the way. Your recipient gets exactly what they need—seamlessly.</string>
<string name="send_with_swap_recipient_amount_success_title">Recipient will receive</string>
<string name="send_with_swap_recipient_amount_text">Will be sent a recipient</string>
<string name="send_with_swap_recipient_amount_title">Amount to receive</string>
<string name="send_with_swap_title">Send with swap</string>
@ -1427,7 +1428,7 @@
<string name="warning_some_networks_unreachable_message">Swipe down to refresh or try again later.</string>
<string name="warning_some_networks_unreachable_title">Some networks are unreachable</string>
<string name="warning_some_token_balances_not_updated">Some token balances could not be updated</string>
<string name="warning_stellar_token_trustline_not_enough_xlm">Not enough %s. Top up your XLM account to associate this token</string>
<string name="warning_stellar_token_trustline_not_enough_xlm">Not enough %s. Top up your XLM account to open trustline.</string>
<string name="warning_testnet_card_message">This is a Testnet card. It cannot process transactions and should only be used for testing and development purposes.</string>
<string name="warning_testnet_card_title">For testing purposes only</string>
<string name="warning_token_balance_not_updated">Balance may be outdated. Refresh the page.</string>
@ -1482,7 +1483,7 @@
<string name="wc_estimated_wallet_changes">Estimated wallet changes</string>
<string name="wc_estimated_wallet_changes_not_simulated">The transaction couldn\'t be simulated. Please proceed with caution.</string>
<string name="wc_malicious_transaction">Malicious transaction</string>
<string name="wc_missing_required_network_description">Add the %s network to your profile for this wallet</string>
<string name="wc_missing_required_network_description">Add the %s network to your portfolio for this wallet</string>
<string name="wc_missing_required_network_title">The wallet has no required networks</string>
<string name="wc_new_connection">New connection</string>
<string name="wc_no_sessions_desc">Connect your wallet to a different dApps</string>

View file

@ -14,4 +14,5 @@ object StringsSigns {
const val PERCENT = "%"
const val THREE_STARS = "\u2217\u2217\u2217"
const val PASSWORD_VISUAL_CHAR = '\u2022'
const val APPROXIMATE = ""
}

View file

@ -250,6 +250,7 @@ internal class SwapAmountModel @Inject constructor(
.onEach { currency ->
uiState.update { amountUM ->
if (amountUM is SwapAmountUM.Content) {
initPairs(currency)
amountUM.copy(
isPrimaryButtonEnabled = false,
secondaryAmount = SwapAmountFieldUM.Loading(
@ -260,7 +261,6 @@ internal class SwapAmountModel @Inject constructor(
amountUM
}
}
initPairs(currency)
}
.launchIn(modelScope)
}
@ -400,6 +400,7 @@ internal class SwapAmountModel @Inject constructor(
swapDirection = swapDirection,
allowanceContract = quote.allowanceContract,
isApprovalNeeded = checkAllowance(state, quote),
fromAmount = fromAmountValue,
).convert(
SwapQuoteUMConverter.Data(
quote = quote,

View file

@ -12,9 +12,13 @@ import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
import com.tangem.utils.extensions.isZero
import java.math.BigDecimal
import java.math.RoundingMode
import kotlin.math.min
internal object SwapAmountQuoteUtils {
private const val MAX_DECIMALS = 8
private const val MIN_DECIMALS = 2
fun calculatePriceImpact(
fromTokenAmount: BigDecimal,
toTokenAmount: BigDecimal,
@ -41,6 +45,11 @@ internal object SwapAmountQuoteUtils {
}
}
fun calculateRate(fromAmount: BigDecimal, toAmount: BigDecimal, toAmountDecimals: Int): BigDecimal {
val rateDecimals = if (toAmountDecimals == 0) MIN_DECIMALS else toAmountDecimals
return toAmount.divide(fromAmount, min(rateDecimals, MAX_DECIMALS), RoundingMode.HALF_UP)
}
fun SwapAmountUM.updateAmount(
onPrimaryAmount: SwapAmountFieldUM.Content.(CryptoCurrencyStatus) -> SwapAmountFieldUM,
onSecondaryAmount: SwapAmountFieldUM.Content.(CryptoCurrencyStatus) -> SwapAmountFieldUM,

View file

@ -1,14 +1,20 @@
package com.tangem.features.swap.v2.impl.amount.model.converter
import androidx.compose.ui.text.buildAnnotatedString
import com.tangem.core.ui.extensions.annotatedReference
import com.tangem.core.ui.extensions.appendSpace
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.format.bigdecimal.anyDecimals
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.express.models.ExpressProvider
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.swap.models.SwapDirection
import com.tangem.domain.swap.models.SwapQuoteModel
import com.tangem.features.swap.v2.impl.amount.model.SwapAmountQuoteUtils.calculateRate
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM.Content.DifferencePercent
import com.tangem.utils.StringsSigns
import com.tangem.utils.converter.Converter
import java.math.BigDecimal
@ -18,10 +24,24 @@ internal class SwapQuoteUMConverter(
private val isApprovalNeeded: Boolean,
private val primaryCurrency: CryptoCurrency,
private val secondaryCurrency: CryptoCurrency,
private val fromAmount: BigDecimal,
) : Converter<SwapQuoteUMConverter.Data, SwapQuoteUM> {
override fun convert(value: Data): SwapQuoteUM {
val (quote, provider) = value
val rate = calculateRate(
fromAmount = fromAmount,
toAmount = quote.toTokenAmount,
toAmountDecimals = secondaryCurrency.decimals,
)
val rateString = buildAnnotatedString {
append(BigDecimal.ONE.format { crypto(symbol = primaryCurrency.symbol, decimals = 0).anyDecimals() })
appendSpace()
append(StringsSigns.APPROXIMATE)
appendSpace()
append(rate.format { crypto(secondaryCurrency) })
}
return if (allowanceContract != null) {
if (isApprovalNeeded) {
SwapQuoteUM.Allowance(
@ -36,6 +56,7 @@ internal class SwapQuoteUMConverter(
quoteAmountValue = stringReference(
quote.toTokenAmount.toQuoteValue(),
),
rate = annotatedReference(rateString),
)
}
} else {
@ -46,6 +67,7 @@ internal class SwapQuoteUMConverter(
quoteAmountValue = stringReference(
quote.toTokenAmount.toQuoteValue(),
),
rate = annotatedReference(rateString),
)
}
}

View file

@ -5,6 +5,8 @@ import com.tangem.core.ui.components.atoms.text.TextEllipsis
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.express.models.ExpressProvider
import com.tangem.domain.express.models.ExpressProviderType
import com.tangem.domain.express.models.ExpressRateType
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
@ -16,10 +18,11 @@ import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountType
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import kotlinx.collections.immutable.persistentListOf
import java.math.BigDecimal
internal data object SwapAmountContentPreview {
private val cryptoCurrencyStatus = CryptoCurrencyStatus(
val cryptoCurrencyStatus = CryptoCurrencyStatus(
currency = CryptoCurrency.Coin(
id = CryptoCurrency.ID.fromValue("coin⟨BITCOIN⟩bitcoin"),
network = Network(
@ -41,12 +44,32 @@ internal data object SwapAmountContentPreview {
name = "Bitcoin",
symbol = "BTC",
decimals = 8,
iconUrl = "",
iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/medium/bitcoin.png",
isCustom = false,
),
value = CryptoCurrencyStatus.Loading,
)
private val provider = ExpressProvider(
providerId = "changenow",
rateTypes = listOf(ExpressRateType.Float),
name = "ChangeNow",
type = ExpressProviderType.CEX,
imageLarge = "",
termsOfUse = "",
privacyPolicy = "",
isRecommended = true,
slippage = BigDecimal.ZERO,
)
private val quote = SwapQuoteUM.Content(
provider = provider,
quoteAmount = "123".toBigDecimal(),
quoteAmountValue = stringReference("123"),
rate = stringReference("1 USD ≈ 123.123 POL"),
diffPercent = SwapQuoteUM.Content.DifferencePercent.Best,
)
val emptyState = SwapAmountUM.Content(
isPrimaryButtonEnabled = false,
primaryAmount = SwapAmountFieldUM.Empty(
@ -95,7 +118,7 @@ internal data object SwapAmountContentPreview {
selectedAmountType = SwapAmountType.From,
swapCurrencies = SwapCurrencies.EMPTY,
swapQuotes = persistentListOf(),
selectedQuote = SwapQuoteUM.Empty,
selectedQuote = quote,
primaryCryptoCurrencyStatus = cryptoCurrencyStatus,
secondaryCryptoCurrencyStatus = cryptoCurrencyStatus,
swapRateType = ExpressRateType.Float,

View file

@ -36,6 +36,7 @@ internal object SwapChooseProviderContentPreview {
provider = provider1,
quoteAmount = "123".toBigDecimal(),
quoteAmountValue = stringReference("123"),
rate = stringReference("1 USD ≈ 123.123 POL"),
diffPercent = SwapQuoteUM.Content.DifferencePercent.Best,
)
@ -43,6 +44,7 @@ internal object SwapChooseProviderContentPreview {
provider = provider2,
quoteAmount = "13.12".toBigDecimal(),
quoteAmountValue = stringReference("13.12"),
rate = stringReference("1 USD ≈ 12.123 POL"),
diffPercent = SwapQuoteUM.Content.DifferencePercent.Empty,
)

View file

@ -3,6 +3,8 @@ package com.tangem.features.swap.v2.impl.common.entity
import androidx.compose.runtime.Immutable
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.express.models.ExpressProvider
import com.tangem.domain.swap.models.SwapDataModel
import kotlinx.collections.immutable.ImmutableList
@Immutable
@ -18,6 +20,14 @@ internal sealed class ConfirmUM {
val notifications: ImmutableList<NotificationUM>,
) : ConfirmUM()
data class Success(
override val isPrimaryButtonEnabled: Boolean = true,
val transactionDate: Long,
val txUrl: String,
val swapDataModel: SwapDataModel,
val provider: ExpressProvider,
) : ConfirmUM()
data object Empty : ConfirmUM() {
override val isPrimaryButtonEnabled: Boolean = false
}

View file

@ -34,6 +34,7 @@ internal sealed class SwapQuoteUM {
val quoteAmount: BigDecimal,
val quoteAmountValue: TextReference,
val diffPercent: DifferencePercent,
val rate: TextReference,
) : SwapQuoteUM() {
sealed class DifferencePercent {
data object Empty : DifferencePercent()

View file

@ -0,0 +1,37 @@
package com.tangem.features.swap.v2.impl.sendviaswap.success
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.common.ui.navigationButtons.NavigationModelCallback
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.swap.v2.impl.sendviaswap.SendWithSwapRoute
import com.tangem.features.swap.v2.impl.sendviaswap.entity.SendWithSwapUM
import com.tangem.features.swap.v2.impl.sendviaswap.success.model.SendWithSwapSuccessModel
import com.tangem.features.swap.v2.impl.sendviaswap.success.ui.SendWithSwapSuccessContent
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
internal class SendWithSwapSuccessComponent(
appComponentContext: AppComponentContext,
params: Params,
) : ComposableContentComponent, AppComponentContext by appComponentContext {
private val model: SendWithSwapSuccessModel = getOrCreateModel(params = params)
@Composable
override fun Content(modifier: Modifier) {
val state by model.uiState.collectAsStateWithLifecycle()
SendWithSwapSuccessContent(sendWithSwapUM = state)
}
data class Params(
val sendWithSwapUMFlow: StateFlow<SendWithSwapUM>,
val analyticsCategoryName: String,
val currentRoute: Flow<SendWithSwapRoute.Success>,
val callback: NavigationModelCallback,
)
}

View file

@ -0,0 +1,20 @@
package com.tangem.features.swap.v2.impl.sendviaswap.success.di
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.core.decompose.model.Model
import com.tangem.features.swap.v2.impl.sendviaswap.success.model.SendWithSwapSuccessModel
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@Module
@InstallIn(ModelComponent::class)
internal interface SendWithSwapSuccessModule {
@Binds
@IntoMap
@ClassKey(SendWithSwapSuccessModel::class)
fun bindSendWithSwapSuccessModel(impl: SendWithSwapSuccessModel): Model
}

View file

@ -0,0 +1,81 @@
package com.tangem.features.swap.v2.impl.sendviaswap.success.model
import com.tangem.common.routing.AppRouter
import com.tangem.common.ui.navigationButtons.NavigationButton
import com.tangem.common.ui.navigationButtons.NavigationUM
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.swap.v2.impl.R
import com.tangem.features.swap.v2.impl.common.entity.ConfirmUM
import com.tangem.features.swap.v2.impl.sendviaswap.entity.SendWithSwapUM
import com.tangem.features.swap.v2.impl.sendviaswap.success.SendWithSwapSuccessComponent
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
@ModelScoped
internal class SendWithSwapSuccessModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
private val urlOpener: UrlOpener,
private val shareManager: ShareManager,
private val appRouter: AppRouter,
paramsContainer: ParamsContainer,
) : Model() {
private val params: SendWithSwapSuccessComponent.Params = paramsContainer.require()
val uiState: StateFlow<SendWithSwapUM> = params.sendWithSwapUMFlow
val confirmUM = uiState.value.confirmUM as? ConfirmUM.Success
init {
configConfirmSuccessNavigation()
}
private fun configConfirmSuccessNavigation() {
params.callback.onNavigationResult(
NavigationUM.Content(
title = TextReference.EMPTY,
subtitle = null,
backIconRes = R.drawable.ic_close_24,
backIconClick = appRouter::pop,
primaryButton = NavigationButton(
textReference = resourceReference(R.string.common_close),
iconRes = null,
isEnabled = true,
isHapticClick = false,
onClick = appRouter::pop,
),
prevButton = null,
secondaryPairButtonsUM = NavigationButton(
textReference = resourceReference(R.string.common_explore),
iconRes = R.drawable.ic_web_24,
onClick = ::onExploreClick,
) to NavigationButton(
textReference = resourceReference(R.string.common_share),
iconRes = R.drawable.ic_share_24,
onClick = ::onShareClick,
),
),
)
}
private fun onExploreClick() {
if (confirmUM == null) return
// analyticsEventHandler.send(CommonSendAnalyticEvents.ExploreButtonClicked(params.analyticsCategoryName))
urlOpener.openUrl(confirmUM.txUrl)
}
private fun onShareClick() {
if (confirmUM == null) return
// analyticsEventHandler.send(CommonSendAnalyticEvents.ShareButtonClicked(params.analyticsCategoryName))
shareManager.shareText(confirmUM.txUrl)
}
}

View file

@ -0,0 +1,441 @@
package com.tangem.features.swap.v2.impl.sendviaswap.success.ui
import android.content.res.Configuration
import androidx.compose.animation.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.amountScreen.utils.getFiatReference
import com.tangem.common.ui.navigationButtons.NavigationButton
import com.tangem.common.ui.navigationButtons.NavigationUM
import com.tangem.core.ui.components.SecondaryButtonIconStart
import com.tangem.core.ui.components.SpacerW12
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.components.icons.identicon.IdentIcon
import com.tangem.core.ui.components.inputrow.InputRowBestRate
import com.tangem.core.ui.components.rows.SelectorRowItem
import com.tangem.core.ui.components.transactions.TransactionDoneTitle
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.fee
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
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.singleEvent
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.express.models.ExpressProvider
import com.tangem.domain.express.models.ExpressProviderType
import com.tangem.domain.swap.models.SwapDataModel
import com.tangem.domain.swap.models.SwapDataTransactionModel
import com.tangem.domain.utils.convertToSdkAmount
import com.tangem.features.send.v2.api.entity.FeeExtraInfo
import com.tangem.features.send.v2.api.entity.FeeItem
import com.tangem.features.send.v2.api.entity.FeeNonce
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationTextFieldUM
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationUM
import com.tangem.features.swap.v2.impl.R
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountFieldUM
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
import com.tangem.features.swap.v2.impl.amount.ui.preview.SwapAmountContentPreview
import com.tangem.features.swap.v2.impl.common.entity.ConfirmUM
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import com.tangem.features.swap.v2.impl.sendviaswap.entity.SendWithSwapUM
import kotlinx.collections.immutable.persistentListOf
import java.math.BigDecimal
private const val GRADIENT_ALPHA = 0.3f
@Composable
internal fun SendWithSwapSuccessContent(sendWithSwapUM: SendWithSwapUM) {
if (sendWithSwapUM.navigationUM !is NavigationUM.Content) return
val confirmUM = sendWithSwapUM.confirmUM as? ConfirmUM.Success ?: return
val amountUM = sendWithSwapUM.amountUM as? SwapAmountUM.Content ?: return
val quoteUM = amountUM.selectedQuote as? SwapQuoteUM.Content ?: return
val destinationUM = sendWithSwapUM.destinationUM as? DestinationUM.Content ?: return
val feeSelectorUM = sendWithSwapUM.feeSelectorUM as? FeeSelectorUM.Content ?: return
Box(
modifier = Modifier
.fillMaxSize()
.background(TangemTheme.colors.background.tertiary),
) {
Column(
modifier = Modifier
.padding(horizontal = 16.dp)
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
TransactionDoneTitle(
title = resourceReference(R.string.sent_transaction_sent_title),
subtitle = resourceReference(
id = R.string.send_date_format,
formatArgs = wrappedList(
confirmUM.transactionDate.toTimeFormat(DateTimeFormatters.dateFormatter),
confirmUM.transactionDate.toTimeFormat(),
),
),
modifier = Modifier.padding(vertical = 12.dp),
)
SwapAmountBlock(amountUM = amountUM)
InputRowBestRate(
imageUrl = confirmUM.provider.imageLarge,
title = stringReference(confirmUM.provider.name),
titleExtra = stringReference(confirmUM.provider.type.typeName),
subtitle = quoteUM.rate,
modifier = Modifier
.clip(TangemTheme.shapes.roundedCornersXMedium)
.background(TangemTheme.colors.background.action),
)
DestinationBlock(destinationUM.addressTextField)
FeeBlock(feeSelectorUM = feeSelectorUM)
Spacer(Modifier.height(60.dp))
}
DoneButtons(
pairButtonsUM = sendWithSwapUM.navigationUM.secondaryPairButtonsUM,
modifier = Modifier
.align(Alignment.BottomCenter)
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
TangemTheme.colors.background.tertiary.copy(GRADIENT_ALPHA),
TangemTheme.colors.background.tertiary,
),
),
)
.padding(top = 24.dp)
.padding(horizontal = 16.dp),
)
}
}
@Composable
private fun SwapAmountBlock(amountUM: SwapAmountUM.Content) {
AmountBlock(
title = resourceReference(
id = R.string.send_from_wallet_name,
formatArgs = wrappedList(
(amountUM.primaryAmount.amountField as? AmountState.Data)?.title
?: TextReference.EMPTY,
),
),
amountFieldUM = amountUM.primaryAmount,
)
AmountBlock(
title = resourceReference(R.string.send_with_swap_recipient_amount_success_title),
amountFieldUM = amountUM.secondaryAmount,
)
}
@Composable
private fun AmountBlock(title: TextReference, amountFieldUM: SwapAmountFieldUM, modifier: Modifier = Modifier) {
val amountFieldData = amountFieldUM.amountField as? AmountState.Data ?: return
val cryptoAmount = amountFieldData.amountTextField.cryptoAmount
val fiatAmount = amountFieldData.amountTextField.fiatAmount
Column(
modifier = modifier
.clip(TangemTheme.shapes.roundedCornersXMedium)
.background(TangemTheme.colors.background.action)
.padding(12.dp),
) {
Text(
text = title.resolveReference(),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp),
) {
CurrencyIcon(
state = amountFieldData.tokenIconState,
)
Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
Text(
text = cryptoAmount.value?.format {
crypto(
symbol = cryptoAmount.currencySymbol,
decimals = cryptoAmount.decimals,
)
}.orEmpty(),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.primary1,
)
Text(
text = fiatAmount.value.format {
fiat(
fiatCurrencyCode = amountFieldData.appCurrency.code,
fiatCurrencySymbol = amountFieldData.appCurrency.symbol,
)
},
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
)
}
}
}
}
@Composable
private fun FeeBlock(feeSelectorUM: FeeSelectorUM.Content) {
val feeExtraInfo = feeSelectorUM.feeExtraInfo
val feeFiatRateUM = feeSelectorUM.feeFiatRateUM
Column(
modifier = Modifier
.fillMaxWidth()
.clip(TangemTheme.shapes.roundedCornersXMedium)
.background(TangemTheme.colors.background.action)
.padding(TangemTheme.dimens.spacing12),
) {
Text(
text = stringResourceSafe(com.tangem.common.ui.R.string.common_network_fee_title),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
Box(modifier = Modifier.padding(top = TangemTheme.dimens.spacing8)) {
val feeAmount = feeSelectorUM.selectedFeeItem.fee.amount
SelectorRowItem(
titleRes = com.tangem.common.ui.R.string.common_fee_selector_option_market,
iconRes = com.tangem.common.ui.R.drawable.ic_bird_24,
preDot = stringReference(
feeAmount.value.format {
crypto(
symbol = feeAmount.currencySymbol,
decimals = feeAmount.decimals,
).fee(canBeLower = feeExtraInfo.isFeeApproximate)
},
),
postDot = if (feeExtraInfo.isFeeConvertibleToFiat && feeFiatRateUM != null) {
getFiatReference(feeAmount.value, feeFiatRateUM.rate, feeFiatRateUM.appCurrency)
} else {
null
},
ellipsizeOffset = feeAmount.currencySymbol.length,
isSelected = true,
showDivider = false,
showSelectedAppearance = false,
paddingValues = PaddingValues(),
)
}
}
}
@Composable
private fun DestinationBlock(address: DestinationTextFieldUM.RecipientAddress, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxWidth()
.clip(TangemTheme.shapes.roundedCornersXMedium)
.background(TangemTheme.colors.background.action)
.padding(12.dp),
) {
Text(
text = stringResourceSafe(R.string.send_recipient),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(24.dp),
modifier = Modifier.padding(top = 8.dp),
) {
Text(
modifier = Modifier.weight(1f),
text = address.value,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
)
IdentIcon(
address = address.value,
modifier = Modifier
.size(TangemTheme.dimens.size36)
.clip(RoundedCornerShape(18.dp))
.background(TangemTheme.colors.background.tertiary),
)
}
}
}
// TODO remove [REDACTED_TASK_KEY]
@Composable
private fun DoneButtons(pairButtonsUM: Pair<NavigationButton, NavigationButton>?, modifier: Modifier = Modifier) {
val hapticFeedback = LocalHapticFeedback.current
AnimatedVisibility(
visible = pairButtonsUM != null,
modifier = modifier,
enter = slideInVertically().plus(fadeIn()),
exit = slideOutVertically().plus(fadeOut()),
label = "Animate show sent state buttons",
) {
val (leftButton, rightButton) = remember(this) { requireNotNull(pairButtonsUM) }
Row {
SecondaryButtonIconStart(
text = leftButton.textReference.resolveReference(),
iconResId = requireNotNull(leftButton.iconRes),
onClick = {
singleEvent {
leftButton.onClick()
}
},
modifier = Modifier.weight(1f),
)
SpacerW12()
SecondaryButtonIconStart(
text = rightButton.textReference.resolveReference(),
iconResId = requireNotNull(rightButton.iconRes),
onClick = {
singleEvent {
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
rightButton.onClick()
}
},
modifier = Modifier.weight(1f),
)
}
}
}
// region Preview
@Suppress("LongMethod")
@Composable
@Preview(showBackground = true, widthDp = 360, heightDp = 720)
@Preview(showBackground = true, widthDp = 360, heightDp = 720, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun SendWithSwapSuccessContent_Preview() {
TangemThemePreview {
SendWithSwapSuccessContent(
sendWithSwapUM = SendWithSwapUM(
amountUM = SwapAmountContentPreview.defaultState,
destinationUM = DestinationUM.Content(
isPrimaryButtonEnabled = false,
addressTextField = DestinationTextFieldUM.RecipientAddress(
value = "0x391316d97a07027a0702c8A002c8A0C25d8470",
keyboardOptions = KeyboardOptions(),
placeholder = TextReference.EMPTY,
label = resourceReference(R.string.send_recipient),
isError = false,
error = null,
isValuePasted = false,
blockchainAddress = "0x391316d97a07027a0702c8A002c8A0C25d8470",
),
memoTextField = null,
recent = persistentListOf(),
wallets = persistentListOf(),
networkName = "Polygon",
isValidating = false,
isInitialized = false,
isRedesignEnabled = false,
),
feeSelectorUM = FeeSelectorUM.Content(
fees = TransactionFee.Single(
normal = Fee.Common(
BigDecimal.ONE.convertToSdkAmount(
SwapAmountContentPreview.cryptoCurrencyStatus.currency,
),
),
),
feeItems = persistentListOf(),
selectedFeeItem = FeeItem.Market(
Fee.Common(
BigDecimal.ONE.convertToSdkAmount(
SwapAmountContentPreview.cryptoCurrencyStatus.currency,
),
),
),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = null,
feeNonce = FeeNonce.None,
),
confirmUM = ConfirmUM.Success(
isPrimaryButtonEnabled = true,
transactionDate = 8960,
txUrl = "https://tangem.com",
provider = ExpressProvider(
providerId = "changelly",
rateTypes = listOf(),
name = "Changelly",
type = ExpressProviderType.CEX,
imageLarge = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/changelly-1024.png",
termsOfUse = "",
privacyPolicy = "",
isRecommended = false,
slippage = null,
),
swapDataModel = SwapDataModel(
toTokenAmount = BigDecimal.TEN,
transaction = SwapDataTransactionModel.CEX(
fromAmount = BigDecimal.TEN,
toAmount = BigDecimal.TEN,
txValue = "cetero",
txId = "oporteat",
txTo = "graecis",
txExtraId = "expetendis",
externalTxId = "atomorum",
externalTxUrl = "https://tangem.com",
txExtraIdName = "Jeffry Blackwell",
),
),
),
navigationUM = NavigationUM.Content(
title = TextReference.EMPTY,
subtitle = null,
backIconRes = R.drawable.ic_close_24,
backIconClick = {},
additionalIconRes = null,
additionalIconClick = null,
primaryButton = NavigationButton(
textReference = resourceReference(R.string.common_close),
isEnabled = true,
onClick = {},
),
secondaryPairButtonsUM = NavigationButton(
textReference = resourceReference(R.string.common_explore),
iconRes = R.drawable.ic_web_24,
isEnabled = true,
onClick = {},
) to NavigationButton(
textReference = resourceReference(R.string.common_share),
iconRes = R.drawable.ic_share_24,
isEnabled = true,
onClick = {},
),
),
),
)
}
}
// endregion