Updated on 2026-08-14
This commit is contained in:
parent
bc1e6acd0f
commit
b9b41e9d26
24 changed files with 570 additions and 815 deletions
|
|
@ -1362,7 +1362,7 @@
|
||||||
<string name="user_push_notification_agreement_argument_two_subtitle">Frühzeitiger Zugriff auf neue Funktionen und exklusive Angebote.</string>
|
<string name="user_push_notification_agreement_argument_two_subtitle">Frühzeitiger Zugriff auf neue Funktionen und exklusive Angebote.</string>
|
||||||
<string name="user_push_notification_agreement_argument_two_title">Updates zu Funktionen und Neuigkeiten</string>
|
<string name="user_push_notification_agreement_argument_two_title">Updates zu Funktionen und Neuigkeiten</string>
|
||||||
<string name="user_push_notification_agreement_header">Möchtest du Push-Benachrichtigungen verwenden?</string>
|
<string name="user_push_notification_agreement_header">Möchtest du Push-Benachrichtigungen verwenden?</string>
|
||||||
<string name="user_push_notification_banner_subtitle">Aktiviere Push-Benachrichtigungen und wir benachrichtigen Dich sofort, wenn Gelder eintreffen \n</string>
|
<string name="user_push_notification_banner_subtitle">Aktiviere Push-Benachrichtigungen und wir benachrichtigen Dich sofort, wenn Gelder eintreffen</string>
|
||||||
<string name="user_push_notification_banner_title">Verpasse keine Transaktion</string>
|
<string name="user_push_notification_banner_title">Verpasse keine Transaktion</string>
|
||||||
<string name="user_wallet_list_add_button">Neues Wallet hinzufügen</string>
|
<string name="user_wallet_list_add_button">Neues Wallet hinzufügen</string>
|
||||||
<string name="user_wallet_list_delete_prompt">Möchtest Du diese Wallet wirklich entfernen?</string>
|
<string name="user_wallet_list_delete_prompt">Möchtest Du diese Wallet wirklich entfernen?</string>
|
||||||
|
|
|
||||||
|
|
@ -1212,6 +1212,8 @@
|
||||||
<string name="user_push_notification_agreement_argument_two_subtitle">Acceso anticipado a nuevas funciones y ofertas exclusivas.</string>
|
<string name="user_push_notification_agreement_argument_two_subtitle">Acceso anticipado a nuevas funciones y ofertas exclusivas.</string>
|
||||||
<string name="user_push_notification_agreement_argument_two_title">Actualizaciones de características y noticias</string>
|
<string name="user_push_notification_agreement_argument_two_title">Actualizaciones de características y noticias</string>
|
||||||
<string name="user_push_notification_agreement_header">¿Quiere utilizar\nnotificaciones push?</string>
|
<string name="user_push_notification_agreement_header">¿Quiere utilizar\nnotificaciones push?</string>
|
||||||
|
<string name="user_push_notification_banner_subtitle">Active las notificaciones push y le avisaremos al instante cuando le lleguen fondos.</string>
|
||||||
|
<string name="user_push_notification_banner_title">No se pierda ninguna transacción</string>
|
||||||
<string name="user_wallet_list_add_button">Agregar una nueva billetera</string>
|
<string name="user_wallet_list_add_button">Agregar una nueva billetera</string>
|
||||||
<string name="user_wallet_list_delete_prompt">¿Estás seguro de que deseas olvidar esta billetera?</string>
|
<string name="user_wallet_list_delete_prompt">¿Estás seguro de que deseas olvidar esta billetera?</string>
|
||||||
<string name="user_wallet_list_error_unable_to_unlock">Ha ocurrido un error, por favor escanee su tarjeta o anillo para iniciar sesión</string>
|
<string name="user_wallet_list_error_unable_to_unlock">Ha ocurrido un error, por favor escanee su tarjeta o anillo para iniciar sesión</string>
|
||||||
|
|
|
||||||
|
|
@ -1185,6 +1185,8 @@
|
||||||
<string name="user_push_notification_agreement_argument_two_subtitle">Accès anticipé à de nouvelles fonctionnalités et à des offres exclusives.</string>
|
<string name="user_push_notification_agreement_argument_two_subtitle">Accès anticipé à de nouvelles fonctionnalités et à des offres exclusives.</string>
|
||||||
<string name="user_push_notification_agreement_argument_two_title">Actualités et mises à jour</string>
|
<string name="user_push_notification_agreement_argument_two_title">Actualités et mises à jour</string>
|
||||||
<string name="user_push_notification_agreement_header">Souhaitez-vous utiliser les\nnotifications push?</string>
|
<string name="user_push_notification_agreement_header">Souhaitez-vous utiliser les\nnotifications push?</string>
|
||||||
|
<string name="user_push_notification_banner_subtitle">Activez les notifications pour recevoir des alertes lorsque des fonds arrivent dans votre portefeuille.</string>
|
||||||
|
<string name="user_push_notification_banner_title">Ne manquez aucune transaction</string>
|
||||||
<string name="user_wallet_list_add_button">Ajouter un nouveau portefeuille</string>
|
<string name="user_wallet_list_add_button">Ajouter un nouveau portefeuille</string>
|
||||||
<string name="user_wallet_list_delete_prompt">Êtes-vous sûr de vouloir supprimer ce portefeuille ?</string>
|
<string name="user_wallet_list_delete_prompt">Êtes-vous sûr de vouloir supprimer ce portefeuille ?</string>
|
||||||
<string name="user_wallet_list_error_unable_to_unlock">Une erreur s\'est produite, veuillez scanner votre carte ou bague pour vous connecter</string>
|
<string name="user_wallet_list_error_unable_to_unlock">Une erreur s\'est produite, veuillez scanner votre carte ou bague pour vous connecter</string>
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@
|
||||||
<string name="biometric_unavailable_warning">お使いの携帯電話で生体認証が無効になっているため、アプリにウォレットを保存できません。ウォレットを保存するには、携帯電話の設定で生体認証機能を有効にしてください。</string>
|
<string name="biometric_unavailable_warning">お使いの携帯電話で生体認証が無効になっているため、アプリにウォレットを保存できません。ウォレットを保存するには、携帯電話の設定で生体認証機能を有効にしてください。</string>
|
||||||
<string name="bitcoin_promo_activation_error">プロモーションコードの処理中にエラーが発生しました。しばらくしてからもう一度お試しください。</string>
|
<string name="bitcoin_promo_activation_error">プロモーションコードの処理中にエラーが発生しました。しばらくしてからもう一度お試しください。</string>
|
||||||
<string name="bitcoin_promo_activation_error_title">アクティベーションエラー</string>
|
<string name="bitcoin_promo_activation_error_title">アクティベーションエラー</string>
|
||||||
<string name="bitcoin_promo_activation_success">プロモコードが正常に有効化されました。リワードは14日以内にあなたのアカウントに付与されます。</string>
|
<string name="bitcoin_promo_activation_success">プロモーションコードが正常に有効化されました。報酬は14日以内にビットコインアカウントに入金されます。</string>
|
||||||
<string name="bitcoin_promo_activation_success_title">プロモーションコードが有効になりました</string>
|
<string name="bitcoin_promo_activation_success_title">プロモーションコードが有効になりました</string>
|
||||||
<string name="bitcoin_promo_already_activated">このプロモーションコードは既に使用されているため、再度使うことはできません。</string>
|
<string name="bitcoin_promo_already_activated">このプロモーションコードは既に使用されているため、再度使うことはできません。</string>
|
||||||
<string name="bitcoin_promo_already_activated_title">コードが利用できません</string>
|
<string name="bitcoin_promo_already_activated_title">コードが利用できません</string>
|
||||||
|
|
@ -180,6 +180,7 @@
|
||||||
<string name="common_add">追加</string>
|
<string name="common_add">追加</string>
|
||||||
<string name="common_add_to_portfolio">ポートフォリオに追加</string>
|
<string name="common_add_to_portfolio">ポートフォリオに追加</string>
|
||||||
<string name="common_add_token">トークンを追加</string>
|
<string name="common_add_token">トークンを追加</string>
|
||||||
|
<string name="common_added">追加済み</string>
|
||||||
<string name="common_address">アドレス</string>
|
<string name="common_address">アドレス</string>
|
||||||
<string name="common_all">すべて</string>
|
<string name="common_all">すべて</string>
|
||||||
<string name="common_allow">許可する</string>
|
<string name="common_allow">許可する</string>
|
||||||
|
|
@ -291,6 +292,7 @@
|
||||||
<string name="common_range_with_space">%1$s — %2$s</string>
|
<string name="common_range_with_space">%1$s — %2$s</string>
|
||||||
<string name="common_read_more">続きを読む</string>
|
<string name="common_read_more">続きを読む</string>
|
||||||
<string name="common_receive">受け取る</string>
|
<string name="common_receive">受け取る</string>
|
||||||
|
<string name="common_recommended">おすすめ</string>
|
||||||
<string name="common_reject">拒否</string>
|
<string name="common_reject">拒否</string>
|
||||||
<string name="common_reload">リロード</string>
|
<string name="common_reload">リロード</string>
|
||||||
<string name="common_rename">名前を変更</string>
|
<string name="common_rename">名前を変更</string>
|
||||||
|
|
@ -347,6 +349,8 @@
|
||||||
<string name="common_yes">はい</string>
|
<string name="common_yes">はい</string>
|
||||||
<string name="contract_address_copied_message">コントラクトアドレスをコピーしました!</string>
|
<string name="contract_address_copied_message">コントラクトアドレスをコピーしました!</string>
|
||||||
<string name="currency_subtitle_expanded">利用可能なネットワーク</string>
|
<string name="currency_subtitle_expanded">利用可能なネットワーク</string>
|
||||||
|
<string name="custom_token_another_account_dialog_description">このトークンの導出パスが%1$sの導出パスと一致しています。トークンはこのアカウントに追加されます。</string>
|
||||||
|
<string name="custom_token_another_account_dialog_title">導出パスは別のアカウントに属します。</string>
|
||||||
<string name="custom_token_contract_address_input_title">コントラクトアドレス</string>
|
<string name="custom_token_contract_address_input_title">コントラクトアドレス</string>
|
||||||
<string name="custom_token_creation_error_invalid_contract_address">コントラクトアドレスが無効です</string>
|
<string name="custom_token_creation_error_invalid_contract_address">コントラクトアドレスが無効です</string>
|
||||||
<string name="custom_token_creation_error_network_not_selected">ネットワークを選択してください</string>
|
<string name="custom_token_creation_error_network_not_selected">ネットワークを選択してください</string>
|
||||||
|
|
@ -464,6 +468,7 @@
|
||||||
<string name="express_provider">プロバイダー</string>
|
<string name="express_provider">プロバイダー</string>
|
||||||
<string name="express_provider_best_rate">ベストレート</string>
|
<string name="express_provider_best_rate">ベストレート</string>
|
||||||
<string name="express_provider_fca_warning_list">FCA警告リスト</string>
|
<string name="express_provider_fca_warning_list">FCA警告リスト</string>
|
||||||
|
<string name="express_provider_great_rate">お得なレート</string>
|
||||||
<string name="express_provider_in_fca_warning_list">FCA警告リストに掲載されたプロバイダー</string>
|
<string name="express_provider_in_fca_warning_list">FCA警告リストに掲載されたプロバイダー</string>
|
||||||
<string name="express_provider_max_amount">最大 %s まで使用可能</string>
|
<string name="express_provider_max_amount">最大 %s まで使用可能</string>
|
||||||
<string name="express_provider_min_amount">%s 以上で利用可能</string>
|
<string name="express_provider_min_amount">%s 以上で利用可能</string>
|
||||||
|
|
@ -1361,9 +1366,10 @@
|
||||||
<string name="user_push_notification_agreement_argument_two_subtitle">新しい機能や限定オファーへの早期アクセス。</string>
|
<string name="user_push_notification_agreement_argument_two_subtitle">新しい機能や限定オファーへの早期アクセス。</string>
|
||||||
<string name="user_push_notification_agreement_argument_two_title">機能およびニュースのアップデート</string>
|
<string name="user_push_notification_agreement_argument_two_title">機能およびニュースのアップデート</string>
|
||||||
<string name="user_push_notification_agreement_header">プッシュ通知を使用しますか?</string>
|
<string name="user_push_notification_agreement_header">プッシュ通知を使用しますか?</string>
|
||||||
<string name="user_push_notification_banner_subtitle">プッシュ通知を有効にすると、資金が到着するとすぐに通知されます</string>
|
<string name="user_push_notification_banner_subtitle">プッシュ通知を有効にすると、ウォレットに着金したときにアラートを受信できます。</string>
|
||||||
<string name="user_push_notification_banner_title">取引を見逃さない</string>
|
<string name="user_push_notification_banner_title">取引を見逃さない</string>
|
||||||
<string name="user_wallet_list_add_button">新しいウォレットを追加</string>
|
<string name="user_wallet_list_add_button">新しいウォレットを追加</string>
|
||||||
|
<string name="user_wallet_list_delete_hw_prompt">バックアップせずにこのウォレットを削除すると、資金に永久にアクセスできなくなります。</string>
|
||||||
<string name="user_wallet_list_delete_prompt">このウォレットを忘れてもよろしいですか?</string>
|
<string name="user_wallet_list_delete_prompt">このウォレットを忘れてもよろしいですか?</string>
|
||||||
<string name="user_wallet_list_error_unable_to_unlock">エラーが発生しました。カードまたはリングをスキャンしてログインしてください。</string>
|
<string name="user_wallet_list_error_unable_to_unlock">エラーが発生しました。カードまたはリングをスキャンしてログインしてください。</string>
|
||||||
<string name="user_wallet_list_error_wallet_already_saved">このウォレットはすでに保存されています。別のウォレットを追加できます。</string>
|
<string name="user_wallet_list_error_wallet_already_saved">このウォレットはすでに保存されています。別のウォレットを追加できます。</string>
|
||||||
|
|
@ -1393,6 +1399,13 @@
|
||||||
<string name="visa_unlock_notification_button">ロック解除</string>
|
<string name="visa_unlock_notification_button">ロック解除</string>
|
||||||
<string name="visa_unlock_notification_subtitle">カードをスキャンしてアクセスロックを解除する</string>
|
<string name="visa_unlock_notification_subtitle">カードをスキャンしてアクセスロックを解除する</string>
|
||||||
<string name="visa_unlock_notification_title">ロック解除が必要</string>
|
<string name="visa_unlock_notification_title">ロック解除が必要</string>
|
||||||
|
<string name="wallet_add_common_title">ウォレットの追加方法を選択してください</string>
|
||||||
|
<string name="wallet_add_hardware_description">Tangemカードまたはリングをスキャンして復元するか、別のウォレットからインポートしてください。</string>
|
||||||
|
<string name="wallet_add_hardware_info_create">ハードウェアウォレットを作成</string>
|
||||||
|
<string name="wallet_add_hardware_purchase">Tangemウォレットを購入しますか?</string>
|
||||||
|
<string name="wallet_add_import_seed_phrase">シードフレーズをインポート</string>
|
||||||
|
<string name="wallet_add_mobile_description">スマートフォン上でウォレットを復元するか、他のアプリからインポートできますが、Tangemカードと比べるとセキュリティは劣ります。</string>
|
||||||
|
<string name="wallet_add_support_title">お選びください</string>
|
||||||
<string name="wallet_balance_blockchain_unreachable_try_later">ブロックチェーンにアクセスできません。後でもう一度お試しください。</string>
|
<string name="wallet_balance_blockchain_unreachable_try_later">ブロックチェーンにアクセスできません。後でもう一度お試しください。</string>
|
||||||
<string name="wallet_balance_missing_derivation">カードまたはリングをスキャン</string>
|
<string name="wallet_balance_missing_derivation">カードまたはリングをスキャン</string>
|
||||||
<string name="wallet_been_activated_message">このウォレットはすでに有効化されています。\nあなたが行ったのでない場合は、サポートに連絡してください。\nTangemは、事前に生成されたアクセスコードと一緒にウォレットを販売することはありません。</string>
|
<string name="wallet_been_activated_message">このウォレットはすでに有効化されています。\nあなたが行ったのでない場合は、サポートに連絡してください。\nTangemは、事前に生成されたアクセスコードと一緒にウォレットを販売することはありません。</string>
|
||||||
|
|
@ -1432,6 +1445,7 @@
|
||||||
<string name="wallet_connect_subtitle">dAppsに接続する</string>
|
<string name="wallet_connect_subtitle">dAppsに接続する</string>
|
||||||
<string name="wallet_connect_title">WalletConnect</string>
|
<string name="wallet_connect_title">WalletConnect</string>
|
||||||
<string name="wallet_connect_toast_awaiting_session_proposal">接続には数秒かかる場合があります</string>
|
<string name="wallet_connect_toast_awaiting_session_proposal">接続には数秒かかる場合があります</string>
|
||||||
|
<string name="wallet_create_common_title">Tangemウォレットを作成する</string>
|
||||||
<string name="wallet_create_hardware_badge">%sから</string>
|
<string name="wallet_create_hardware_badge">%sから</string>
|
||||||
<string name="wallet_create_hardware_description">Tangemウォレットを購入ーこれは、あなたの秘密鍵をオフラインで安全に保管する物理デバイスです。</string>
|
<string name="wallet_create_hardware_description">Tangemウォレットを購入ーこれは、あなたの秘密鍵をオフラインで安全に保管する物理デバイスです。</string>
|
||||||
<string name="wallet_create_hardware_title">ハードウェアウォレット</string>
|
<string name="wallet_create_hardware_title">ハードウェアウォレット</string>
|
||||||
|
|
@ -1657,13 +1671,20 @@
|
||||||
<string name="wc_uri_already_used_title">URIはすでに使用されています</string>
|
<string name="wc_uri_already_used_title">URIはすでに使用されています</string>
|
||||||
<string name="wc_wallet_connect">WalletConnect</string>
|
<string name="wc_wallet_connect">WalletConnect</string>
|
||||||
<string name="wc_warning_transaction">不審な取引</string>
|
<string name="wc_warning_transaction">不審な取引</string>
|
||||||
|
<string name="welcome_create_wallet_already_have">すでにTangemをお持ちですか?</string>
|
||||||
|
<string name="welcome_create_wallet_feature_assets">数千種類の資産</string>
|
||||||
<string name="welcome_create_wallet_feature_class">業界最高水準のハードウェアウォレット</string>
|
<string name="welcome_create_wallet_feature_class">業界最高水準のハードウェアウォレット</string>
|
||||||
<string name="welcome_create_wallet_feature_delivery">迅速な配送</string>
|
<string name="welcome_create_wallet_feature_delivery">迅速な配送</string>
|
||||||
|
<string name="welcome_create_wallet_feature_one_tap">ワンタップで開始</string>
|
||||||
|
<string name="welcome_create_wallet_feature_seamless">シームレスで安全</string>
|
||||||
<string name="welcome_create_wallet_feature_use">シンプルな操作</string>
|
<string name="welcome_create_wallet_feature_use">シンプルな操作</string>
|
||||||
<string name="welcome_create_wallet_hardware_description">Tangemでハードウェアウォレットを作成しましょう。銀行のカードのようにスリムで、金庫のように安全です。</string>
|
<string name="welcome_create_wallet_hardware_description">Tangemでハードウェアウォレットを作成しましょう。銀行のカードのようにスリムで、金庫のように安全です。</string>
|
||||||
<string name="welcome_create_wallet_mobile_description">ソフトウェアウォレットを作成またはインポート</string>
|
<string name="welcome_create_wallet_mobile_description">ソフトウェアウォレットを作成またはインポート</string>
|
||||||
|
<string name="welcome_create_wallet_mobile_description_full">スマートフォン上にソフトウェアウォレットを作成するか、インポートしてください。</string>
|
||||||
<string name="welcome_create_wallet_mobile_title">モバイルウォレットから始める</string>
|
<string name="welcome_create_wallet_mobile_title">モバイルウォレットから始める</string>
|
||||||
<string name="welcome_create_wallet_other_method">その他の方法</string>
|
<string name="welcome_create_wallet_other_method">その他の方法</string>
|
||||||
|
<string name="welcome_create_wallet_use_hardware_description">Tangemハードウェアウォレットを使用する</string>
|
||||||
|
<string name="welcome_create_wallet_use_hardware_title">詳細を見る・購入する</string>
|
||||||
<string name="welcome_interrupted_backup_alert_discard">破棄</string>
|
<string name="welcome_interrupted_backup_alert_discard">破棄</string>
|
||||||
<string name="welcome_interrupted_backup_alert_message">バックアップが中断されました。再開しますか?</string>
|
<string name="welcome_interrupted_backup_alert_message">バックアップが中断されました。再開しますか?</string>
|
||||||
<string name="welcome_interrupted_backup_alert_resume">はい、再開します</string>
|
<string name="welcome_interrupted_backup_alert_resume">はい、再開します</string>
|
||||||
|
|
@ -1688,6 +1709,7 @@
|
||||||
<string name="yield_module_approve_sheet_title">承認を確定する</string>
|
<string name="yield_module_approve_sheet_title">承認を確定する</string>
|
||||||
<string name="yield_module_balance_info_sheet_subtitle">資産残高に関するテキスト [プレースホルダー]</string>
|
<string name="yield_module_balance_info_sheet_subtitle">資産残高に関するテキスト [プレースホルダー]</string>
|
||||||
<string name="yield_module_balance_info_sheet_title">あなたの%sはAaveに預けられています</string>
|
<string name="yield_module_balance_info_sheet_title">あなたの%sはAaveに預けられています</string>
|
||||||
|
<string name="yield_module_chart_loading_error">チャートを読み込めません・・</string>
|
||||||
<string name="yield_module_deposit_error_notification_title">受け取った金額%1$s %2$sはAaveに入金されませんでした。</string>
|
<string name="yield_module_deposit_error_notification_title">受け取った金額%1$s %2$sはAaveに入金されませんでした。</string>
|
||||||
<string name="yield_module_earn_badge">%1$s%% を獲得</string>
|
<string name="yield_module_earn_badge">%1$s%% を獲得</string>
|
||||||
<string name="yield_module_earn_sheet_available_title">利用可能</string>
|
<string name="yield_module_earn_sheet_available_title">利用可能</string>
|
||||||
|
|
@ -1705,6 +1727,7 @@
|
||||||
<string name="yield_module_fee_policy_sheet_max_fee_title">最大手数料</string>
|
<string name="yield_module_fee_policy_sheet_max_fee_title">最大手数料</string>
|
||||||
<string name="yield_module_fee_policy_sheet_title">手数料ポリシー</string>
|
<string name="yield_module_fee_policy_sheet_title">手数料ポリシー</string>
|
||||||
<string name="yield_module_high_fee_error">ネットワーク手数料が現在高すぎます。設定した上限を下回るまで待機しています。</string>
|
<string name="yield_module_high_fee_error">ネットワーク手数料が現在高すぎます。設定した上限を下回るまで待機しています。</string>
|
||||||
|
<string name="yield_module_historical_returns">過去のリターン</string>
|
||||||
<string name="yield_module_main_view_approve_notification_description">ここに説明を入力してください。1〜3行が理想的です。[プレースホルダー]</string>
|
<string name="yield_module_main_view_approve_notification_description">ここに説明を入力してください。1〜3行が理想的です。[プレースホルダー]</string>
|
||||||
<string name="yield_module_main_view_approve_notification_title">トークン承認が必要</string>
|
<string name="yield_module_main_view_approve_notification_title">トークン承認が必要</string>
|
||||||
<string name="yield_module_network_fee_unreachable_notification_description">ネットワーク接続を確認してください</string>
|
<string name="yield_module_network_fee_unreachable_notification_description">ネットワーク接続を確認してください</string>
|
||||||
|
|
@ -1738,7 +1761,8 @@
|
||||||
<string name="yield_module_supply_apr">供給APR</string>
|
<string name="yield_module_supply_apr">供給APR</string>
|
||||||
<string name="yield_module_token_details_earn_notification_apy">APY</string>
|
<string name="yield_module_token_details_earn_notification_apy">APY</string>
|
||||||
<string name="yield_module_token_details_earn_notification_description">あなたの資産を眠らせない — 残高を運用して利息を得ましょう。</string>
|
<string name="yield_module_token_details_earn_notification_description">あなたの資産を眠らせない — 残高を運用して利息を得ましょう。</string>
|
||||||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">保有資産から報酬を得る</string>
|
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">利息は自動的に発生します</string>
|
||||||
|
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Aaveレンディング</string>
|
||||||
<string name="yield_module_token_details_earn_notification_processing">入金の処理中</string>
|
<string name="yield_module_token_details_earn_notification_processing">入金の処理中</string>
|
||||||
<string name="yield_module_token_details_earn_notification_title">年間%1$s%%の収益</string>
|
<string name="yield_module_token_details_earn_notification_title">年間%1$s%%の収益</string>
|
||||||
<string name="yield_module_transfer_mode_automatic">自動</string>
|
<string name="yield_module_transfer_mode_automatic">自動</string>
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@
|
||||||
<string name="biometric_unavailable_warning">Вы отключили биометрическую аутентификацию на вашем телефоне и не сможете сохранять кошельки в приложении. Для сохранения кошельков, пожалуйста, включите функцию биометрической аутентификации в настройках телефона.</string>
|
<string name="biometric_unavailable_warning">Вы отключили биометрическую аутентификацию на вашем телефоне и не сможете сохранять кошельки в приложении. Для сохранения кошельков, пожалуйста, включите функцию биометрической аутентификации в настройках телефона.</string>
|
||||||
<string name="bitcoin_promo_activation_error">При обработке промокода произошла ошибка. Пожалуйста, попробуйте позже.</string>
|
<string name="bitcoin_promo_activation_error">При обработке промокода произошла ошибка. Пожалуйста, попробуйте позже.</string>
|
||||||
<string name="bitcoin_promo_activation_error_title">Ошибка активации</string>
|
<string name="bitcoin_promo_activation_error_title">Ошибка активации</string>
|
||||||
<string name="bitcoin_promo_activation_success">Ваш промокод был успешно активирован. Награда будет зачислена на ваш счёт в течение 14 дней.</string>
|
<string name="bitcoin_promo_activation_success">Ваш промокод был успешно активирован. Награда будет зачислена на ваш Bitcoin адрес в течение 14 дней.</string>
|
||||||
<string name="bitcoin_promo_activation_success_title">Промокод активирован</string>
|
<string name="bitcoin_promo_activation_success_title">Промокод активирован</string>
|
||||||
<string name="bitcoin_promo_already_activated">Этот промокод уже был использован и не может быть активирован повторно.</string>
|
<string name="bitcoin_promo_already_activated">Этот промокод уже был использован и не может быть активирован повторно.</string>
|
||||||
<string name="bitcoin_promo_already_activated_title">Код недоступен</string>
|
<string name="bitcoin_promo_already_activated_title">Код недоступен</string>
|
||||||
|
|
@ -1288,6 +1288,8 @@
|
||||||
<string name="user_push_notification_agreement_argument_two_subtitle">Ранний доступ к новым функциям и эксклюзивным предложениям.</string>
|
<string name="user_push_notification_agreement_argument_two_subtitle">Ранний доступ к новым функциям и эксклюзивным предложениям.</string>
|
||||||
<string name="user_push_notification_agreement_argument_two_title">Новые функции и важные новости</string>
|
<string name="user_push_notification_agreement_argument_two_title">Новые функции и важные новости</string>
|
||||||
<string name="user_push_notification_agreement_header">Хотите использовать Push-уведомления?</string>
|
<string name="user_push_notification_agreement_header">Хотите использовать Push-уведомления?</string>
|
||||||
|
<string name="user_push_notification_banner_subtitle">Включите push-уведомления, и мы мгновенно сообщим вам, когда поступят средства.</string>
|
||||||
|
<string name="user_push_notification_banner_title">Не пропустите транзакцию</string>
|
||||||
<string name="user_wallet_list_add_button">Добавить новый кошелек</string>
|
<string name="user_wallet_list_add_button">Добавить новый кошелек</string>
|
||||||
<string name="user_wallet_list_delete_prompt">Вы уверены, что хотите забыть этот кошелек?</string>
|
<string name="user_wallet_list_delete_prompt">Вы уверены, что хотите забыть этот кошелек?</string>
|
||||||
<string name="user_wallet_list_error_unable_to_unlock">Произошла ошибка, пожалуйста, отсканируйте свою карту или кольцо для входа</string>
|
<string name="user_wallet_list_error_unable_to_unlock">Произошла ошибка, пожалуйста, отсканируйте свою карту или кольцо для входа</string>
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@
|
||||||
<string name="biometric_unavailable_warning">You have disabled biometric authentication on your phone and will not be able to save wallets in the app. To save wallets, please enable the biometric authentication function in your phone settings.</string>
|
<string name="biometric_unavailable_warning">You have disabled biometric authentication on your phone and will not be able to save wallets in the app. To save wallets, please enable the biometric authentication function in your phone settings.</string>
|
||||||
<string name="bitcoin_promo_activation_error">An error occurred while processing your promo code. Please try again later.</string>
|
<string name="bitcoin_promo_activation_error">An error occurred while processing your promo code. Please try again later.</string>
|
||||||
<string name="bitcoin_promo_activation_error_title">Activation error</string>
|
<string name="bitcoin_promo_activation_error_title">Activation error</string>
|
||||||
<string name="bitcoin_promo_activation_success">Your promo code was successfully activated. A reward will be credited to your account within 14 days.</string>
|
<string name="bitcoin_promo_activation_success">Your promo code was successfully activated. The reward will be credited to your Bitcoin account within 14 days.</string>
|
||||||
<string name="bitcoin_promo_activation_success_title">Promo Code Activated</string>
|
<string name="bitcoin_promo_activation_success_title">Promo Code Activated</string>
|
||||||
<string name="bitcoin_promo_already_activated">This promo code has already been used and cannot be activated again.</string>
|
<string name="bitcoin_promo_already_activated">This promo code has already been used and cannot be activated again.</string>
|
||||||
<string name="bitcoin_promo_already_activated_title">Code unavailable</string>
|
<string name="bitcoin_promo_already_activated_title">Code unavailable</string>
|
||||||
|
|
@ -183,6 +183,7 @@
|
||||||
<string name="common_add">Add</string>
|
<string name="common_add">Add</string>
|
||||||
<string name="common_add_to_portfolio">Add to portfolio</string>
|
<string name="common_add_to_portfolio">Add to portfolio</string>
|
||||||
<string name="common_add_token">Add token</string>
|
<string name="common_add_token">Add token</string>
|
||||||
|
<string name="common_added">Added</string>
|
||||||
<string name="common_address">Address</string>
|
<string name="common_address">Address</string>
|
||||||
<string name="common_all">All</string>
|
<string name="common_all">All</string>
|
||||||
<string name="common_allow">Allow</string>
|
<string name="common_allow">Allow</string>
|
||||||
|
|
@ -297,6 +298,7 @@
|
||||||
<string name="common_range_with_space">%1$s — %2$s</string>
|
<string name="common_range_with_space">%1$s — %2$s</string>
|
||||||
<string name="common_read_more">Read more</string>
|
<string name="common_read_more">Read more</string>
|
||||||
<string name="common_receive">Receive</string>
|
<string name="common_receive">Receive</string>
|
||||||
|
<string name="common_recommended">Recommended</string>
|
||||||
<string name="common_reject">Reject</string>
|
<string name="common_reject">Reject</string>
|
||||||
<string name="common_reload">Reload</string>
|
<string name="common_reload">Reload</string>
|
||||||
<string name="common_rename">Rename</string>
|
<string name="common_rename">Rename</string>
|
||||||
|
|
@ -474,6 +476,7 @@
|
||||||
<string name="express_provider">Provider</string>
|
<string name="express_provider">Provider</string>
|
||||||
<string name="express_provider_best_rate">Best rate</string>
|
<string name="express_provider_best_rate">Best rate</string>
|
||||||
<string name="express_provider_fca_warning_list">FCA Warning List</string>
|
<string name="express_provider_fca_warning_list">FCA Warning List</string>
|
||||||
|
<string name="express_provider_great_rate">Great rate</string>
|
||||||
<string name="express_provider_in_fca_warning_list">Provider in FCA warning list</string>
|
<string name="express_provider_in_fca_warning_list">Provider in FCA warning list</string>
|
||||||
<string name="express_provider_max_amount">Available up to %s</string>
|
<string name="express_provider_max_amount">Available up to %s</string>
|
||||||
<string name="express_provider_min_amount">Available from %s</string>
|
<string name="express_provider_min_amount">Available from %s</string>
|
||||||
|
|
@ -1386,9 +1389,10 @@
|
||||||
<string name="user_push_notification_agreement_argument_two_subtitle">Early access to fresh features and exclusive offers.</string>
|
<string name="user_push_notification_agreement_argument_two_subtitle">Early access to fresh features and exclusive offers.</string>
|
||||||
<string name="user_push_notification_agreement_argument_two_title">Feature and News Updates</string>
|
<string name="user_push_notification_agreement_argument_two_title">Feature and News Updates</string>
|
||||||
<string name="user_push_notification_agreement_header">Would you like to use\nPush-notifications?</string>
|
<string name="user_push_notification_agreement_header">Would you like to use\nPush-notifications?</string>
|
||||||
<string name="user_push_notification_banner_subtitle">Enable push notifications and we’ll notify you instantly when funds arrive\n</string>
|
<string name="user_push_notification_banner_subtitle">Enable push notifications to receive alerts when funds arrive in your wallet.</string>
|
||||||
<string name="user_push_notification_banner_title">Don’t Miss a Transaction</string>
|
<string name="user_push_notification_banner_title">Don\'t Miss a Transaction</string>
|
||||||
<string name="user_wallet_list_add_button">Add new wallet</string>
|
<string name="user_wallet_list_add_button">Add new wallet</string>
|
||||||
|
<string name="user_wallet_list_delete_hw_prompt">If you delete this wallet without a backup, you will permanently lose access to your funds</string>
|
||||||
<string name="user_wallet_list_delete_prompt">Are you sure you want to forget this wallet?</string>
|
<string name="user_wallet_list_delete_prompt">Are you sure you want to forget this wallet?</string>
|
||||||
<string name="user_wallet_list_error_unable_to_unlock">An error has occurred, please scan your card or ring to log in</string>
|
<string name="user_wallet_list_error_unable_to_unlock">An error has occurred, please scan your card or ring to log in</string>
|
||||||
<string name="user_wallet_list_error_wallet_already_saved">This wallet has already been saved, you can add another one</string>
|
<string name="user_wallet_list_error_wallet_already_saved">This wallet has already been saved, you can add another one</string>
|
||||||
|
|
@ -1465,6 +1469,13 @@
|
||||||
<string name="visa_unlock_notification_button">Unlock</string>
|
<string name="visa_unlock_notification_button">Unlock</string>
|
||||||
<string name="visa_unlock_notification_subtitle">Scan your card to unlock access</string>
|
<string name="visa_unlock_notification_subtitle">Scan your card to unlock access</string>
|
||||||
<string name="visa_unlock_notification_title">Needed unlock</string>
|
<string name="visa_unlock_notification_title">Needed unlock</string>
|
||||||
|
<string name="wallet_add_common_title">Choose how to add your wallet</string>
|
||||||
|
<string name="wallet_add_hardware_description">Scan your Tangem card or ring to restore it or import from another wallet.</string>
|
||||||
|
<string name="wallet_add_hardware_info_create">Create Hardware Wallet</string>
|
||||||
|
<string name="wallet_add_hardware_purchase">Want to purchase a Tangem Wallet?</string>
|
||||||
|
<string name="wallet_add_import_seed_phrase">Import seed phrase</string>
|
||||||
|
<string name="wallet_add_mobile_description">Restore your wallet on your phone or import from another app — convenient, but less secure than a Tangem card.</string>
|
||||||
|
<string name="wallet_add_support_title">What to choose?</string>
|
||||||
<string name="wallet_balance_blockchain_unreachable_try_later">Blockchain is unreachable. Try later</string>
|
<string name="wallet_balance_blockchain_unreachable_try_later">Blockchain is unreachable. Try later</string>
|
||||||
<string name="wallet_balance_missing_derivation">Scan card or ring</string>
|
<string name="wallet_balance_missing_derivation">Scan card or ring</string>
|
||||||
<string name="wallet_been_activated_message">This wallet has already been activated earlier.\nIf it was not done by you, please contact support.\nTangem never sells wallets along with pre-generated access codes.</string>
|
<string name="wallet_been_activated_message">This wallet has already been activated earlier.\nIf it was not done by you, please contact support.\nTangem never sells wallets along with pre-generated access codes.</string>
|
||||||
|
|
@ -1504,6 +1515,7 @@
|
||||||
<string name="wallet_connect_subtitle">Connect to dApps</string>
|
<string name="wallet_connect_subtitle">Connect to dApps</string>
|
||||||
<string name="wallet_connect_title">WalletConnect</string>
|
<string name="wallet_connect_title">WalletConnect</string>
|
||||||
<string name="wallet_connect_toast_awaiting_session_proposal">Connecting may take a few seconds</string>
|
<string name="wallet_connect_toast_awaiting_session_proposal">Connecting may take a few seconds</string>
|
||||||
|
<string name="wallet_create_common_title">Create Tangem Wallet</string>
|
||||||
<string name="wallet_create_hardware_badge">From %s</string>
|
<string name="wallet_create_hardware_badge">From %s</string>
|
||||||
<string name="wallet_create_hardware_description">Buy Tangem Wallet—a physical device that securely stores your private key offline.</string>
|
<string name="wallet_create_hardware_description">Buy Tangem Wallet—a physical device that securely stores your private key offline.</string>
|
||||||
<string name="wallet_create_hardware_title">Hardware Wallet</string>
|
<string name="wallet_create_hardware_title">Hardware Wallet</string>
|
||||||
|
|
@ -1785,7 +1797,10 @@
|
||||||
<string name="yield_module_fee_policy_sheet_description">All future %s top-ups will be supplied to Aave automatically, with the transaction fee deducted.</string>
|
<string name="yield_module_fee_policy_sheet_description">All future %s top-ups will be supplied to Aave automatically, with the transaction fee deducted.</string>
|
||||||
<string name="yield_module_fee_policy_sheet_max_fee_note">If network fees rise above maximum fee, the transaction won’t go through until they decrease. You can change this limit later.</string>
|
<string name="yield_module_fee_policy_sheet_max_fee_note">If network fees rise above maximum fee, the transaction won’t go through until they decrease. You can change this limit later.</string>
|
||||||
<string name="yield_module_fee_policy_sheet_max_fee_title">Maximum fee</string>
|
<string name="yield_module_fee_policy_sheet_max_fee_title">Maximum fee</string>
|
||||||
|
<string name="yield_module_fee_policy_sheet_min_amount_note">The transaction fee must stay below 4% of your deposit. Tangem will transfer funds to Aave only once your balance is large enough to meet this condition. </string>
|
||||||
|
<string name="yield_module_fee_policy_sheet_min_amount_title">Minimal amount</string>
|
||||||
<string name="yield_module_fee_policy_sheet_title">Fee policy</string>
|
<string name="yield_module_fee_policy_sheet_title">Fee policy</string>
|
||||||
|
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem also takes a 3% service fee on the yield earned.</string>
|
||||||
<string name="yield_module_high_fee_error">Network fee is too high right now. Waiting until it falls below your limit.</string>
|
<string name="yield_module_high_fee_error">Network fee is too high right now. Waiting until it falls below your limit.</string>
|
||||||
<string name="yield_module_historical_returns">Historical returns</string>
|
<string name="yield_module_historical_returns">Historical returns</string>
|
||||||
<string name="yield_module_main_view_approve_notification_description">Write description here. In one, two or three lines will be awesome. [PLACEHOLDER]</string>
|
<string name="yield_module_main_view_approve_notification_description">Write description here. In one, two or three lines will be awesome. [PLACEHOLDER]</string>
|
||||||
|
|
@ -1821,7 +1836,8 @@
|
||||||
<string name="yield_module_supply_apr">Supply APR</string>
|
<string name="yield_module_supply_apr">Supply APR</string>
|
||||||
<string name="yield_module_token_details_earn_notification_apy">APY</string>
|
<string name="yield_module_token_details_earn_notification_apy">APY</string>
|
||||||
<string name="yield_module_token_details_earn_notification_description">Make your money work — earn interest on your balance.</string>
|
<string name="yield_module_token_details_earn_notification_description">Make your money work — earn interest on your balance.</string>
|
||||||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Earning on your balance</string>
|
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">Interest accrues automatically</string>
|
||||||
|
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Aave lending</string>
|
||||||
<string name="yield_module_token_details_earn_notification_processing">Processing your deposit</string>
|
<string name="yield_module_token_details_earn_notification_processing">Processing your deposit</string>
|
||||||
<string name="yield_module_token_details_earn_notification_title">Earn %1$s%% per year</string>
|
<string name="yield_module_token_details_earn_notification_title">Earn %1$s%% per year</string>
|
||||||
<string name="yield_module_transfer_mode_automatic">Automatic</string>
|
<string name="yield_module_transfer_mode_automatic">Automatic</string>
|
||||||
|
|
|
||||||
|
|
@ -1,198 +0,0 @@
|
||||||
package com.tangem.domain.account.status.producer
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth
|
|
||||||
import com.tangem.common.test.utils.getEmittedValues
|
|
||||||
import com.tangem.domain.account.models.AccountStatusList
|
|
||||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
|
||||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
|
||||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
|
||||||
import io.mockk.*
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.jupiter.api.AfterEach
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.junit.jupiter.api.TestInstance
|
|
||||||
|
|
||||||
@Suppress("UnusedFlow")
|
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
|
||||||
class DefaultMultiAccountStatusListProducerTest {
|
|
||||||
|
|
||||||
private val userWalletsListRepository: UserWalletsListRepository = mockk()
|
|
||||||
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier = mockk()
|
|
||||||
private val dispatchers = TestingCoroutineDispatcherProvider()
|
|
||||||
|
|
||||||
private val userWalletId1 = UserWalletId("001")
|
|
||||||
private val userWallet1 = mockk<UserWallet> {
|
|
||||||
every { walletId } returns userWalletId1
|
|
||||||
}
|
|
||||||
|
|
||||||
private val userWalletId2 = UserWalletId("002")
|
|
||||||
private val userWallet2 = mockk<UserWallet> {
|
|
||||||
every { walletId } returns userWalletId2
|
|
||||||
}
|
|
||||||
|
|
||||||
private val producer = DefaultMultiAccountStatusListProducer(
|
|
||||||
params = Unit,
|
|
||||||
userWalletsListRepository = userWalletsListRepository,
|
|
||||||
singleAccountStatusListSupplier = singleAccountStatusListSupplier,
|
|
||||||
dispatchers = dispatchers,
|
|
||||||
)
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
fun tearDown() {
|
|
||||||
clearMocks(userWalletsListRepository, singleAccountStatusListSupplier)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `produce returns status lists for all user wallets`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val wallets = listOf(userWallet1, userWallet2)
|
|
||||||
val walletsFlow = MutableStateFlow(wallets)
|
|
||||||
|
|
||||||
every { userWalletsListRepository.userWallets } returns walletsFlow
|
|
||||||
val accountStatusList1 = mockk<AccountStatusList>()
|
|
||||||
val accountStatusList2 = mockk<AccountStatusList>()
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId1),
|
|
||||||
)
|
|
||||||
} returns flowOf(accountStatusList1)
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId2),
|
|
||||||
)
|
|
||||||
} returns flowOf(accountStatusList2)
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
val expected = listOf(accountStatusList1, accountStatusList2)
|
|
||||||
Truth.assertThat(actual).containsExactly(expected)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
userWalletsListRepository.userWallets
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId1),
|
|
||||||
)
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId2),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `produce returns empty flow if userWallets is empty list`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val walletsFlow = MutableStateFlow<List<UserWallet>>(emptyList())
|
|
||||||
every { userWalletsListRepository.userWallets } returns walletsFlow
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Truth.assertThat(actual).isEmpty()
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
userWalletsListRepository.userWallets
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `produce returns empty flow if userWallets is null`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val walletsFlow = MutableStateFlow<List<UserWallet>?>(null)
|
|
||||||
every { userWalletsListRepository.userWallets } returns walletsFlow
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Truth.assertThat(actual).isEmpty()
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
userWalletsListRepository.userWallets
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `flow will updated if userWallets are updated`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val userWalletId3 = UserWalletId("003")
|
|
||||||
val userWallet3 = mockk<UserWallet> { every { walletId } returns userWalletId3 }
|
|
||||||
|
|
||||||
val walletsFlow = MutableStateFlow(listOf(userWallet1, userWallet2))
|
|
||||||
every { userWalletsListRepository.userWallets } returns walletsFlow
|
|
||||||
|
|
||||||
val accountStatusList1 = mockk<AccountStatusList>()
|
|
||||||
val accountStatusList2 = mockk<AccountStatusList>()
|
|
||||||
val accountStatusList3 = mockk<AccountStatusList>()
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId1),
|
|
||||||
)
|
|
||||||
} returns flowOf(accountStatusList1)
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId2),
|
|
||||||
)
|
|
||||||
} returns flowOf(accountStatusList2)
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId3),
|
|
||||||
)
|
|
||||||
} returns flowOf(accountStatusList3)
|
|
||||||
|
|
||||||
// Act (first emission)
|
|
||||||
val actual1 = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert (first emission)
|
|
||||||
val expected1 = listOf(accountStatusList1, accountStatusList2)
|
|
||||||
Truth.assertThat(actual1).containsExactly(expected1)
|
|
||||||
|
|
||||||
// Act (second emission)
|
|
||||||
walletsFlow.value = listOf(userWallet1, userWallet2, userWallet3)
|
|
||||||
val actual2 = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert (second emission)
|
|
||||||
val expected2 = listOf(accountStatusList1, accountStatusList2, accountStatusList3)
|
|
||||||
Truth.assertThat(actual2).containsExactly(expected2)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
userWalletsListRepository.userWallets
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId1),
|
|
||||||
)
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId2),
|
|
||||||
)
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId1),
|
|
||||||
)
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId2),
|
|
||||||
)
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId3),
|
|
||||||
)
|
|
||||||
userWalletsListRepository.userWallets
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId1),
|
|
||||||
)
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId2),
|
|
||||||
)
|
|
||||||
singleAccountStatusListSupplier(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId3),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,244 +0,0 @@
|
||||||
package com.tangem.domain.account.status.producer
|
|
||||||
|
|
||||||
import arrow.core.nonEmptyListOf
|
|
||||||
import com.google.common.truth.Truth
|
|
||||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
|
||||||
import com.tangem.common.test.utils.getEmittedValues
|
|
||||||
import com.tangem.domain.account.models.AccountList
|
|
||||||
import com.tangem.domain.account.models.AccountStatusList
|
|
||||||
import com.tangem.domain.account.producer.SingleAccountListProducer
|
|
||||||
import com.tangem.domain.account.status.utils.CryptoCurrencyStatusesFlowFactory
|
|
||||||
import com.tangem.domain.account.supplier.SingleAccountListSupplier
|
|
||||||
import com.tangem.domain.core.utils.lceContent
|
|
||||||
import com.tangem.domain.core.utils.lceLoading
|
|
||||||
import com.tangem.domain.models.StatusSource
|
|
||||||
import com.tangem.domain.models.TokensSortType
|
|
||||||
import com.tangem.domain.models.TotalFiatBalance
|
|
||||||
import com.tangem.domain.models.account.AccountStatus
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|
||||||
import com.tangem.domain.models.quote.PriceChange
|
|
||||||
import com.tangem.domain.models.tokenlist.TokenList
|
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
|
||||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
|
||||||
import io.mockk.*
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.jupiter.api.AfterEach
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.junit.jupiter.api.TestInstance
|
|
||||||
import java.math.BigDecimal
|
|
||||||
|
|
||||||
/**
|
|
||||||
[REDACTED_AUTHOR]
|
|
||||||
*/
|
|
||||||
@Suppress("UnusedFlow")
|
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
|
||||||
class DefaultSingleAccountStatusListProducerTest {
|
|
||||||
|
|
||||||
private val singleAccountListSupplier: SingleAccountListSupplier = mockk()
|
|
||||||
private val cryptoCurrencyStatusesFlowFactory: CryptoCurrencyStatusesFlowFactory = mockk()
|
|
||||||
|
|
||||||
private val userWalletId = UserWalletId("011")
|
|
||||||
private val userWallet = mockk<UserWallet> {
|
|
||||||
every { this@mockk.walletId } returns userWalletId
|
|
||||||
}
|
|
||||||
|
|
||||||
private val producer = DefaultSingleAccountStatusListProducer(
|
|
||||||
params = SingleAccountStatusListProducer.Params(userWalletId),
|
|
||||||
singleAccountListSupplier = singleAccountListSupplier,
|
|
||||||
cryptoCurrencyStatusesFlowFactory = cryptoCurrencyStatusesFlowFactory,
|
|
||||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
|
||||||
)
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
fun tearDown() {
|
|
||||||
clearMocks(singleAccountListSupplier, cryptoCurrencyStatusesFlowFactory)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `flow is mapped for user wallet id from params`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val accountList = AccountList.empty(userWallet)
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
} returns flowOf(accountList)
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
val expected = AccountStatusList(
|
|
||||||
userWallet = userWallet,
|
|
||||||
accountStatuses = setOf(
|
|
||||||
AccountStatus.CryptoPortfolio(
|
|
||||||
account = accountList.mainAccount,
|
|
||||||
tokenList = TokenList.Empty,
|
|
||||||
priceChangeLce = PriceChange(value = BigDecimal("0.00"), source = StatusSource.ACTUAL).lceContent(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
totalAccounts = 1,
|
|
||||||
totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL),
|
|
||||||
)
|
|
||||||
Truth.assertThat(actual).containsExactly(expected)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `flow will updated if balances are updated`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val accountList = AccountList.empty(userWallet)
|
|
||||||
val updatedAccountList = AccountList.empty(userWallet = userWallet, sortType = TokensSortType.BALANCE)
|
|
||||||
|
|
||||||
val accountListFlow = MutableStateFlow(value = accountList)
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
} returns accountListFlow
|
|
||||||
|
|
||||||
// Act (first emission)
|
|
||||||
val actual1 = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert (first emission)
|
|
||||||
val expected = AccountStatusList(
|
|
||||||
userWallet = userWallet,
|
|
||||||
accountStatuses = setOf(
|
|
||||||
AccountStatus.CryptoPortfolio(
|
|
||||||
account = accountList.mainAccount,
|
|
||||||
tokenList = TokenList.Empty,
|
|
||||||
priceChangeLce = PriceChange(value = BigDecimal("0.00"), source = StatusSource.ACTUAL).lceContent(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
totalAccounts = 1,
|
|
||||||
totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL),
|
|
||||||
)
|
|
||||||
Truth.assertThat(actual1).containsExactly(expected)
|
|
||||||
|
|
||||||
// Act (second emission)
|
|
||||||
accountListFlow.value = updatedAccountList
|
|
||||||
val actual2 = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert (second emission)
|
|
||||||
val expected2 = AccountStatusList(
|
|
||||||
userWallet = userWallet,
|
|
||||||
accountStatuses = setOf(
|
|
||||||
AccountStatus.CryptoPortfolio(
|
|
||||||
account = updatedAccountList.mainAccount,
|
|
||||||
tokenList = TokenList.Empty,
|
|
||||||
priceChangeLce = PriceChange(value = BigDecimal("0.00"), source = StatusSource.ACTUAL).lceContent(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
totalAccounts = 1,
|
|
||||||
totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL),
|
|
||||||
)
|
|
||||||
Truth.assertThat(actual2).containsExactly(expected2)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `flow is filtered the same balance`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val accountList = AccountList.empty(userWallet)
|
|
||||||
val accountListFlow = MutableStateFlow(value = accountList)
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
} returns accountListFlow
|
|
||||||
|
|
||||||
val expected = AccountStatusList(
|
|
||||||
userWallet = userWallet,
|
|
||||||
accountStatuses = setOf(
|
|
||||||
AccountStatus.CryptoPortfolio(
|
|
||||||
account = accountList.mainAccount,
|
|
||||||
tokenList = TokenList.Empty,
|
|
||||||
priceChangeLce = PriceChange(value = BigDecimal("0.00"), source = StatusSource.ACTUAL).lceContent(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
totalAccounts = 1,
|
|
||||||
totalFiatBalance = TotalFiatBalance.Loaded(amount = BigDecimal.ZERO, source = StatusSource.ACTUAL),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Act (first emission)
|
|
||||||
val actual1 = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert (first emission)
|
|
||||||
Truth.assertThat(actual1).containsExactly(expected)
|
|
||||||
|
|
||||||
// Act (second emission)
|
|
||||||
accountListFlow.value = accountList
|
|
||||||
val actual2 = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert (second emission)
|
|
||||||
Truth.assertThat(actual2).containsExactly(expected)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `flow is produced for account with non empty crypto currencies`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val cryptoCurrencyFactory = MockCryptoCurrencyFactory()
|
|
||||||
val accountList = AccountList.empty(
|
|
||||||
userWallet = userWallet,
|
|
||||||
cryptoCurrencies = cryptoCurrencyFactory.ethereumAndStellar.toSet(),
|
|
||||||
)
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
} returns flowOf(accountList)
|
|
||||||
|
|
||||||
val ethereumStatus = CryptoCurrencyStatus(
|
|
||||||
currency = cryptoCurrencyFactory.ethereum,
|
|
||||||
value = CryptoCurrencyStatus.Loading,
|
|
||||||
)
|
|
||||||
every {
|
|
||||||
cryptoCurrencyStatusesFlowFactory.create(userWallet = userWallet, currency = cryptoCurrencyFactory.ethereum)
|
|
||||||
} returns flowOf(ethereumStatus)
|
|
||||||
|
|
||||||
val stellarStatus = CryptoCurrencyStatus(
|
|
||||||
currency = cryptoCurrencyFactory.stellar,
|
|
||||||
value = CryptoCurrencyStatus.MissedDerivation(priceChange = null, fiatRate = null),
|
|
||||||
)
|
|
||||||
every {
|
|
||||||
cryptoCurrencyStatusesFlowFactory.create(userWallet = userWallet, currency = cryptoCurrencyFactory.stellar)
|
|
||||||
} returns flowOf(stellarStatus)
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = producer.produce().let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
val expected = AccountStatusList(
|
|
||||||
userWallet = userWallet,
|
|
||||||
accountStatuses = setOf(
|
|
||||||
AccountStatus.CryptoPortfolio(
|
|
||||||
account = accountList.mainAccount,
|
|
||||||
tokenList = TokenList.Ungrouped(
|
|
||||||
totalFiatBalance = TotalFiatBalance.Loading,
|
|
||||||
sortedBy = TokensSortType.NONE,
|
|
||||||
currencies = nonEmptyListOf(ethereumStatus, stellarStatus),
|
|
||||||
),
|
|
||||||
priceChangeLce = lceLoading(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
totalAccounts = 1,
|
|
||||||
totalFiatBalance = TotalFiatBalance.Loading,
|
|
||||||
)
|
|
||||||
Truth.assertThat(actual).containsExactly(expected)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
singleAccountListSupplier(params = SingleAccountListProducer.Params(userWalletId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,308 +0,0 @@
|
||||||
package com.tangem.domain.account.status.utils
|
|
||||||
|
|
||||||
import arrow.core.left
|
|
||||||
import arrow.core.right
|
|
||||||
import com.google.common.truth.Truth
|
|
||||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
|
||||||
import com.tangem.common.test.utils.getEmittedValues
|
|
||||||
import com.tangem.domain.models.StatusSource
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|
||||||
import com.tangem.domain.models.network.NetworkAddress
|
|
||||||
import com.tangem.domain.models.network.NetworkStatus
|
|
||||||
import com.tangem.domain.models.quote.QuoteStatus
|
|
||||||
import com.tangem.domain.models.staking.StakingID
|
|
||||||
import com.tangem.domain.models.staking.YieldBalance
|
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
|
||||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
|
||||||
import com.tangem.domain.networks.single.SingleNetworkStatusProducer
|
|
||||||
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
|
|
||||||
import com.tangem.domain.quotes.single.SingleQuoteStatusProducer
|
|
||||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
|
||||||
import com.tangem.domain.staking.StakingIdFactory
|
|
||||||
import com.tangem.domain.staking.single.SingleYieldBalanceProducer
|
|
||||||
import com.tangem.domain.staking.single.SingleYieldBalanceSupplier
|
|
||||||
import io.mockk.*
|
|
||||||
import kotlinx.coroutines.flow.emptyFlow
|
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.jupiter.api.AfterEach
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.junit.jupiter.api.TestInstance
|
|
||||||
import java.math.BigDecimal
|
|
||||||
|
|
||||||
/**
|
|
||||||
[REDACTED_AUTHOR]
|
|
||||||
*/
|
|
||||||
@Suppress("UnusedFlow")
|
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
|
||||||
class CryptoCurrencyStatusesFlowFactoryTest {
|
|
||||||
|
|
||||||
private val singleNetworkStatusSupplier: SingleNetworkStatusSupplier = mockk()
|
|
||||||
private val singleQuoteStatusSupplier: SingleQuoteStatusSupplier = mockk()
|
|
||||||
private val singleYieldBalanceSupplier: SingleYieldBalanceSupplier = mockk()
|
|
||||||
private val stakingIdFactory: StakingIdFactory = mockk()
|
|
||||||
|
|
||||||
private val factory = CryptoCurrencyStatusesFlowFactory(
|
|
||||||
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
|
|
||||||
singleQuoteStatusSupplier = singleQuoteStatusSupplier,
|
|
||||||
singleYieldBalanceSupplier = singleYieldBalanceSupplier,
|
|
||||||
stakingIdFactory = stakingIdFactory,
|
|
||||||
)
|
|
||||||
|
|
||||||
private val userWalletId = UserWalletId("011")
|
|
||||||
private val cryptoCurrencyFactory = MockCryptoCurrencyFactory()
|
|
||||||
|
|
||||||
private val networkAddress = NetworkAddress.Single(
|
|
||||||
defaultAddress = NetworkAddress.Address(value = "0x1", type = NetworkAddress.Address.Type.Primary),
|
|
||||||
)
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
fun tearDown() {
|
|
||||||
clearMocks(
|
|
||||||
singleNetworkStatusSupplier,
|
|
||||||
singleQuoteStatusSupplier,
|
|
||||||
singleYieldBalanceSupplier,
|
|
||||||
stakingIdFactory,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `if rawCurrencyId is null, there will be no subscription to the quote status`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val userWallet = mockk<UserWallet> {
|
|
||||||
every { this@mockk.walletId } returns userWalletId
|
|
||||||
every { this@mockk.isMultiCurrency } returns true
|
|
||||||
}
|
|
||||||
|
|
||||||
val currency = cryptoCurrencyFactory.ethereum.copy(
|
|
||||||
id = cryptoCurrencyFactory.ethereum.id.copy(
|
|
||||||
suffix = CryptoCurrency.ID.Suffix.ContractAddress(contractAddress = "0x12345"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
val networkStatus = NetworkStatus(
|
|
||||||
network = currency.network,
|
|
||||||
value = NetworkStatus.Unreachable(address = networkAddress),
|
|
||||||
)
|
|
||||||
val networkStatusFlow = flowOf(networkStatus)
|
|
||||||
every {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
} returns networkStatusFlow
|
|
||||||
|
|
||||||
val stakingId = StakingID(integrationId = "id", address = networkAddress.defaultAddress.value)
|
|
||||||
coEvery {
|
|
||||||
stakingIdFactory.create(currencyId = currency.id, defaultAddress = networkAddress.defaultAddress.value)
|
|
||||||
} returns stakingId.right()
|
|
||||||
|
|
||||||
val yieldBalance = YieldBalance.Empty(stakingId = stakingId, source = StatusSource.ACTUAL)
|
|
||||||
val yieldBalanceFlow = flowOf(yieldBalance)
|
|
||||||
every {
|
|
||||||
singleYieldBalanceSupplier(
|
|
||||||
params = SingleYieldBalanceProducer.Params(userWalletId = userWalletId, stakingId = stakingId),
|
|
||||||
)
|
|
||||||
} returns yieldBalanceFlow
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = factory.create(userWallet = userWallet, currency = currency).let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
val expected = CryptoCurrencyStatus(
|
|
||||||
currency = currency,
|
|
||||||
value = CryptoCurrencyStatus.Unreachable(
|
|
||||||
priceChange = null,
|
|
||||||
fiatRate = null,
|
|
||||||
networkAddress = networkAddress,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
Truth.assertThat(actual).containsExactly(expected)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
stakingIdFactory.create(currencyId = currency.id, defaultAddress = networkAddress.defaultAddress.value)
|
|
||||||
singleYieldBalanceSupplier(params = SingleYieldBalanceProducer.Params(userWalletId, stakingId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `if userWallet is not multi-currency, there will be no subscription to the yield balance`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val userWallet = mockk<UserWallet> {
|
|
||||||
every { this@mockk.walletId } returns userWalletId
|
|
||||||
every { this@mockk.isMultiCurrency } returns false
|
|
||||||
}
|
|
||||||
|
|
||||||
val currency = cryptoCurrencyFactory.ethereum
|
|
||||||
|
|
||||||
val networkStatus = NetworkStatus(
|
|
||||||
network = currency.network,
|
|
||||||
value = NetworkStatus.Unreachable(address = networkAddress),
|
|
||||||
)
|
|
||||||
val networkStatusFlow = flowOf(networkStatus)
|
|
||||||
every {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
} returns networkStatusFlow
|
|
||||||
|
|
||||||
val quoteStatus = QuoteStatus(
|
|
||||||
rawCurrencyId = currency.id.rawCurrencyId!!,
|
|
||||||
value = QuoteStatus.Data(
|
|
||||||
source = StatusSource.ACTUAL,
|
|
||||||
fiatRate = BigDecimal.ONE,
|
|
||||||
priceChange = BigDecimal.ONE,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
val quoteStatusFlow = flowOf(quoteStatus)
|
|
||||||
every {
|
|
||||||
singleQuoteStatusSupplier(params = SingleQuoteStatusProducer.Params(currency.id.rawCurrencyId!!))
|
|
||||||
} returns quoteStatusFlow
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = factory.create(userWallet = userWallet, currency = currency).let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
val expected = CryptoCurrencyStatus(
|
|
||||||
currency = currency,
|
|
||||||
value = CryptoCurrencyStatus.Unreachable(
|
|
||||||
priceChange = BigDecimal.ONE,
|
|
||||||
fiatRate = BigDecimal.ONE,
|
|
||||||
networkAddress = networkAddress,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
Truth.assertThat(actual).containsExactly(expected)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
singleQuoteStatusSupplier(params = SingleQuoteStatusProducer.Params(currency.id.rawCurrencyId!!))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `no subscription to the quote status and yield balance`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val userWallet = mockk<UserWallet> {
|
|
||||||
every { this@mockk.walletId } returns userWalletId
|
|
||||||
every { this@mockk.isMultiCurrency } returns false
|
|
||||||
}
|
|
||||||
|
|
||||||
val currency = cryptoCurrencyFactory.ethereum.copy(
|
|
||||||
id = cryptoCurrencyFactory.ethereum.id.copy(
|
|
||||||
suffix = CryptoCurrency.ID.Suffix.ContractAddress(contractAddress = "0x12345"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
val networkStatus = NetworkStatus(
|
|
||||||
network = currency.network,
|
|
||||||
value = NetworkStatus.Unreachable(address = networkAddress),
|
|
||||||
)
|
|
||||||
val networkStatusFlow = flowOf(networkStatus)
|
|
||||||
every {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
} returns networkStatusFlow
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = factory.create(userWallet = userWallet, currency = currency).let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
val expected = CryptoCurrencyStatus(
|
|
||||||
currency = currency,
|
|
||||||
value = CryptoCurrencyStatus.Unreachable(
|
|
||||||
priceChange = null,
|
|
||||||
fiatRate = null,
|
|
||||||
networkAddress = networkAddress,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
Truth.assertThat(actual).containsExactly(expected)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `if stakingId is not supported, yield balance will be null`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val userWallet = mockk<UserWallet> {
|
|
||||||
every { this@mockk.walletId } returns userWalletId
|
|
||||||
every { this@mockk.isMultiCurrency } returns true
|
|
||||||
}
|
|
||||||
|
|
||||||
val currency = cryptoCurrencyFactory.ethereum
|
|
||||||
|
|
||||||
val networkStatus = NetworkStatus(
|
|
||||||
network = currency.network,
|
|
||||||
value = NetworkStatus.Unreachable(address = networkAddress),
|
|
||||||
)
|
|
||||||
val networkStatusFlow = flowOf(networkStatus)
|
|
||||||
every {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
} returns networkStatusFlow
|
|
||||||
|
|
||||||
val quoteStatus = QuoteStatus(
|
|
||||||
rawCurrencyId = currency.id.rawCurrencyId!!,
|
|
||||||
value = QuoteStatus.Data(
|
|
||||||
source = StatusSource.ACTUAL,
|
|
||||||
fiatRate = BigDecimal.ONE,
|
|
||||||
priceChange = BigDecimal.ONE,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
val quoteStatusFlow = flowOf(quoteStatus)
|
|
||||||
every {
|
|
||||||
singleQuoteStatusSupplier(params = SingleQuoteStatusProducer.Params(currency.id.rawCurrencyId!!))
|
|
||||||
} returns quoteStatusFlow
|
|
||||||
|
|
||||||
coEvery {
|
|
||||||
stakingIdFactory.create(currencyId = currency.id, defaultAddress = networkAddress.defaultAddress.value)
|
|
||||||
} returns StakingIdFactory.Error.UnsupportedCurrency.left()
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = factory.create(userWallet = userWallet, currency = currency).let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
val expected = CryptoCurrencyStatus(
|
|
||||||
currency = currency,
|
|
||||||
value = CryptoCurrencyStatus.Unreachable(
|
|
||||||
priceChange = BigDecimal.ONE,
|
|
||||||
fiatRate = BigDecimal.ONE,
|
|
||||||
networkAddress = networkAddress,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
Truth.assertThat(actual).containsExactly(expected)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
singleQuoteStatusSupplier(params = SingleQuoteStatusProducer.Params(currency.id.rawCurrencyId!!))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `all sources are empty`() = runTest {
|
|
||||||
// Arrange
|
|
||||||
val userWallet = mockk<UserWallet> {
|
|
||||||
every { this@mockk.walletId } returns userWalletId
|
|
||||||
every { this@mockk.isMultiCurrency } returns true
|
|
||||||
}
|
|
||||||
|
|
||||||
val currency = cryptoCurrencyFactory.ethereum
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
} returns emptyFlow()
|
|
||||||
|
|
||||||
every {
|
|
||||||
singleQuoteStatusSupplier(params = SingleQuoteStatusProducer.Params(currency.id.rawCurrencyId!!))
|
|
||||||
} returns emptyFlow()
|
|
||||||
|
|
||||||
// Act
|
|
||||||
val actual = factory.create(userWallet = userWallet, currency = currency).let(::getEmittedValues)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
val expected = CryptoCurrencyStatus(currency = currency, value = CryptoCurrencyStatus.Loading)
|
|
||||||
Truth.assertThat(actual).containsExactly(expected)
|
|
||||||
|
|
||||||
coVerify(ordering = Ordering.SEQUENCE) {
|
|
||||||
singleNetworkStatusSupplier(params = SingleNetworkStatusProducer.Params(userWalletId, currency.network))
|
|
||||||
singleQuoteStatusSupplier(params = SingleQuoteStatusProducer.Params(currency.id.rawCurrencyId!!))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -69,4 +69,8 @@ internal interface StakingClickIntents : AmountScreenClickIntents {
|
||||||
fun showPrimaryClickAlert()
|
fun showPrimaryClickAlert()
|
||||||
|
|
||||||
fun onOpenLearnMoreAboutApproveClick()
|
fun onOpenLearnMoreAboutApproveClick()
|
||||||
|
|
||||||
|
fun onActivateTonAccountNotificationClick()
|
||||||
|
|
||||||
|
fun onActivateTonAccountClick()
|
||||||
}
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.staking.impl.presentation.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import arrow.core.getOrElse
|
import arrow.core.getOrElse
|
||||||
|
import com.tangem.blockchain.common.TransactionData
|
||||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||||
import com.tangem.common.routing.AppRouter
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer
|
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer
|
||||||
|
|
@ -48,8 +49,11 @@ import com.tangem.domain.staking.utils.getValidatorsCount
|
||||||
import com.tangem.domain.tokens.*
|
import com.tangem.domain.tokens.*
|
||||||
import com.tangem.domain.transaction.error.GetFeeError
|
import com.tangem.domain.transaction.error.GetFeeError
|
||||||
import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase
|
import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase
|
||||||
|
import com.tangem.domain.transaction.usecase.CreateTransferTransactionUseCase
|
||||||
import com.tangem.domain.transaction.usecase.GetAllowanceUseCase
|
import com.tangem.domain.transaction.usecase.GetAllowanceUseCase
|
||||||
|
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||||
|
import com.tangem.domain.utils.convertToSdkAmount
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
import com.tangem.features.staking.api.StakingComponent
|
import com.tangem.features.staking.api.StakingComponent
|
||||||
import com.tangem.features.staking.impl.analytics.StakingParamsInterceptor
|
import com.tangem.features.staking.impl.analytics.StakingParamsInterceptor
|
||||||
|
|
@ -69,10 +73,15 @@ import com.tangem.features.staking.impl.presentation.state.transformers.approval
|
||||||
import com.tangem.features.staking.impl.presentation.state.transformers.confirmation.SetUpdatedAllowanceTransformer
|
import com.tangem.features.staking.impl.presentation.state.transformers.confirmation.SetUpdatedAllowanceTransformer
|
||||||
import com.tangem.features.staking.impl.presentation.state.transformers.notifications.AddStakingNotificationsTransformer
|
import com.tangem.features.staking.impl.presentation.state.transformers.notifications.AddStakingNotificationsTransformer
|
||||||
import com.tangem.features.staking.impl.presentation.state.transformers.notifications.DismissStakingNotificationsStateTransformer
|
import com.tangem.features.staking.impl.presentation.state.transformers.notifications.DismissStakingNotificationsStateTransformer
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.transformers.ton.CompleteInitializeBottomSheetTransformer
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.transformers.ton.SetFeeToTonInitializeBottomSheetTransformer
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.transformers.ton.ShowTonInitializeBottomSheetTransformer
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.transformers.ton.SetFeeErrorToTonInitializeBottomSheetTransformer
|
||||||
import com.tangem.features.staking.impl.presentation.state.transformers.validator.ValidatorSelectChangeTransformer
|
import com.tangem.features.staking.impl.presentation.state.transformers.validator.ValidatorSelectChangeTransformer
|
||||||
import com.tangem.features.staking.impl.presentation.state.utils.checkAndCalculateSubtractedAmount
|
import com.tangem.features.staking.impl.presentation.state.utils.checkAndCalculateSubtractedAmount
|
||||||
import com.tangem.features.staking.impl.presentation.state.utils.isSingleAction
|
import com.tangem.features.staking.impl.presentation.state.utils.isSingleAction
|
||||||
import com.tangem.features.staking.impl.presentation.state.utils.withStubUnstakeAction
|
import com.tangem.features.staking.impl.presentation.state.utils.withStubUnstakeAction
|
||||||
|
import com.tangem.lib.crypto.BlockchainUtils.isTon
|
||||||
import com.tangem.utils.Provider
|
import com.tangem.utils.Provider
|
||||||
import com.tangem.utils.TangemBlogUrlBuilder.RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP
|
import com.tangem.utils.TangemBlogUrlBuilder.RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP
|
||||||
import com.tangem.utils.coroutines.*
|
import com.tangem.utils.coroutines.*
|
||||||
|
|
@ -122,6 +131,9 @@ internal class StakingModel @Inject constructor(
|
||||||
private val getActionsUseCase: GetActionsUseCase,
|
private val getActionsUseCase: GetActionsUseCase,
|
||||||
private val getYieldUseCase: GetYieldUseCase,
|
private val getYieldUseCase: GetYieldUseCase,
|
||||||
private val checkAccountInitializedUseCase: CheckAccountInitializedUseCase,
|
private val checkAccountInitializedUseCase: CheckAccountInitializedUseCase,
|
||||||
|
private val createTransferTransactionUseCase: CreateTransferTransactionUseCase,
|
||||||
|
private val getFeeUseCase: GetFeeUseCase,
|
||||||
|
private val getNetworkAddressesUseCase: GetNetworkAddressesUseCase,
|
||||||
private val getActionRequirementAmountUseCase: GetActionRequirementAmountUseCase,
|
private val getActionRequirementAmountUseCase: GetActionRequirementAmountUseCase,
|
||||||
private val paramsInterceptorHolder: ParamsInterceptorHolder,
|
private val paramsInterceptorHolder: ParamsInterceptorHolder,
|
||||||
private val shareManager: ShareManager,
|
private val shareManager: ShareManager,
|
||||||
|
|
@ -150,11 +162,14 @@ internal class StakingModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var isAccountInitialized: Boolean = true
|
||||||
private var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
private var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
||||||
private var stakingActions: List<StakingAction> = emptyList()
|
private var stakingActions: List<StakingAction> = emptyList()
|
||||||
private var feeCryptoCurrencyStatus: CryptoCurrencyStatus? = null
|
private var feeCryptoCurrencyStatus: CryptoCurrencyStatus? = null
|
||||||
private var minimumTransactionAmount: EnterAmountBoundary? = null
|
private var minimumTransactionAmount: EnterAmountBoundary? = null
|
||||||
|
|
||||||
|
private var tonAccountInitializeTransaction: TransactionData.Uncompiled? = null
|
||||||
|
|
||||||
private val userWallet by lazy {
|
private val userWallet by lazy {
|
||||||
requireNotNull(
|
requireNotNull(
|
||||||
getUserWalletUseCase(userWalletId).getOrNull(),
|
getUserWalletUseCase(userWalletId).getOrNull(),
|
||||||
|
|
@ -250,26 +265,12 @@ internal class StakingModel @Inject constructor(
|
||||||
val isInitialInfoStep = value.currentStep == StakingStep.InitialInfo
|
val isInitialInfoStep = value.currentStep == StakingStep.InitialInfo
|
||||||
val noBalanceState = balanceState == null
|
val noBalanceState = balanceState == null
|
||||||
val noYieldBalanceData = cryptoCurrencyStatus.value.yieldBalance !is YieldBalance.Data
|
val noYieldBalanceData = cryptoCurrencyStatus.value.yieldBalance !is YieldBalance.Data
|
||||||
val isAccountInitialized = checkAccountInitializedUseCase.invoke(
|
|
||||||
userWalletId = userWalletId,
|
|
||||||
network = cryptoCurrencyStatus.currency.network,
|
|
||||||
).getOrElse {
|
|
||||||
Timber.e(it)
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
when {
|
when {
|
||||||
isInitialInfoStep && noBalanceState && yield.allValidatorsFull && noYieldBalanceData -> {
|
isInitialInfoStep && noBalanceState && yield.allValidatorsFull && noYieldBalanceData -> {
|
||||||
stakingEventFactory.createStakingValidatorsUnavailableAlert()
|
stakingEventFactory.createStakingValidatorsUnavailableAlert()
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
isInitialInfoStep && noBalanceState && !isAccountInitialized -> {
|
|
||||||
analyticsEventHandler.send(StakingAnalyticsEvent.UnitializedAddress(
|
|
||||||
token = cryptoCurrencyStatus.currency.symbol,
|
|
||||||
))
|
|
||||||
stakingEventFactory.createInitializeAccountAlert()
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
isInitialInfoStep && noBalanceState -> {
|
isInitialInfoStep && noBalanceState -> {
|
||||||
val list = buildList {
|
val list = buildList {
|
||||||
SetConfirmationStateInitTransformer(
|
SetConfirmationStateInitTransformer(
|
||||||
|
|
@ -763,6 +764,7 @@ internal class StakingModel @Inject constructor(
|
||||||
AddStakingNotificationsTransformer(
|
AddStakingNotificationsTransformer(
|
||||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||||
appCurrencyProvider = Provider { appCurrency },
|
appCurrencyProvider = Provider { appCurrency },
|
||||||
|
isAccountInitializedProvider = Provider { isAccountInitialized },
|
||||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||||
currencyWarning = currencyWarning,
|
currencyWarning = currencyWarning,
|
||||||
currencyCheck = currencyStatus,
|
currencyCheck = currencyStatus,
|
||||||
|
|
@ -934,6 +936,85 @@ internal class StakingModel @Inject constructor(
|
||||||
urlOpener.openUrl(RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP)
|
urlOpener.openUrl(RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onActivateTonAccountNotificationClick() {
|
||||||
|
modelScope.launch {
|
||||||
|
stateController.update(
|
||||||
|
ShowTonInitializeBottomSheetTransformer(
|
||||||
|
onDismiss = { stateController.update(DismissBottomSheetStateTransformer) },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val tonAmount = BigDecimal(1)
|
||||||
|
val destination = getNetworkAddressesUseCase.invokeSync(
|
||||||
|
userWalletId = userWalletId,
|
||||||
|
network = cryptoCurrencyStatus.currency.network,
|
||||||
|
).getOrNull(0)?.address ?: return@launch
|
||||||
|
|
||||||
|
val transaction = createTransferTransactionUseCase(
|
||||||
|
amount = tonAmount.convertToSdkAmount(cryptoCurrencyStatus),
|
||||||
|
destination = destination,
|
||||||
|
userWalletId = userWalletId,
|
||||||
|
network = cryptoCurrencyStatus.currency.network,
|
||||||
|
memo = null,
|
||||||
|
)
|
||||||
|
tonAccountInitializeTransaction = transaction.getOrElse {
|
||||||
|
stateController.update(
|
||||||
|
SetFeeErrorToTonInitializeBottomSheetTransformer(),
|
||||||
|
)
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
|
||||||
|
val transactionFee = getFeeUseCase(
|
||||||
|
userWallet = userWallet,
|
||||||
|
network = cryptoCurrencyStatus.currency.network,
|
||||||
|
transactionData = tonAccountInitializeTransaction!!,
|
||||||
|
)
|
||||||
|
|
||||||
|
transactionFee.fold(
|
||||||
|
ifLeft = {
|
||||||
|
stateController.update(
|
||||||
|
SetFeeErrorToTonInitializeBottomSheetTransformer(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
ifRight = {
|
||||||
|
stateController.update(
|
||||||
|
SetFeeToTonInitializeBottomSheetTransformer(
|
||||||
|
appCurrencyProvider = Provider { appCurrency },
|
||||||
|
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||||
|
fee = it.normal,
|
||||||
|
isFeeApproximate = false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivateTonAccountClick() {
|
||||||
|
modelScope.launch {
|
||||||
|
tonAccountInitializeTransaction?.let { transaction ->
|
||||||
|
sendTransactionUseCase.invoke(
|
||||||
|
txData = transaction,
|
||||||
|
userWallet = userWallet,
|
||||||
|
network = cryptoCurrencyStatus.currency.network,
|
||||||
|
).fold(
|
||||||
|
ifLeft = {
|
||||||
|
stateController.update(DismissBottomSheetStateTransformer)
|
||||||
|
},
|
||||||
|
ifRight = {
|
||||||
|
stateController.update(CompleteInitializeBottomSheetTransformer(
|
||||||
|
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||||
|
minimumTransactionAmount = minimumTransactionAmount,
|
||||||
|
))
|
||||||
|
|
||||||
|
balanceUpdater.partialUpdateWithDelay()
|
||||||
|
stateController.update(DismissBottomSheetStateTransformer)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun setupApprovalNeeded() {
|
private suspend fun setupApprovalNeeded() {
|
||||||
val approval = StakingIntegrationID.create(currencyId = cryptoCurrencyStatus.currency.id)?.approval
|
val approval = StakingIntegrationID.create(currencyId = cryptoCurrencyStatus.currency.id)?.approval
|
||||||
?: StakingApproval.Empty
|
?: StakingApproval.Empty
|
||||||
|
|
@ -961,7 +1042,9 @@ internal class StakingModel @Inject constructor(
|
||||||
)
|
)
|
||||||
.conflate()
|
.conflate()
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.filter { value.currentStep == StakingStep.InitialInfo }
|
.filter {
|
||||||
|
value.currentStep == StakingStep.InitialInfo || isCaseWithUnitializedTonAccount()
|
||||||
|
}
|
||||||
.onEach { maybeStatus ->
|
.onEach { maybeStatus ->
|
||||||
maybeStatus.fold(
|
maybeStatus.fold(
|
||||||
ifRight = { status ->
|
ifRight = { status ->
|
||||||
|
|
@ -989,6 +1072,19 @@ internal class StakingModel @Inject constructor(
|
||||||
}
|
}
|
||||||
cryptoCurrencyStatus = status
|
cryptoCurrencyStatus = status
|
||||||
|
|
||||||
|
val isAccountInitializedNew = checkAccountInitializedUseCase.invoke(
|
||||||
|
userWalletId = userWalletId,
|
||||||
|
network = cryptoCurrencyStatus.currency.network,
|
||||||
|
).getOrElse {
|
||||||
|
Timber.e(it)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
if (isAccountInitializedNew && !isAccountInitialized) {
|
||||||
|
isAccountInitialized = true
|
||||||
|
updateNotifications()
|
||||||
|
}
|
||||||
|
isAccountInitialized = isAccountInitializedNew
|
||||||
|
|
||||||
setupApprovalNeeded()
|
setupApprovalNeeded()
|
||||||
setupIsAnyTokenStaked()
|
setupIsAnyTokenStaked()
|
||||||
checkIfSubtractAvailable()
|
checkIfSubtractAvailable()
|
||||||
|
|
@ -1150,6 +1246,12 @@ internal class StakingModel @Inject constructor(
|
||||||
.getOrElse { false }
|
.getOrElse { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isCaseWithUnitializedTonAccount(): Boolean {
|
||||||
|
return value.currentStep == StakingStep.Confirmation &&
|
||||||
|
isTon(cryptoCurrencyStatus.currency.network.rawId) &&
|
||||||
|
!isAccountInitialized
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val WHAT_IS_STAKING_ARTICLE_URL = "https://tangem.com/en/blog/post/how-to-stake-cryptocurrency/"
|
const val WHAT_IS_STAKING_ARTICLE_URL = "https://tangem.com/en/blog/post/how-to-stake-cryptocurrency/"
|
||||||
const val ALLOWANCE_UPDATE_DELAY = 10_000L
|
const val ALLOWANCE_UPDATE_DELAY = 10_000L
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,15 @@ internal object StakingNotification {
|
||||||
title = resourceReference(R.string.staking_notification_low_staked_balance_title),
|
title = resourceReference(R.string.staking_notification_low_staked_balance_title),
|
||||||
subtitle = resourceReference(R.string.staking_notification_low_staked_balance_text),
|
subtitle = resourceReference(R.string.staking_notification_low_staked_balance_text),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class InitializeTonAccount(private val onInitializeClick: () -> Unit) : Info(
|
||||||
|
title = resourceReference(R.string.staking_notification_ton_account_initialization_title),
|
||||||
|
subtitle = resourceReference(R.string.staking_notification_ton_account_initialization_message),
|
||||||
|
buttonsState = NotificationConfig.ButtonsState.PrimaryButtonConfig(
|
||||||
|
text = resourceReference(R.string.common_activate),
|
||||||
|
onClick = onInitializeClick,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class Info(
|
sealed class Info(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.tangem.features.staking.impl.presentation.state.bottomsheet
|
||||||
|
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||||
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||||
|
|
||||||
|
internal data class TonInitializeAccountBottomSheetConfig(
|
||||||
|
val title: TextReference,
|
||||||
|
val message: TextReference,
|
||||||
|
val footer: TextReference,
|
||||||
|
val onButtonClick: () -> Unit,
|
||||||
|
val isButtonEnabled: Boolean,
|
||||||
|
val isButtonLoading: Boolean,
|
||||||
|
val feeState: FeeState,
|
||||||
|
) : TangemBottomSheetConfigContent
|
||||||
|
|
@ -62,13 +62,6 @@ internal sealed class StakingAlertUM : AlertUM {
|
||||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
data object InitializeAccount : StakingAlertUM() {
|
|
||||||
override val onConfirmClick: (() -> Unit)? = null
|
|
||||||
override val title: TextReference = resourceReference(id = R.string.staking_error_no_validators_title)
|
|
||||||
override val message: TextReference = resourceReference(id = R.string.staking_notification_ton_activate_account)
|
|
||||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
data class RewardsMinimumRequirementsError(
|
data class RewardsMinimumRequirementsError(
|
||||||
val cryptoCurrencyName: String,
|
val cryptoCurrencyName: String,
|
||||||
val cryptoAmountValue: String,
|
val cryptoAmountValue: String,
|
||||||
|
|
|
||||||
|
|
@ -47,11 +47,6 @@ internal class StakingEventFactory(
|
||||||
stateController.updateEvent(alert)
|
stateController.updateEvent(alert)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createInitializeAccountAlert() {
|
|
||||||
val alert = StakingEvent.ShowAlert(alert = StakingAlertUM.InitializeAccount)
|
|
||||||
stateController.updateEvent(alert)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createStakingRewardsMinimumRequirementsErrorAlert(cryptoCurrencyName: String, cryptoAmountValue: String) {
|
fun createStakingRewardsMinimumRequirementsErrorAlert(cryptoCurrencyName: String, cryptoAmountValue: String) {
|
||||||
stateController.updateEvent(
|
stateController.updateEvent(
|
||||||
StakingEvent.ShowAlert(
|
StakingEvent.ShowAlert(
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,11 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun partialUpdateWithDelay() {
|
||||||
|
delay(BALANCE_UPDATE_DELAY)
|
||||||
|
partialUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun fetchCurrencyStatus(delayMillis: Long = 0L) {
|
private suspend fun fetchCurrencyStatus(delayMillis: Long = 0L) {
|
||||||
delay(delayMillis)
|
delay(delayMillis)
|
||||||
fetchCurrencyStatusUseCase(
|
fetchCurrencyStatusUseCase(
|
||||||
|
|
|
||||||
|
|
@ -78,4 +78,8 @@ internal object StakingClickIntentsStub : StakingClickIntents {
|
||||||
override fun showPrimaryClickAlert() {}
|
override fun showPrimaryClickAlert() {}
|
||||||
|
|
||||||
override fun onOpenLearnMoreAboutApproveClick() {}
|
override fun onOpenLearnMoreAboutApproveClick() {}
|
||||||
|
|
||||||
|
override fun onActivateTonAccountNotificationClick() {}
|
||||||
|
|
||||||
|
override fun onActivateTonAccountClick() {}
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +40,7 @@ import java.math.BigDecimal
|
||||||
internal class AddStakingNotificationsTransformer(
|
internal class AddStakingNotificationsTransformer(
|
||||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||||
|
private val isAccountInitializedProvider: Provider<Boolean>,
|
||||||
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||||
private val currencyWarning: CryptoCurrencyWarning?,
|
private val currencyWarning: CryptoCurrencyWarning?,
|
||||||
private val feeError: GetFeeError?,
|
private val feeError: GetFeeError?,
|
||||||
|
|
@ -90,34 +91,40 @@ internal class AddStakingNotificationsTransformer(
|
||||||
BigDecimal.ZERO
|
BigDecimal.ZERO
|
||||||
}
|
}
|
||||||
|
|
||||||
val notifications = buildList {
|
val notifications = if (isAccountInitializedProvider.invoke()) {
|
||||||
// errors
|
buildList {
|
||||||
addErrorNotifications(
|
// errors
|
||||||
prevState = prevState,
|
addErrorNotifications(
|
||||||
feeError = feeError,
|
prevState = prevState,
|
||||||
sendingAmount = sendingAmount,
|
feeError = feeError,
|
||||||
onReload = prevState.clickIntents::getFee,
|
sendingAmount = sendingAmount,
|
||||||
feeValue = feeValue,
|
onReload = prevState.clickIntents::getFee,
|
||||||
)
|
feeValue = feeValue,
|
||||||
addStakingErrorNotifications(stakingError = stakingError, onReload = prevState.clickIntents::getFee)
|
)
|
||||||
// warnings
|
addStakingErrorNotifications(stakingError = stakingError, onReload = prevState.clickIntents::getFee)
|
||||||
addWarningNotifications(
|
// warnings
|
||||||
prevState = prevState,
|
addWarningNotifications(
|
||||||
amountState = amountState,
|
prevState = prevState,
|
||||||
feeState = feeState,
|
amountState = amountState,
|
||||||
sendingAmount = sendingAmount,
|
feeState = feeState,
|
||||||
isFeeCoverage = isFeeCoverage && isEnterAction && !sendingAmount.equals(minimumRequirement),
|
sendingAmount = sendingAmount,
|
||||||
)
|
isFeeCoverage = isFeeCoverage && isEnterAction && !sendingAmount.equals(minimumRequirement),
|
||||||
|
)
|
||||||
|
|
||||||
stakingInfoNotificationsFactory.addInfoNotifications(
|
stakingInfoNotificationsFactory.addInfoNotifications(
|
||||||
notifications = this,
|
notifications = this,
|
||||||
prevState = prevState,
|
prevState = prevState,
|
||||||
sendingAmount = sendingAmount,
|
sendingAmount = sendingAmount,
|
||||||
actionAmount = amountValue,
|
actionAmount = amountValue,
|
||||||
feeValue = feeValue,
|
feeValue = feeValue,
|
||||||
tonBalanceExtraFeeThreshold = TON_BALANCE_EXTRA_FEE_THRESHOLD,
|
tonBalanceExtraFeeThreshold = TON_BALANCE_EXTRA_FEE_THRESHOLD,
|
||||||
)
|
)
|
||||||
}.toImmutableList()
|
}.toImmutableList()
|
||||||
|
} else {
|
||||||
|
buildList {
|
||||||
|
addTonInitializeAccountNotification(prevState)
|
||||||
|
}.toImmutableList()
|
||||||
|
}
|
||||||
|
|
||||||
val isActualSources = with(cryptoCurrencyStatus.value) {
|
val isActualSources = with(cryptoCurrencyStatus.value) {
|
||||||
sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
||||||
|
|
@ -130,7 +137,8 @@ internal class AddStakingNotificationsTransformer(
|
||||||
it is StakingNotification.Error ||
|
it is StakingNotification.Error ||
|
||||||
it is NotificationUM.Error ||
|
it is NotificationUM.Error ||
|
||||||
it is NotificationUM.Warning.NetworkFeeUnreachable ||
|
it is NotificationUM.Warning.NetworkFeeUnreachable ||
|
||||||
it is StakingNotification.Warning.TransactionInProgress
|
it is StakingNotification.Warning.TransactionInProgress ||
|
||||||
|
it is StakingNotification.Warning.InitializeTonAccount
|
||||||
} && isActualSources,
|
} && isActualSources,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -219,7 +227,6 @@ internal class AddStakingNotificationsTransformer(
|
||||||
) {
|
) {
|
||||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||||
val appCurrency = appCurrencyProvider()
|
val appCurrency = appCurrencyProvider()
|
||||||
cryptoCurrencyStatus.currency
|
|
||||||
|
|
||||||
addRentExemptionNotification(
|
addRentExemptionNotification(
|
||||||
rentWarning = currencyCheck.rentWarning,
|
rentWarning = currencyCheck.rentWarning,
|
||||||
|
|
@ -282,6 +289,19 @@ internal class AddStakingNotificationsTransformer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun MutableList<NotificationUM>.addTonInitializeAccountNotification(prevState: StakingUiState) {
|
||||||
|
val isAccountInitialized = isAccountInitializedProvider.invoke()
|
||||||
|
val cryptoCurrencyNetworkIdValue = cryptoCurrencyStatusProvider().currency.network.rawId
|
||||||
|
|
||||||
|
if (isTon(cryptoCurrencyNetworkIdValue) && !isAccountInitialized) {
|
||||||
|
add(
|
||||||
|
StakingNotification.Warning.InitializeTonAccount(
|
||||||
|
onInitializeClick = prevState.clickIntents::onActivateTonAccountNotificationClick,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
val TON_BALANCE_EXTRA_FEE_THRESHOLD = BigDecimal(0.2)
|
val TON_BALANCE_EXTRA_FEE_THRESHOLD = BigDecimal(0.2)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.tangem.features.staking.impl.presentation.state.transformers.ton
|
||||||
|
|
||||||
|
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer
|
||||||
|
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer.ReduceByData
|
||||||
|
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||||
|
import com.tangem.utils.transformer.Transformer
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
internal class CompleteInitializeBottomSheetTransformer(
|
||||||
|
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||||
|
private val minimumTransactionAmount: EnterAmountBoundary?,
|
||||||
|
) : Transformer<StakingUiState> {
|
||||||
|
|
||||||
|
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||||
|
val prevBottomSheetConfig = prevState.bottomSheetConfig ?: return prevState
|
||||||
|
val prevBottomSheetConfigContent =
|
||||||
|
prevBottomSheetConfig.content as? TonInitializeAccountBottomSheetConfig ?: return prevState
|
||||||
|
|
||||||
|
val feeAmount = (prevBottomSheetConfigContent.feeState as? FeeState.Content)
|
||||||
|
?.fee?.amount?.value?.multiply(BigDecimal(FEE_MULTIPLIER)) ?: return prevState
|
||||||
|
|
||||||
|
val confirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data ?: return prevState
|
||||||
|
|
||||||
|
return prevState.copy(
|
||||||
|
amountState = AmountReduceByTransformer(
|
||||||
|
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||||
|
minimumTransactionAmount = minimumTransactionAmount,
|
||||||
|
value = ReduceByData(
|
||||||
|
feeAmount,
|
||||||
|
feeAmount,
|
||||||
|
),
|
||||||
|
).transform(prevState.amountState),
|
||||||
|
confirmationState = confirmationState.copy(
|
||||||
|
reduceAmountBy = feeAmount,
|
||||||
|
),
|
||||||
|
bottomSheetConfig = prevBottomSheetConfig.copy(
|
||||||
|
content = prevBottomSheetConfigContent.copy(
|
||||||
|
isButtonLoading = true,
|
||||||
|
isButtonEnabled = false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val FEE_MULTIPLIER = 1.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.tangem.features.staking.impl.presentation.state.transformers.ton
|
||||||
|
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||||
|
import com.tangem.utils.transformer.Transformer
|
||||||
|
|
||||||
|
internal class SetFeeErrorToTonInitializeBottomSheetTransformer : Transformer<StakingUiState> {
|
||||||
|
|
||||||
|
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||||
|
val prevBottomSheetConfig = prevState.bottomSheetConfig ?: return prevState
|
||||||
|
val prevBottomSheetConfigContent =
|
||||||
|
prevBottomSheetConfig.content as? TonInitializeAccountBottomSheetConfig ?: return prevState
|
||||||
|
|
||||||
|
return prevState.copy(
|
||||||
|
bottomSheetConfig = prevBottomSheetConfig.copy(
|
||||||
|
content = prevBottomSheetConfigContent.copy(
|
||||||
|
isButtonEnabled = false,
|
||||||
|
feeState = FeeState.Error,
|
||||||
|
isButtonLoading = false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.tangem.features.staking.impl.presentation.state.transformers.ton
|
||||||
|
|
||||||
|
import com.tangem.blockchain.common.transaction.Fee
|
||||||
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||||
|
import com.tangem.utils.Provider
|
||||||
|
import com.tangem.utils.transformer.Transformer
|
||||||
|
|
||||||
|
internal class SetFeeToTonInitializeBottomSheetTransformer(
|
||||||
|
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||||
|
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||||
|
private val fee: Fee,
|
||||||
|
private val isFeeApproximate: Boolean,
|
||||||
|
) : Transformer<StakingUiState> {
|
||||||
|
|
||||||
|
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||||
|
val prevBottomSheetConfig = prevState.bottomSheetConfig ?: return prevState
|
||||||
|
val prevBottomSheetConfigContent =
|
||||||
|
prevBottomSheetConfig.content as? TonInitializeAccountBottomSheetConfig ?: return prevState
|
||||||
|
|
||||||
|
val isFeeConvertibleToFiat = feeCryptoCurrencyStatus?.currency?.network?.hasFiatFeeRate == true
|
||||||
|
return prevState.copy(
|
||||||
|
bottomSheetConfig = prevBottomSheetConfig.copy(
|
||||||
|
content = prevBottomSheetConfigContent.copy(
|
||||||
|
isButtonEnabled = true,
|
||||||
|
isButtonLoading = false,
|
||||||
|
feeState = FeeState.Content(
|
||||||
|
fee = fee,
|
||||||
|
rate = feeCryptoCurrencyStatus?.value?.fiatRate,
|
||||||
|
isFeeConvertibleToFiat = isFeeConvertibleToFiat,
|
||||||
|
appCurrency = appCurrencyProvider(),
|
||||||
|
isFeeApproximate = isFeeApproximate,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.tangem.features.staking.impl.presentation.state.transformers.ton
|
||||||
|
|
||||||
|
import com.tangem.common.ui.R
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||||
|
import com.tangem.utils.transformer.Transformer
|
||||||
|
|
||||||
|
internal class ShowTonInitializeBottomSheetTransformer(
|
||||||
|
private val onDismiss: () -> Unit,
|
||||||
|
) : Transformer<StakingUiState> {
|
||||||
|
|
||||||
|
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||||
|
return prevState.copy(
|
||||||
|
bottomSheetConfig = TangemBottomSheetConfig(
|
||||||
|
isShown = true,
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
content = TonInitializeAccountBottomSheetConfig(
|
||||||
|
title = resourceReference(R.string.staking_account_initialization_title),
|
||||||
|
message = resourceReference(R.string.staking_account_initialization_message),
|
||||||
|
footer = resourceReference(R.string.staking_account_initialization_footer),
|
||||||
|
onButtonClick = prevState.clickIntents::onActivateTonAccountClick,
|
||||||
|
isButtonEnabled = false,
|
||||||
|
feeState = FeeState.Loading,
|
||||||
|
isButtonLoading = false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,8 +28,10 @@ import com.tangem.features.staking.impl.presentation.state.StakingStep
|
||||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingActionSelectionBottomSheetConfig
|
import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingActionSelectionBottomSheetConfig
|
||||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingInfoBottomSheetConfig
|
import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingInfoBottomSheetConfig
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||||
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.StakingActionSelectorBottomSheet
|
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.StakingActionSelectorBottomSheet
|
||||||
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.StakingInfoBottomSheet
|
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.StakingInfoBottomSheet
|
||||||
|
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.TonInitializeAccountBottomSheet
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
@ -83,6 +85,7 @@ fun StakingBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
|
||||||
is StakingInfoBottomSheetConfig -> StakingInfoBottomSheet(bottomSheetConfig)
|
is StakingInfoBottomSheetConfig -> StakingInfoBottomSheet(bottomSheetConfig)
|
||||||
is GiveTxPermissionBottomSheetConfig -> GiveTxPermissionBottomSheet(bottomSheetConfig)
|
is GiveTxPermissionBottomSheetConfig -> GiveTxPermissionBottomSheet(bottomSheetConfig)
|
||||||
is StakingActionSelectionBottomSheetConfig -> StakingActionSelectorBottomSheet(bottomSheetConfig)
|
is StakingActionSelectionBottomSheetConfig -> StakingActionSelectorBottomSheet(bottomSheetConfig)
|
||||||
|
is TonInitializeAccountBottomSheetConfig -> TonInitializeAccountBottomSheet(bottomSheetConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
package com.tangem.features.staking.impl.presentation.ui.bottomsheet
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
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.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.tangem.blockchain.common.Amount
|
||||||
|
import com.tangem.blockchain.common.AmountType
|
||||||
|
import com.tangem.blockchain.common.transaction.Fee
|
||||||
|
import com.tangem.common.ui.R
|
||||||
|
import com.tangem.core.ui.components.SpacerH
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
|
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||||
|
import com.tangem.core.ui.components.buttons.common.TangemButton
|
||||||
|
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||||
|
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||||
|
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
|
||||||
|
import com.tangem.core.ui.extensions.resolveReference
|
||||||
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.core.ui.res.TangemThemePreview
|
||||||
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||||
|
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||||
|
import com.tangem.features.staking.impl.presentation.ui.block.StakingFeeBlock
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun TonInitializeAccountBottomSheet(config: TangemBottomSheetConfig) {
|
||||||
|
TangemBottomSheet<TonInitializeAccountBottomSheetConfig>(
|
||||||
|
config = config,
|
||||||
|
containerColor = TangemTheme.colors.background.tertiary,
|
||||||
|
) { content ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(
|
||||||
|
start = TangemTheme.dimens.spacing16,
|
||||||
|
end = TangemTheme.dimens.spacing16,
|
||||||
|
bottom = TangemTheme.dimens.spacing16,
|
||||||
|
)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
SpacerH(height = 16.dp)
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.img_ton_22),
|
||||||
|
modifier = Modifier.size(56.dp),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(height = 24.dp)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
text = content.title.resolveReference(),
|
||||||
|
style = TangemTheme.typography.h3,
|
||||||
|
color = TangemTheme.colors.text.primary1,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(height = 16.dp)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
text = content.message.resolveReference(),
|
||||||
|
style = TangemTheme.typography.body2,
|
||||||
|
color = TangemTheme.colors.text.secondary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(height = 24.dp)
|
||||||
|
|
||||||
|
StakingFeeBlock(content.feeState)
|
||||||
|
|
||||||
|
SpacerH(height = 12.dp)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
text = content.footer.resolveReference(),
|
||||||
|
style = TangemTheme.typography.caption2,
|
||||||
|
color = TangemTheme.colors.text.tertiary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(height = 20.dp)
|
||||||
|
|
||||||
|
TangemButton(
|
||||||
|
text = stringResourceSafe(R.string.common_activate),
|
||||||
|
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_tangem_24),
|
||||||
|
onClick = content.onButtonClick,
|
||||||
|
colors = TangemButtonsDefaults.primaryButtonColors,
|
||||||
|
showProgress = content.feeState is FeeState.Loading || content.isButtonLoading,
|
||||||
|
enabled = content.isButtonEnabled,
|
||||||
|
size = TangemButtonSize.WideAction,
|
||||||
|
textStyle = TangemTheme.typography.subtitle1,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
|
||||||
|
SpacerH(height = 8.dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// region Preview
|
||||||
|
@Composable
|
||||||
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
private fun Preview_TonInitializeAccountBottomSheetContent() {
|
||||||
|
TangemThemePreview {
|
||||||
|
TonInitializeAccountBottomSheet(
|
||||||
|
config = TangemBottomSheetConfig(
|
||||||
|
isShown = true,
|
||||||
|
onDismissRequest = {},
|
||||||
|
content = TonInitializeAccountBottomSheetConfig(
|
||||||
|
title = resourceReference(R.string.staking_account_initialization_title),
|
||||||
|
message = resourceReference(R.string.staking_account_initialization_message),
|
||||||
|
footer = resourceReference(R.string.staking_account_initialization_footer),
|
||||||
|
onButtonClick = {},
|
||||||
|
isButtonEnabled = true,
|
||||||
|
isButtonLoading = false,
|
||||||
|
feeState = FeeState.Content(
|
||||||
|
fee = Fee.Common(
|
||||||
|
amount = Amount(
|
||||||
|
currencySymbol = "MATIC",
|
||||||
|
value = BigDecimal(0.159806),
|
||||||
|
decimals = 18,
|
||||||
|
type = AmountType.Coin,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
rate = BigDecimal.ONE,
|
||||||
|
appCurrency = AppCurrency.Default,
|
||||||
|
isFeeApproximate = false,
|
||||||
|
isFeeConvertibleToFiat = true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion Preview
|
||||||
Loading…
Add table
Add a link
Reference in a new issue