diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountFieldContainer.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountFieldContainer.kt index db265212a0..12335b79ad 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountFieldContainer.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/ui/AmountFieldContainer.kt @@ -1,6 +1,9 @@ package com.tangem.common.ui.amountScreen.ui import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -127,6 +130,8 @@ private fun AmountInfoMain(amountUM: AmountState, modifier: Modifier = Modifier) AnimatedContent( targetState = amountUM, modifier = modifier, + contentKey = { amountUM.javaClass }, // Show animation only when the state type changes [Empty -> Data] + transitionSpec = { fadeIn().togetherWith(fadeOut()) }, ) { currentAmount -> Column( verticalArrangement = Arrangement.spacedBy(2.dp), diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt index 8c2f75bb85..66b28de458 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt @@ -274,6 +274,14 @@ sealed class NotificationUM(val config: NotificationConfig) { title = resourceReference(id = R.string.yield_module_balance_info_sheet_title, wrappedList(tokenName)), subtitle = resourceReference(id = R.string.yield_module_balance_info_sheet_subtitle), ) + + data class YieldSupplyNotAllAmountSupplied(val formattedAmount: String, val symbol: String) : Warning( + title = resourceReference( + id = R.string.yield_module_amount_not_transfered_to_aave_title, + formatArgs = wrappedList(formattedAmount, symbol), + ), + subtitle = TextReference.EMPTY, + ) } open class Info( diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt index 0c5042c6d8..17aa2184d7 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt @@ -20,7 +20,6 @@ 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.currency.yieldSupplyKey -import com.tangem.domain.models.currency.yieldSupplyNotAllAmountSupplied import com.tangem.domain.models.staking.YieldBalance import com.tangem.domain.staking.utils.getTotalWithRewardsStakingBalance import com.tangem.utils.StringsSigns.DASH_SIGN @@ -271,8 +270,7 @@ class TokenItemStateConverter( isFlickering = status.value.isFlickering(), icons = buildList { if (status.value.yieldSupplyStatus?.isActive == true && - status.value.yieldSupplyStatus?.isAllowedToSpend == false || - status.yieldSupplyNotAllAmountSupplied() + status.value.yieldSupplyStatus?.isAllowedToSpend == false ) { TokenItemState.FiatAmountState.Content.IconUM( iconRes = R.drawable.ic_alert_triangle_20, diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index ee000bb82f..d03a24ea12 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -1675,31 +1675,82 @@ Nein, alles senden Um %s XTZ reduziert Damit Sie beim nächsten Aufladen Ihrer Brieftasche keine erhöhte Provision zahlen, soll der Betrag um %s XTZ reduziert werden + Wenn der Yield-Modus aktiviert ist, gehen alle zukünftigen Einzahlungen an diese Adresse an Aave. Du kannst über Dein Guthaben weiterhin frei verfügen. + Deine %s wird an Aave übermittelt + Die Bereitstellung von %1$s %2$s für Aave steht aus + Genehmigen + Die Genehmigung Deines Tokens wurde widerrufen. Erteilen diese erneut, um die Servicefunktionalität fortzusetzen. + Genehmigung erforderlich + Die Gebühr wird abgezogen und Dein Vermögen wird erneut verliehen. + Um weiterhin Geld verdienen zu können, ist eine Genehmigung erforderlich. + Genehmigung bestätigen + Deine Gelder werden derzeit dem Aave-Protokoll bereitgestellt, Du kannst sie jedoch jederzeit verwalten. + Deine%s ist in Aave hinterlegt Chart konnte nicht geladen werden... Der erhaltene Betrag %1$s %2$s wurde nicht auf Aave eingezahlt. + APY %1$s%% + Verfügbar + Aktueller effektiver Jahreszins + Beim Aufladen zum Ausleihen wird eine Netzwerkgebühr von maximal %1$s vom Guthaben abgezogen. + Die Netzwerkgebühr ist derzeit zu hoch, um die Kreditvergabe durchzuführen. Die Mittel werden bereitgestellt, sobald sie auf %1$s oder darunter fallen. + Meine Mittel + Dein %1$s ist nun bei Aave hinterlegt und bringt Zinsen ein. Du besitzt einen %2$s-Token, der Dein Guthaben repräsentiert und mit der Zeit wächst. Wenn Du mehr Geld einzahlst, wird dieses an Aave weitergeleitet, um Zinsen abzüglich einer Transaktionsgebühr zu erwirtschaften. + Ertragsmodus + Gesamtverdienst + Übertragungen zu Aave + Entdecke Aave + Dies ist die aktuelle Liefergebühr auf %s. Die tatsächlichen Kosten werden auf der Registerkarte \"Aktivierung\" angezeigt. Aktuelle Gebühr + Alle zukünftigen %s-Einzahlungen werden automatisch an Aave geliefert, wobei die Transaktionsgebühr abgezogen wird. + Bei jeder zukünftigen Aufladung wird eine Netzwerkgebühr von ungefähr %1$s (%2$s) abgezogen, die Ihr Limit von %3$s (%4$s) nicht überschreitet. + Wenn die Netzwerkgebühren über die maximale Gebühr steigen, wird die Transaktion erst durchgeführt, wenn diese sinken. Du kannst dieses Limit später ändern. Maximale Gebühr - Dies ist die niedrigste Einzahlung, die an Aave gesendet werden kann. Um Einzahlungen rentabel zu halten, verarbeiten wir sie nicht, wenn die Netzwerkgebühren 4 % des Betrags übersteigen. + Der Mindestbetrag wird aus der aktuellen Netzwerkgebühr berechnet, um sicherzustellen, dass er 4%% nicht überschreitet, was den Mindestbetrag %1$s (%2$s) ergibt. + Mindestaufladung Gebührenpolitik - Die Netzwerkgebühr ist derzeit zu hoch. Warte, bis sie unter Dein Limit fällt. + Tangem erhebt außerdem eine Servicegebühr von 3% auf den erzielten Ertrag. + Deine Gelder werden automatisch an Aave überwiesen, sobald die Netzwerkgebühren niedriger sind oder Dein Guthaben den erforderlichen Mindestbetrag erreicht. Historische Renditen - Sofortige Auszahlung + Die Freigabe für Deine Token im Yield-Modus wurde widerrufen. Öffne den Token, um die Berechtigung erneut zu erteilen. + Token-Genehmigung erforderlich + Prüfe Deine Netzwerkverbindung + Informationen zu den Netzwerkgebühren nicht erreichbar + Jede Einzahlung, die Du tätigst, wird automatisch an Aave weitergeleitet. + Automatische Übertragung zu Aave + Senden, tauschen oder verkaufen Deine Gelder sofort, wann immer Du willst. + Jederzeit Zugriff auf Dein Geld Wie funktioniert das? + Aave ist ein dezentrales Protokoll, das einen Gesamtwert von über 81,9 Milliarden US-Dollar verwaltet. + Dezentral und selbstverwahrend + Durch die Nutzung dieses Dienstes erklärst Du Dich mit provider\n%1$s und %2$s einverstanden Mit Aave verbinden - Aave %1$s • Variabler Zinssatz + Aave %1$s%% • Variabler Zinssatz Aave Durchschnitt %s Renditen des letzten Jahres + Der aktuelle Zinssatz ist immer variabel und wird automatisch vom Aave On-Chain-Smart-Contract auf der Grundlage von Angebot und Nachfrage in Echtzeit berechnet. Unterstützt durch Der Zinssatz ist variabel + Wenn Du dein Guthaben auflädst, wird es automatisch an Aave weitergeleitet, um Zinsen zu verdienen. zur Deckung der Transaktionsgebühr wird ein Betrag von %s abgezogen. Beginn des Verdienstes + Dein %s wird an Aave übermittelt, bleibt aber verwaltbar. Siehe Gebührenrichtlinie + Deine nächste Aufladung wird automatisch an Aave weitergeleitet. Aktiv Pausiert + Deaktiviere den Yield-Modus + Wenn Du diese Option deaktivierst, wird Dein Geld von Aave auf %s in Deiner Wallet abgehoben und es werden keine Belohnungen mehr verdient. + Die Netzwerkgebühr wird von dem Betrag, den Du abhebst, abgezogen. Effektiver Jahreszins für Versorgung + Effektiver Jahreszins Lass Dein Geld arbeiten – verdiene Zinsen auf Dein Guthaben. - Verdienst auf Dein Guthaben + Zinsen fallen automatisch an + Ertragsmodus + Bearbeitung Deiner Einzahlung Lass dein Guthaben arbeiten + Automatisch + Einzahlung von %1$s %2$s zur Deckung der Netzwerkgebühr für Transaktionen + Die Gebühr %s kann nicht gedeckt werden Der Stakingservice ist derzeit nicht verfügbar. Bitte versuche es später erneut. Einnahmen nicht verfügbar Chart konnte nicht geladen werden... diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 6a2f5f1caf..4a8daa7d9e 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -1106,6 +1106,7 @@ Compatible con Web 3.0 Se requiere una transacción entrante de al menos %1$s para proceder Fondos insuficientes + Al aprobar, permites que el contrato inteligente use tus tokens en futuras transacciones. Tasa Fija La red cobrará una tasa de aprobación del token para verificar que usted autoriza el uso de su token para el intercambio. Intercambie más tokens a mejores tasas directamente en su billetera. @@ -1400,6 +1401,7 @@ Tenemos algún tipo de problema Todas las dApps desconectadas Permitir gastar + Al aprobar, permites que la dApp o el contrato inteligente utilicen los tokens en futuras transacciones. Dirección Conectar Cargando @@ -1474,4 +1476,82 @@ No, enviar todo Reducir en %s XTZ Para evitar pagar una comisión mayor la próxima vez que recargue su billetera, reduzca el importe en %s XTZ + Con el modo Rendimiento activo, todos los depósitos futuros a esta dirección irán a Aave. Puede seguir gestionando sus fondos libremente. + Su %s se suministra a Aave + El suministro de %1$s %2$s a Aave está pendiente + Aprobar + Se ha revocado la aprobación de su token. Concédalo de nuevo para reanudar el servicio. + Aprobación necesaria + Se le descontará la comisión y se le volverán a prestar sus activos. + Para seguir ganando, se requiere aprobación. + Confirmar aprobación + Sus fondos se suministran actualmente al protocolo Aave, pero puede gestionarlos en cualquier momento. + Su %s está depositado en Aave + No se puede cargar el gráfico... + La cantidad recibida, %1$s %2$s no fue suministrada a Aave. + APY %1$s%% + Disponible + APY actual + En las recargas para préstamos, se deducirá del saldo una comisión de red no superior a %1$s. + La tasa de red es actualmente demasiado alta para ejecutar préstamos. Los fondos se suministrarán una vez que baje a %1$s o menos. + Mis fondos + Su %1$s está ahora depositado en Aave y devenga intereses. Tiene un token%2$s, que representa su saldo y crece con el tiempo. Cuando deposite más fondos, estos se suministrarán a Aave para ganar intereses, menos una comisión por transacción. + Modo de rendimiento + Ganancias totales + Transferencias a Aave + Explore Aave + Esta es la tarifa de suministro actual en %s. El coste real se mostrará en la pestaña de activación. + Tarifa actual + Todos los depósitos futuros %s se proporcionarán a Aave automáticamente, con la tarifa de transacción deducida. + Se deducirá una comisión de red aproximada de %1$s (%2$s) de cada recarga futura, y no superará su límite de %3$s (%4$s). + Si las tarifas de red superan la tarifa máxima, la transacción no se realizará hasta que disminuyan. Puede cambiar este límite más adelante. + Tarifa máxima + El monto mínimo se calcula a partir de la tarifa de red actual para garantizar que no exceda 4%%, lo que hace que el mínimo sea %1$s (%2$s). + Recarga mínima + Política de tarifas + Tangem también cobra una comisión de servicio del 3% sobre el rendimiento obtenido. + Sus fondos se suministrarán automáticamente a Aave una vez que las comisiones de red sean más bajas o su saldo alcance el importe mínimo requerido. + Rendimientos históricos + Se ha revocado la autorización para su token en el modo Rendimiento. Abra el token para volver a conceder el permiso. + Se necesita la aprobación de Token + Compruebe su conexión de red + Información de tarifas de red inaccesible + Cada depósito que realice se suministrará a Aave automáticamente. + Transferencia automática a Aave + Envíe, intercambie o venda sus fondos al instante, cuando quiera. + Acceda a sus fondos en cualquier momento + ¿Cómo funciona? + Aave es un protocolo descentralizado que administra más de 81.9 billones de dólares en valor total. + Descentralizado y autocustodiado + Al utilizar este servicio, usted acepta que el proveedor\n%1$s y %2$s + Conectar Aave + Aave %1$s%% - Tipo de interés variable + Aave + Promedio %s + Resultados del año pasado + La tasa de interés actual siempre es variable y calculada automáticamente por el contrato inteligente onchain de Aave, en función de la oferta y la demanda en tiempo real. + Desarrollado por + El tipo de interés es variable + Cuando recargue, sus fondos se enviarán automáticamente a Aave para comenzar a ganar intereses. %s se deducirá para cubrir la tarifa de transacción. + Suministro de activos + Su %s se suministrará a Aave, pero seguirá siendo gestionable. + Ver política de tarifas + Sus próximas recargas se suministrarán automáticamente a Aave. + Activo + En pausa + Desactivar el modo de rendimiento + Al desactivar esto, retirará sus fondos de Aave a %s en su billetera y dejará de ganar recompensas. + La comisión de red se deducirá del importe que retire. + Suministro APY + APY + Deje que sus fondos hagan el trabajo mientras usted mantiene el control. + Los intereses se devengan automáticamente + Modo de rendimiento + Procesando su depósito + Haga que sus activos trabajen para usted + Automático + Deposite algo de %1$s %2$s para cubrir la tarifa de red para las transacciones + No se puede cubrir la tarifa %s + El servicio de intereses no está disponible en este momento. Vuelva a intentarlo más tarde. + Ganancias no disponibles diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 868ad2f695..8e7c887222 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -1080,6 +1080,7 @@ Compatible avec Web 3.0 Une transaction entrante d\'au moins de %1$s est requise pour continuer Fonds insuffisants + En approuvant, vous autorisez le contrat intelligent à utiliser vos jetons dans de futures transactions. Taux fixe Le réseau facturera des frais d\'approbation de jeton pour vérifier que vous autorisez l\'utilisation de votre jeton pour l\'échange. Échangez plus de jetons à de meilleurs taux directement dans votre portefeuille. @@ -1386,6 +1387,7 @@ Nous avons un problème. Toutes les dApps sont déconnectées Autoriser à dépenser + En approuvant, vous autorisez la dApp ou le contrat intelligent à utiliser les jetons dans de futures transactions. Adresse Connecter Chargement @@ -1453,4 +1455,80 @@ Non, envoyer toute la somme Réduire de %s XTZ Pour ne pas payer un fraid de commissions élevé la prochaine fois que vous rechargez votre portefeuille, veuillez réduire le montant de %s XTZ + Vos fonds sont actuellement fournis au protocole Aave, mais vous pouvez les gérer à tout moment. + Vos %s sont fournis à Aave. + Le transfert de %1$s %2$s vers Aave est en attente. + Donnez votre accord + Un problème est survenu lors de votre précédente approbation, nous avons donc besoin d\'une nouvelle approbation. Choisissez comment vous souhaitez procéder. + Autorisation nécessaire + Les frais seront prélevés et vos actifs seront à nouveau prêtés. + Pour continuer à percevoir des revenus, une autorisation est nécessaire. + Confirmer l\'approbation + Vos %s sont déposés dans Aave. + Impossible de charger le graphique... + Le montant reçu, %1$s %2$s, n\'a pas été fourni à Aave. + APY %1$s%% + Disponible + APY actuel + Lors du rechargement pour le dépôt, des frais de réseau ne dépassant pas %1$s seront déduits du solde. + Les frais de réseau sont actuellement trop élevés pour permettre l\'exécution des prêts. Les fonds seront versés dès qu\'ils auront baissé à %1$s ou moins. + Mes fonds + Vos %1$s sont désormais déposés chez Aave et rapportent des intérêts. Vous détenez %2$s tokens, ce qui représente votre solde et augmente au fil du temps. Lorsque vous déposez davantage de fonds, ceux-ci sont fournis à Aave afin de rapporter des intérêts, moins les frais de transaction. + Gagner + Total des gains + Transferts vers Aave + Découvrez Aave + Il s\'agit des frais d\'approvisionnement actuels sur %s. Le coût réel sera indiqué dans l\'onglet Activation. + Frais actuels + Tous les futurs dépôts %s seront automatiquement fournis à Aave, après déduction des frais de transaction. + Des frais de réseau d\'environ %1$s (%2$s) seront déduits de chaque recharge future, sans dépasser votre limite de %3$s (%4$s). + Si les frais de réseau dépassent le montant maximal, la transaction ne sera pas effectuée tant qu\'ils n\'auront pas diminué. Vous pouvez modifier cette limite ultérieurement. + Frais maximaux + Le montant minimum est calculé à partir des frais de réseau actuels afin de garantir qu\'il ne dépasse pas 4 %, ce qui donne un minimum de %1$s (%2$s). + Recharge minimale + Politique tarifaire + Tangem prélève également des frais de service de 3% sur les revenus générés. + Vos fonds seront automatiquement transférés vers Aave dès que les frais de réseau seront moins élevés ou que votre solde atteindra le montant minimum requis. + Rendements historiques + Approbations de tokens nécessaires + Vérifiez votre connexion réseau. + Informations sur les frais de réseau inaccessibles + Chaque dépôt que vous effectuez sera automatiquement transféré à Aave. + Transfert automatique vers Aave + Envoyez, échangez ou vendez vos fonds instantanément, quand vous le souhaitez. + Accédez à vos fonds à tout moment + Comment ça marche ? + Aave est un protocole décentralisé qui gère plus de 81,9 milliards de dollars en valeur totale. + Décentralisé et auto-détenu + En utilisant ce service, vous acceptez les conditions générales du fournisseur %1$s et %2$s. + Connecter Aave + Aave %1$s%% • Taux d\'intérêt variable + Aave + Moyenne %s + Rendements de l\'année dernière + Le taux d\'intérêt actuel est toujours variable et calculé automatiquement par le contrat intelligent Aave, en fonction de l\'offre et de la demande en temps réel. + Alimenté par + Le taux d\'intérêt est variable. + Lorsque vous effectuez un dépôt, vos fonds sont automatiquement transférés vers Aave afin de commencer à générer des intérêts. %s sera déduit pour couvrir les frais de transaction. + Actifs d\'approvisionnement + Vos %s seront fournis à Aave, mais resteront gérables. + Voir la politique tarifaire + Vos prochains dépôts seront automatiquement transférés vers Aave. + Actif + En pause + Désactiver le mode rendement + En désactivant cela, vos fonds seront retirés d\'Aave vers %s dans votre portefeuille et vous ne gagnerez plus de récompenses. + Les frais de réseau seront déduits du montant que vous retirez. + Rendement annuel brut (APY) + APY + Laissez vos fonds travailler pour vous tout en gardant le contrôle. + Les intérêts sont cumulés automatiquement. + Mode de rendement + Traitement de votre dépôt + Faites fructifier vos actifs + Automatique + Déposez %1$s %2$s pour couvrir les frais de réseau liés aux transactions. + Impossible de couvrir les frais %s + Le service d\'intérêt n\'est pas disponible pour le moment. Veuillez réessayer plus tard. + Gains indisponibles diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index e23ac2ff8f..1b9d2b102f 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -23,6 +23,8 @@ アカウントを復元できません アーカイブ済み アカウントをアーカイブできませんでした。しばらくしてからもう一度お試しください。 + このアカウントは紹介プログラムに参加しています。 + このアカウントはアーカイブできません。 アカウントを作成できませんでした。しばらくしてからもう一度お試しください。 アカウントを作成しました アカウントをアーカイブする @@ -42,6 +44,8 @@ アカウントを編集 %1$s ( %2$s内) メインアカウント + すでにアクティブアカウントの上限%1$s件を超えています。復元するには、1つをアーカイブしてください。 + アカウントを復元できません アカウントが回復しました アカウントを長押しして並べ替える 編集を続ける @@ -1738,14 +1742,13 @@ 次回ウォレットにチャージするときに手数料の増加を避けるには、金額を%s XTZ減らしてください。 あなたの資金は現在Aaveプロトコルに供給されていますが、いつでも管理できます。 %sはAaveに供給されています - 受け取った金額%1$s %2$sはAaveに入金されませんでした。 + Aaveへの%1$s %2$sの供給は保留中です 承認する 前回の承認に問題があったため、新しい承認が必要です。手続き方法を選択してください。 承認が必要 手数料が差し引かれ、あなたの資産は再び貸し出されます。 引き続き収益を得るには承認が必要です。 承認を確定する - 資産残高に関するテキスト [プレースホルダー] あなたの%sはAaveに預けられています チャートを読み込めません・・ 受け取った金額%1$s %2$sはAaveに入金されませんでした。 @@ -1763,19 +1766,19 @@ これは%sの現在の供給手数料です。実際のコストはアクティベーションタブに表示されます。 現在の手数料 今後の%sの入金はすべて、取引手数料が差し引かれて自動的にAaveに供給されます。 + 今後のチャージごとに、おおよそ%1$s(%2$s)のネットワーク手数料が差し引かれますが、上限の%3$s(%4$s)を超えることはありません。 ネットワーク手数料が上限手数料を超えた場合、手数料が下がるまで取引は成立しません。この制限は後で変更できます。 最大手数料 - これがAaveに供給できる最小金額です。利回りモードの収益性を保つため、ネットワーク手数料が金額の4%を超える場合は資産を供給しません。 + 最小金額は現在のネットワーク手数料に基づいて計算されており、手数料が4%を超えないように設定されています。その結果、最小金額は%1$s(%2$s)となります。 最低入金額 手数料ポリシー Tangemはまた、得られた利回りに対して3%のサービス手数料を差し引きます。 ネットワーク手数料が下がるか、残高が最低必要額に達すると、資金は自動的にAaveに供給されます。 過去のリターン - ここに説明を入力してください。1〜3行が理想的です。[プレースホルダー] トークンの承認が必要 ネットワーク接続を確認してください ネットワーク手数料についての情報にアクセスできません - アカウントへの入金はすべて自動的にAaveに貸し出されます。 + あなたが行うすべての入金は、自動的にAaveへ供給されます。 Aaveへの自動送金 いつでも、即座に資金を送信、交換、売却できます。 いつでも資金にアクセス可能 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 9b73434b2d..143ab7e150 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -395,6 +395,7 @@ Больше провайдеров на подходе.\nСледите за обновлениями! Провайдер Лучший курс + Лучший выбор Доступно до %s Доступно с %s Недоступно для этой пары @@ -1236,6 +1237,7 @@ Отправка средств станет доступной после завершения транзакции(-ий) в сети %s Продажа %s в данный момент не поддерживается ни одним провайдером. Мы работаем над добавлением новых возможностей. Следите за нашими новостями. Стейкинг %s в данный момент не поддерживается ни одним провайдером. Мы работаем над добавлением новых возможностей. Следите за нашими новостями. + Разрешение было отозвано. Ваши средства остаются в Yield сервисе. Чтобы совершать операции, перейдите в Yield сервис и снова выдайте разрешение. Сгенерировать XPUB Скрыть Вы скрываете токен с главного экрана, но в любой момент сможете добавить его обратно через страницу управления токенами. @@ -1494,6 +1496,7 @@ Похоже, возникла проблема Все dapps отключены Разрешение на использование + Подтверждая, вы разрешаете смарт-контракту использовать ваши токены в будущих транзакциях. Адрес Подключение Загрузка @@ -1569,14 +1572,15 @@ Нет, отправить все Уменьшить на %s XTZ Чтобы не платить повышенную комиссию при следующем пополнении кошелька, уменьшите сумму на %s XTZ - Ваши средства сейчас размещены в протоколе AAVE, но вы можете управлять ими в любое время. + При активном режиме доходности все будущие депозиты на этот адрес будут направляться в Aave. Вы по-прежнему можете свободно управлять своими средствами. Ваш %s внесён в Aave Выдать разрешение - Что-то пошло не так с вашим предыдущим разрешением, поэтому требуется новое. Выберите, как хотите продолжить. + Разрешение для вашего токена было отозвано. Выдайте его снова, чтобы продолжить работу сервиса. Необходимо разрешение Комиссия будет списана, и ваши активы снова начнут приносить доход. Чтобы продолжить зарабатывать, нужно выдать разрешение. Подтвердить разрешение + Ваши средства в данный момент размещены в протоколе Aave, но вы можете воспользоваться ими в любое время. Ваш %s внесён в Aave Невозможно загрузить график Полученная сумма, %1$s %2$s, не была зачислена на Aave. @@ -1599,6 +1603,7 @@ Tangem взимает комиссию за обслуживание в размере 3% от полученного дохода. Ваши средства будут автоматически переведены в Aave, как только комиссия сети снизится или баланс достигнет минимально необходимой суммы. Историческая доходность + Разрешение для вашего токена в Yield сервисе было отозвано. Откройте токен, чтобы выдать разрешение снова. Необходимо разрешение для токена Проверьте ваше интернет соединение Информация о комиссии недоступна @@ -1632,13 +1637,13 @@ APY Пусть ваши деньги работают — зарабатывайте проценты на свой баланс. Проценты начисляются автоматически. - Доходность + Режим доходности Отправка ваших средств Пусть ваш баланс работает на вас! Автоматически Внесите немного %1$s %2$s, чтобы покрыть комиссию сети за транзакции. Невозможно покрыть комиссию в %s - Сервис начисления процентов в данный момент недоступен. Пожалуйста, попробуйте позже. - Данные о доходе недоступны + Сервис доходности в данный момент недоступен. Пожалуйста, попробуйте позже. + Режим доходности недоступен Невозможно загрузить график diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index b13f5ecb1d..429d57b4f6 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -1086,6 +1086,7 @@ Web 3.0 сумісність Для відправки потрібна вхідна транзакція на суму не менше %1$s Недостатньо коштів + Підтверджуючи, ви дозволяєте смартконтракту використовувати ваші токени в майбутніх транзакціях. Мережа стягує комісію за схвалення токену за підтвердження, що саме ви дозволяєте використовувати ваш токен для обміну. Обмінюйте більше токенів за вигіднішим курсом прямо у своєму гаманці. З\'явився новий провайдер обмінів! @@ -1366,6 +1367,7 @@ Обрана не вірна картка або кільце Схоже, виникла проблема Усі dApps відключені + Підтверджуючи, ви дозволяєте dApp або смартконтракту використовувати токени в майбутніх транзакціях. Адреса Підключення Мережа @@ -1431,4 +1433,5 @@ Зменшити на %s XTZ Щоб не платити підвищену комісію при наступному поповненні гаманця, зменште суму на %s XTZ Це найменший депозит, який можна надіслати в Aave. Щоб депозити залишалися прибутковими, ми не обробляємо їх, коли комісія мережі перевищує 4% від суми. + Дозвіл для вашого токена в режимі Yield було відкликано. Відкрийте токен, щоб надати дозвіл знову. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index c32a04da24..f93fca2b20 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -249,6 +249,7 @@ Enable Enabled Error + Estimated fee Swap Explore Explore transaction history @@ -484,7 +485,7 @@ Provider Best rate FCA Warning List - Great rate + Best choice Provider in FCA warning list Available up to %s Available from %s @@ -1369,7 +1370,7 @@ Sending funds will be available once the pending transaction(s) in network %s is complete Selling %s is not supported by current providers, but we are working to add more options. Staking %s is not supported by current providers, but we are working to add more options. - Text here + Approval has been revoked. Your funds remain in Yield mode. To perform actions, please go to Yield mode and grant permission again. Generate XPUB Hide You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. @@ -1812,16 +1813,16 @@ No, send all Reduce by %s XTZ To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ - Your funds are currently supplied to the Aave protocol, but you can manage them at any time. + With Yield mode active, all future deposits to this address will go to Aave. You can still manage your funds freely. Your %s is supplied to Aave Supplying %1$s %2$s to Aave is pending Give Approve - Something went wrong with your previous approval, so we need a new one. Choose how you’d like to proceed. + Your token’s approval has been revoked. Grant it again to resume service functionality. Approve needed The fee will be taken out, and your assets will be lent again. To continue earning, approval is required. Confirm approval - Text about your money in balance [PLACEHOLDER] + Your funds are currently supplied to the Aave protocol, but you can manage them at any time. Your %s is deposited in Aave Unable to load chart... The amount received, %1$s %2$s was not supplied to Aave. @@ -1832,7 +1833,7 @@ The network fee is currently too high to execute lending. Funds will be supplied once it drops to %1$s or below. My funds Your %1$s is now deposited in Aave and earning interest. You hold a%2$s token, which represents your balance and grows over time. When you deposit more funds, they\'ll be supplied to Aave to earn interest, minus a transaction fee. - Earn + Yield mode Total earnings Transfers to Aave Explore Aave @@ -1842,14 +1843,14 @@ An approximate network fee of %1$s (%2$s) will be deducted from each future top-up, and it won’t exceed your %3$s (%4$s) limit. If network fees rise above maximum fee, the transaction won’t go through until they decrease. You can change this limit later. Maximum fee - The minimum amount is calculated from the current network fee to ensure it does not exceed 4%, which makes the minimum %1$s (%2$s). + The minimum amount is calculated from the current network fee to ensure it does not exceed 4%%, which makes the minimum %1$s (%2$s). Minimum top-up Fee policy Tangem also takes a 3% service fee on yield earned. Your funds will be automatically supplied to Aave once network fees are lower or your balance meets the minimum required amount. Historical returns - Write description here. In one, two or three lines will be awesome. [PLACEHOLDER] - Token approvals needed + Approval for your token in the Yield mode has been revoked. Open the token to grant permission again. + Token approval needed Check your network connection Network fee info unreachable Every deposit you make will be supplied to Aave automatically. @@ -1872,7 +1873,7 @@ Supply assets Your %s will be supplied to Aave, but will remain manageable. See fee policy - Your next deposits will be automatically supplied to Aave. + Your next top-ups will be automatically supplied to Aave. Active Paused Disable yield mode @@ -1888,7 +1889,7 @@ Automatic Deposit some %1$s %2$s to cover the network fee for transactions Unable to cover %s fee - The interest service isn’t available at the moment. Please try again later. - Earnings unavailable + The Yield mode service isn’t available at the moment. Please try again later. + Yield mode unavailable Unable to load chart... diff --git a/core/utils/src/main/java/com/tangem/utils/TangemBlogUrlBuilder.kt b/core/utils/src/main/java/com/tangem/utils/TangemBlogUrlBuilder.kt index 3bb43d00e2..5d8f4ba63f 100644 --- a/core/utils/src/main/java/com/tangem/utils/TangemBlogUrlBuilder.kt +++ b/core/utils/src/main/java/com/tangem/utils/TangemBlogUrlBuilder.kt @@ -21,7 +21,7 @@ object TangemBlogUrlBuilder { const val RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP = "https://tangem.com/en/blog/post/give-revoke-permission/" - const val YIELD_SUPPLY_HOW_IT_WORKS_URL = "https://tangem.com/en/blog/post/savings-account" + const val YIELD_SUPPLY_HOW_IT_WORKS_URL = "https://tangem.com/en/blog/post/yield-mode" const val YIELD_SUPPLY_TOS_URL = "https://aave.com/terms-of-service" const val YIELD_SUPPLY_PRIVACY_URL = "https://aave.com/privacy-policy" } \ No newline at end of file diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrencyChecksRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrencyChecksRepository.kt index 48ac28966a..0d179fc31e 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrencyChecksRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrencyChecksRepository.kt @@ -2,7 +2,6 @@ package com.tangem.data.tokens.repository import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.common.* -import com.tangem.blockchainsdk.utils.toBlockchain import com.tangem.data.tokens.converters.UtxoConverter import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus @@ -19,7 +18,6 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.extensions.isZero import com.tangem.utils.extensions.orZero import kotlinx.coroutines.withContext -import timber.log.Timber import java.math.BigDecimal internal class DefaultCurrencyChecksRepository( @@ -168,27 +166,4 @@ internal class DefaultCurrencyChecksRepository( else -> null } } - - override suspend fun getProtocolBalance( - userWalletId: UserWalletId, - cryptoCurrencyStatus: CryptoCurrencyStatus, - ): BigDecimal? { - val token = cryptoCurrencyStatus.currency as? CryptoCurrency.Token ?: return null - val isActive = cryptoCurrencyStatus.value.yieldSupplyStatus?.isActive ?: false - if (!isActive) return null - return runCatching { - val walletManager = walletManagersFacade.getOrCreateWalletManager( - userWalletId = userWalletId, - blockchain = token.network.toBlockchain(), - derivationPath = token.network.derivationPath.value, - ) ?: error("Wallet manager not found") - walletManager.getEffectiveProtocolBalance( - token = Token( - symbol = token.symbol, - contractAddress = token.contractAddress, - decimals = token.decimals, - ), - ) - }.onFailure(Timber::e).getOrThrow() - } } \ No newline at end of file diff --git a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt index 8d8613e976..8f5fe85b65 100644 --- a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt +++ b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt @@ -16,11 +16,13 @@ import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.yield.supply.YieldSupplyRepository import com.tangem.domain.yield.supply.models.YieldMarketToken +import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus import com.tangem.domain.yield.supply.models.YieldSupplyMarketChartData import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext +import java.util.concurrent.ConcurrentHashMap import kotlin.collections.map internal class DefaultYieldSupplyRepository( @@ -30,6 +32,8 @@ internal class DefaultYieldSupplyRepository( private val dispatchers: CoroutineDispatcherProvider, ) : YieldSupplyRepository { + private val statusMap: MutableMap = ConcurrentHashMap() + override suspend fun getCachedMarkets(): List? = withContext(dispatchers.io) { val cache = store.getSyncOrNull().orEmpty() val domain = cache.map(YieldMarketTokenConverter::convert) @@ -97,6 +101,17 @@ internal class DefaultYieldSupplyRepository( ).getOrThrow().isActive } + override suspend fun saveTokenProtocolStatus( + cryptoCurrency: CryptoCurrency, + yieldSupplyEnterStatus: YieldSupplyEnterStatus, + ) { + statusMap[cryptoCurrency.id.value] = yieldSupplyEnterStatus + } + + override fun getTokenProtocolStatus(cryptoCurrencyToken: CryptoCurrency): YieldSupplyEnterStatus? { + return statusMap[cryptoCurrencyToken.id.value] + } + private fun List.enrichNetworkIds(): List { val chainIdMap = Blockchain.entries.associate { it.getChainId() to it.toNetworkId() } return this.map { token -> diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt index cb4b78542e..9edbf243da 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt @@ -73,10 +73,4 @@ sealed class CryptoCurrencyWarning { val requiredAmount: BigDecimal, val currencyDecimals: Int, ) : CryptoCurrencyWarning() - - data class YieldSupplyNotDepositedAmount( - val currency: CryptoCurrency, - val currencySymbol: String, - val amount: BigDecimal, - ) : CryptoCurrencyWarning() } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt index d491aff2a6..d4611e9d40 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt @@ -51,8 +51,7 @@ class GetCurrencyWarningsUseCase( flowOf(currencyChecksRepository.getRentInfoWarning(userWalletId, currencyStatus)), flowOf(currencyChecksRepository.getExistentialDeposit(userWalletId, currency.network)), flowOf(currencyChecksRepository.getFeeResourceAmount(userWalletId, currency.network)), - flowOf(currencyChecksRepository.getProtocolBalance(userWalletId, currencyStatus)), - ) { coinRelatedWarnings, maybeRentWarning, maybeEdWarning, maybeFeeResource, yieldSupplyProtocolBalance -> + ) { coinRelatedWarnings, maybeRentWarning, maybeEdWarning, maybeFeeResource -> setOfNotNull( maybeRentWarning, maybeEdWarning?.let { getExistentialDepositWarning(currency, it) }, @@ -63,7 +62,6 @@ class GetCurrencyWarningsUseCase( getBeaconChainShutdownWarning(rawId = currency.network.id.rawId), getAssetRequirementsWarning(userWalletId = userWalletId, currency = currency), getMigrationFromMaticToPolWarning(currency), - getYieldSupplyWarning(cryptoCurrencyStatus = currencyStatus, yieldSupplyProtocolBalance), ) }.flowOn(dispatchers.io) } @@ -263,28 +261,6 @@ class GetCurrencyWarningsUseCase( } } - private fun getYieldSupplyWarning( - cryptoCurrencyStatus: CryptoCurrencyStatus, - protocolBalance: BigDecimal?, - ): CryptoCurrencyWarning? { - val value = cryptoCurrencyStatus.value - val isActive = value.yieldSupplyStatus?.isActive == true - val amount = value.amount - - if (!isActive || protocolBalance == null || amount == null) return null - - val notDepositedAmount = amount.minus(protocolBalance) - return if (notDepositedAmount > BigDecimal.ZERO) { - CryptoCurrencyWarning.YieldSupplyNotDepositedAmount( - currency = cryptoCurrencyStatus.currency, - amount = notDepositedAmount, - currencySymbol = cryptoCurrencyStatus.currency.symbol, - ) - } else { - null - } - } - private fun BigDecimal?.isZero(): Boolean { return this?.signum() == 0 } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrencyChecksRepository.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrencyChecksRepository.kt index d1b4b99d81..8351958b10 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrencyChecksRepository.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrencyChecksRepository.kt @@ -61,11 +61,4 @@ interface CurrencyChecksRepository { currencyStatus: CryptoCurrencyStatus, balanceAfterTransaction: BigDecimal, ): CryptoCurrencyWarning.Rent? - - /** - * Returns the YieldSupplied protocol balance in Aave for the given `cryptoCurrency`. - * This represents the amount supplied to the protocol for the specified `userWalletId` - * (e.g., aTokens balance). Returns null if not applicable or unknown. - */ - suspend fun getProtocolBalance(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus): BigDecimal? } \ No newline at end of file diff --git a/domain/yield-supply/models/src/main/java/com/tangem/domain/yield/supply/models/YieldSupplyEnterStatus.kt b/domain/yield-supply/models/src/main/java/com/tangem/domain/yield/supply/models/YieldSupplyEnterStatus.kt new file mode 100644 index 0000000000..4ecdb12732 --- /dev/null +++ b/domain/yield-supply/models/src/main/java/com/tangem/domain/yield/supply/models/YieldSupplyEnterStatus.kt @@ -0,0 +1,6 @@ +package com.tangem.domain.yield.supply.models + +enum class YieldSupplyEnterStatus { + Enter, + Exit, +} \ No newline at end of file diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt index c721f9e942..a9ce7c69dd 100644 --- a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt +++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt @@ -3,6 +3,7 @@ package com.tangem.domain.yield.supply import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.yield.supply.models.YieldMarketToken +import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus import com.tangem.domain.yield.supply.models.YieldSupplyMarketChartData import kotlinx.coroutines.flow.Flow @@ -56,4 +57,30 @@ interface YieldSupplyRepository { */ @Throws suspend fun deactivateProtocol(cryptoCurrencyToken: CryptoCurrency.Token): Boolean + + /** + * Save the last user-initiated yield protocol action for the given currency. + * + * The saved value helps the UI render an intermediate "processing" state while waiting + * for the definitive protocol status to be fetched from the network. This information + * is transient and not intended to be persisted across app restarts. + * + * @param cryptoCurrencyToken the currency or token the action relates to + * @param yieldSupplyEnterStatus the last action intent: [YieldSupplyEnterStatus.Enter] or [YieldSupplyEnterStatus.Exit] + */ + suspend fun saveTokenProtocolStatus( + cryptoCurrencyToken: CryptoCurrency, + yieldSupplyEnterStatus: YieldSupplyEnterStatus, + ) + + /** + * Get the last saved user-initiated yield protocol action for the given currency, if any. + * + * Used to determine whether the UI should display an intermediate "processing" state + * until the protocol status retrieved from backend reflects the change. + * + * @param cryptoCurrencyToken the currency or token to query + * @return the last action intent or null if nothing has been recorded + */ + fun getTokenProtocolStatus(cryptoCurrencyToken: CryptoCurrency): YieldSupplyEnterStatus? } \ No newline at end of file diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetMaxFeeUseCase.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetMaxFeeUseCase.kt index e463368cd3..3c8c7aa671 100644 --- a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetMaxFeeUseCase.kt +++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetMaxFeeUseCase.kt @@ -4,6 +4,7 @@ import arrow.core.Either import arrow.core.Either.Companion.catch import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.models.currency.yieldSupplyKey import com.tangem.domain.models.quote.QuoteStatus import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.quotes.QuotesRepository @@ -51,7 +52,9 @@ class YieldSupplyGetMaxFeeUseCase( ?: error("Native fiat rate is missing") require(nativeFiatRate > BigDecimal.ZERO) { "Native fiat rate must be > 0" } - val marketToken = yieldSupplyRepository.getTokenStatus(token) + val cachedMarketToken = yieldSupplyRepository.getCachedMarkets().orEmpty() + .firstOrNull { it.yieldSupplyKey == token.yieldSupplyKey() } + val marketToken = cachedMarketToken ?: yieldSupplyRepository.getTokenStatus(token) val maxFeeNative = marketToken.maxFeeNative.toBigDecimal() val rateRatio = nativeFiatRate.divide( diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/model/SwapSelectTokensModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/model/SwapSelectTokensModel.kt index 5d12338467..9bda5e4153 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/model/SwapSelectTokensModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/model/SwapSelectTokensModel.kt @@ -8,6 +8,7 @@ import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.components.token.state.TokenItemState +import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase @@ -37,6 +38,7 @@ internal class SwapSelectTokensModel @Inject constructor( private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase, private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase, + private val accountsFeatureToggles: AccountsFeatureToggles, ) : Model() { val state: StateFlow = controller.state @@ -77,10 +79,14 @@ internal class SwapSelectTokensModel @Inject constructor( selectedTokenItemState = selectedTokenItemState, onRemoveClick = ::onRemoveFromTokenClick, isAccountsMode = isAccountsMode, - account = getAccountCurrencyStatusUseCase.invokeSync( - userWalletId = params.userWalletId, - currency = status.currency, - ).getOrNull()?.account, + account = if (accountsFeatureToggles.isFeatureEnabled) { + getAccountCurrencyStatusUseCase.invokeSync( + userWalletId = params.userWalletId, + currency = status.currency, + ).getOrNull()?.account + } else { + null + }, ), ) } @@ -104,10 +110,14 @@ internal class SwapSelectTokensModel @Inject constructor( transformer = SelectToTokenTransformer( selectedTokenItemState = selectedTokenItemState, isAccountsMode = isAccountsMode, - account = getAccountCurrencyStatusUseCase.invokeSync( - userWalletId = params.userWalletId, - currency = status.currency, - ).getOrNull()?.account, + account = if (accountsFeatureToggles.isFeatureEnabled) { + getAccountCurrencyStatusUseCase.invokeSync( + userWalletId = params.userWalletId, + currency = status.currency, + ).getOrNull()?.account + } else { + null + }, ), ) diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/model/SendAmountModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/model/SendAmountModel.kt index 1d8c41c27a..7926083e2e 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/model/SendAmountModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/model/SendAmountModel.kt @@ -142,8 +142,8 @@ internal class SendAmountModel @Inject constructor( ) { newCryptoCurrencyStatus, account, isAccountsMode -> maxAmountBoundary = MaxEnterAmountConverter().convert(newCryptoCurrencyStatus) cryptoCurrencyStatus = newCryptoCurrencyStatus - initMinBoundary(cryptoCurrencyStatus, account, isAccountsMode) - }.flowOn(dispatchers.default) + initMinBoundary(newCryptoCurrencyStatus, account, isAccountsMode) + }.flowOn(dispatchers.main) .launchIn(modelScope) } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt index f334d19633..968dff50ae 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt @@ -171,7 +171,7 @@ internal class StakingModel @Inject constructor( } private var isAccountInitialized: Boolean = true - private var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull() + private lateinit var cryptoCurrencyStatus: CryptoCurrencyStatus private var stakingActions: List = emptyList() private var feeCryptoCurrencyStatus: CryptoCurrencyStatus? = null private var minimumTransactionAmount: EnterAmountBoundary? = null @@ -1299,6 +1299,7 @@ internal class StakingModel @Inject constructor( } private fun isCaseWithUnitializedTonAccount(): Boolean { + if (!::cryptoCurrencyStatus.isInitialized) return false return value.currentStep == StakingStep.Confirmation && isTon(cryptoCurrencyStatus.currency.network.rawId) && !isAccountInitialized diff --git a/features/token-recieve/impl/src/main/java/com/tangem/features/tokenreceive/entity/TokenReceiveStateFactory.kt b/features/token-recieve/impl/src/main/java/com/tangem/features/tokenreceive/entity/TokenReceiveStateFactory.kt index 2d014adf53..ee3dd1a028 100644 --- a/features/token-recieve/impl/src/main/java/com/tangem/features/tokenreceive/entity/TokenReceiveStateFactory.kt +++ b/features/token-recieve/impl/src/main/java/com/tangem/features/tokenreceive/entity/TokenReceiveStateFactory.kt @@ -19,7 +19,6 @@ import com.tangem.features.tokenreceive.entity.ReceiveAddress.Type.Ens import com.tangem.features.tokenreceive.entity.ReceiveAddress.Type.Primary import com.tangem.features.tokenreceive.ui.state.TokenReceiveUM import com.tangem.utils.Provider -import com.tangem.utils.extensions.addIf import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toPersistentList @@ -138,12 +137,7 @@ internal class TokenReceiveStateFactory( tokenName: String, tokenReceiveNotification: List, ): List { - val yieldSupplyNotification: TokenReceiveNotification? = - tokenReceiveNotification.firstOrNull { it.isYieldSupplyNotification } return buildList { - addIf(yieldSupplyNotification != null) { - NotificationUM.Warning.YieldSupplyIsActive(tokenName) - } add( NotificationUM.Info( title = resourceReference( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt index c5081a966c..dfb37410b9 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt @@ -156,10 +156,6 @@ internal class TokenDetailsNotificationConverter( ) is CryptoCurrencyWarning.MigrationMaticToPol -> MigrationMaticToPol is CryptoCurrencyWarning.UsedOutdatedDataWarning -> UsedOutdatedData - is CryptoCurrencyWarning.YieldSupplyNotDepositedAmount -> YieldSupplyNotTransferedToAave( - tokenName = warning.currencySymbol, - amount = warning.amount.format { crypto(symbol = "", decimals = warning.currency.decimals) }, - ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt index fab2288352..84a19cc5e5 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt @@ -123,6 +123,14 @@ private fun TokenList( end = TangemTheme.dimens.spacing16, ) + // workaround to force recomposition of list items when the list is updated + // because sometimes items disappear after reordering in 1.7.4+ compose-runtime version + // check removing after update to compose-runtime 1.8.0+ + val forceRecompose = remember { mutableIntStateOf(0) } + LaunchedEffect(state.items) { + forceRecompose.intValue++ + } + LazyColumn( modifier = Modifier .align(Alignment.TopCenter) @@ -143,13 +151,15 @@ private fun TokenList( } } - DraggableItem( - index = index, - item = item, - reorderableState = reorderableListState, - onDragStart = onDragStart, - isBalanceHidden = isBalanceHidden, - ) + key(forceRecompose.intValue) { + DraggableItem( + index = index, + item = item, + reorderableState = reorderableListState, + onDragStart = onDragStart, + isBalanceHidden = isBalanceHidden, + ) + } } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletImageFetcher.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletImageFetcher.kt index 293be6f47b..4fc2e6290b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletImageFetcher.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/utils/DefaultUserWalletImageFetcher.kt @@ -46,7 +46,7 @@ class DefaultUserWalletImageFetcher @Inject constructor( override fun walletImage(walletId: UserWalletId, size: ArtworkSize): Flow = getUserWalletUseCase.invokeFlow(walletId) - .transformLatest { + .transform { it.fold( ifLeft = { emit(UserWalletItemUM.ImageState.Loading) }, ifRight = { wallet -> emitAll(walletImage(wallet, size)) }, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/YieldSupplyTrigger.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/YieldSupplyTrigger.kt deleted file mode 100644 index 691095237a..0000000000 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/YieldSupplyTrigger.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.tangem.features.yield.supply.impl.common - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow -import javax.inject.Inject -import javax.inject.Singleton - -/** - * Trigger for entering/exiting protocol from other components - */ -interface YieldSupplyProtocolTrigger { - suspend fun onEnterProtocol() - suspend fun onExitProtocol() -} - -/** - * Listener to observe entering/exiting protocol events - */ -interface YieldSupplyProtocolListener { - val enterProtocolTriggerFlow: Flow - val exitProtocolTriggerFlow: Flow -} - -@Singleton -internal class DefaultYieldSupplyProtocolTrigger @Inject constructor() : - YieldSupplyProtocolTrigger, - YieldSupplyProtocolListener { - - override val enterProtocolTriggerFlow = MutableSharedFlow() - override val exitProtocolTriggerFlow = MutableSharedFlow() - - override suspend fun onEnterProtocol() { - enterProtocolTriggerFlow.emit(Unit) - } - - override suspend fun onExitProtocol() { - exitProtocolTriggerFlow.emit(Unit) - } -} \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt index ffac0fef60..7b3d8e94ed 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt @@ -13,10 +13,12 @@ internal sealed class YieldSupplyFeeUM { data object Error : YieldSupplyFeeUM() data class Content( val transactionDataList: ImmutableList, - val feeValue: TextReference, - val currentNetworkFeeValue: TextReference, - val maxNetworkFeeValue: TextReference, - val minAmountFeeValue: TextReference, + val feeFiatValue: TextReference, + val tokenFeeFiatValue: TextReference, + val maxNetworkFeeFiatValue: TextReference, + val minTopUpFiatValue: TextReference, + val feeNoteValue: TextReference = TextReference.EMPTY, + val minFeeNoteValue: TextReference = TextReference.EMPTY, ) : YieldSupplyFeeUM() } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt index 03437a23fe..abc8b25b63 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt @@ -3,11 +3,13 @@ package com.tangem.features.yield.supply.impl.common.ui import android.content.res.Configuration import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.key import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.text.LinkAnnotation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.withLink @@ -85,13 +87,17 @@ internal fun YieldSupplyActionContent( ), ) { val fee = when (val yieldSupplyFeeUM = yieldSupplyActionUM.yieldSupplyFeeUM) { - is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.feeValue + is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.feeFiatValue YieldSupplyFeeUM.Error -> stringReference(StringsSigns.DASH_SIGN) YieldSupplyFeeUM.Loading -> null } YieldSupplyFeeRow( title = resourceReference(R.string.common_network_fee_title), value = fee, + modifier = Modifier.fillMaxWidth() + .clip(RoundedCornerShape(14.dp)) + .background(TangemTheme.colors.background.action) + .padding(horizontal = 16.dp, vertical = 12.dp), ) } } @@ -138,10 +144,11 @@ private class YieldSupplyActionContentPreviewProvider : PreviewParameterProvider currencyIconState = CurrencyIconState.Loading, yieldSupplyFeeUM = YieldSupplyFeeUM.Content( transactionDataList = persistentListOf(), - feeValue = stringReference("0.00020 ETH • \$0.99"), - currentNetworkFeeValue = stringReference("1.45 USDT • \$1.45"), - maxNetworkFeeValue = stringReference("8.50 USDT • \$8.50"), - minAmountFeeValue = stringReference("50 USDT • \$50"), + feeFiatValue = stringReference("$0.99"), + tokenFeeFiatValue = stringReference("$1.45"), + maxNetworkFeeFiatValue = stringReference("$8.50"), + minTopUpFiatValue = stringReference("$50"), + feeNoteValue = TextReference.EMPTY, ), isPrimaryButtonEnabled = false, isTransactionSending = false, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyFeeRow.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyFeeRow.kt index dc00a547a8..c893885dbb 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyFeeRow.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyFeeRow.kt @@ -1,17 +1,12 @@ package com.tangem.features.yield.supply.impl.common.ui import androidx.compose.animation.AnimatedContent -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.SpacerWMax @@ -23,15 +18,11 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.features.yield.supply.impl.R @Composable -internal fun YieldSupplyFeeRow(title: TextReference, value: TextReference?) { +internal fun YieldSupplyFeeRow(title: TextReference, value: TextReference?, modifier: Modifier = Modifier) { Row( horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(14.dp)) - .background(TangemTheme.colors.background.action) - .padding(horizontal = 16.dp, vertical = 12.dp), + modifier = modifier, ) { Text( text = title.resolveReference(), diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/di/YieldSupplyFeatureModule.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/di/YieldSupplyFeatureModule.kt index 9226bcfa8e..45b8806bd6 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/di/YieldSupplyFeatureModule.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/di/YieldSupplyFeatureModule.kt @@ -3,10 +3,6 @@ package com.tangem.features.yield.supply.impl.di import com.tangem.core.configtoggle.feature.FeatureTogglesManager import com.tangem.features.yield.supply.impl.DefaultYieldSupplyFeatureToggles import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles -import com.tangem.features.yield.supply.impl.common.DefaultYieldSupplyProtocolTrigger -import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolListener -import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolTrigger -import dagger.Binds import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -22,17 +18,4 @@ internal object YieldSupplyFeatureModule { fun provideYieldFeatureToggles(featureTogglesManager: FeatureTogglesManager): YieldSupplyFeatureToggles { return DefaultYieldSupplyFeatureToggles(featureTogglesManager) } -} - -@InstallIn(SingletonComponent::class) -@Module -internal interface YieldSupplyProtocolModuleBinds { - - @Singleton - @Binds - fun bindYieldSupplyProtocolTrigger(impl: DefaultYieldSupplyProtocolTrigger): YieldSupplyProtocolTrigger - - @Singleton - @Binds - fun bindYieldSupplyProtocolListener(impl: DefaultYieldSupplyProtocolTrigger): YieldSupplyProtocolListener } \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt index 112b1dbb24..2d7419ea4b 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt @@ -24,7 +24,7 @@ internal sealed class YieldSupplyUM { val subtitle: TextReference, val rewardsApy: TextReference, val onClick: () -> Unit, - val isAllowedToSpend: Boolean, + val showWarningIcon: Boolean, ) : YieldSupplyUM() @Immutable diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt index 5d1d974638..9d5b7885d9 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt @@ -15,12 +15,14 @@ import com.tangem.core.ui.extensions.stringReference import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus -import com.tangem.domain.models.network.TxInfo +import com.tangem.domain.models.currency.yieldSupplyNotAllAmountSupplied import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.yield.supply.YieldSupplyStatus import com.tangem.domain.networks.single.SingleNetworkStatusFetcher import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase +import com.tangem.domain.yield.supply.YieldSupplyRepository +import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus import com.tangem.domain.yield.supply.usecase.YieldSupplyActivateUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyDeactivateUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyGetTokenStatusUseCase @@ -28,7 +30,6 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyIsAvailableUseCase import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.api.YieldSupplyComponent import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics -import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolListener import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM import com.tangem.features.yield.supply.impl.main.model.transformers.YieldSupplyTokenStatusSuccessTransformer import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -58,7 +59,7 @@ internal class YieldSupplyModel @Inject constructor( private val yieldSupplyIsAvailableUseCase: YieldSupplyIsAvailableUseCase, private val yieldSupplyActivateUseCase: YieldSupplyActivateUseCase, private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase, - private val yieldSupplyProtocolListener: YieldSupplyProtocolListener, + private val yieldSupplyRepository: YieldSupplyRepository, ) : Model(), YieldSupplyClickIntents { private val params = paramsContainer.require() @@ -86,38 +87,6 @@ internal class YieldSupplyModel @Inject constructor( init { checkIfYieldSupplyIsAvailable() - observeProtocolEvents() - } - - private fun observeProtocolEvents() { - yieldSupplyProtocolListener.exitProtocolTriggerFlow.onEach { - uiState.update { - YieldSupplyUM.Processing.Exit - } - coroutineScope.launch(dispatchers.io) { - delay(PROCESSING_UPDATE_DELAY) - singleNetworkStatusFetcher( - params = SingleNetworkStatusFetcher.Params( - userWalletId = userWallet.walletId, - network = cryptoCurrency.network, - ), - ) - } - }.launchIn(modelScope) - yieldSupplyProtocolListener.enterProtocolTriggerFlow.onEach { - uiState.update { - YieldSupplyUM.Processing.Enter - } - coroutineScope.launch(dispatchers.io) { - delay(PROCESSING_UPDATE_DELAY) - singleNetworkStatusFetcher( - params = SingleNetworkStatusFetcher.Params( - userWalletId = userWallet.walletId, - network = cryptoCurrency.network, - ), - ) - } - }.launchIn(modelScope) } private fun checkIfYieldSupplyIsAvailable() { @@ -141,7 +110,6 @@ internal class YieldSupplyModel @Inject constructor( currencyId = cryptoCurrency.id, isSingleWalletWithTokens = false, ).onEach { maybeCryptoCurrency -> - Timber.tag("getSingleCryptoCurrencyStatusUseCase").d("update $maybeCryptoCurrency") maybeCryptoCurrency.fold( ifRight = { cryptoCurrencyStatus -> cryptoCurrencyStatusFlow.update { cryptoCurrencyStatus } @@ -174,7 +142,7 @@ internal class YieldSupplyModel @Inject constructor( ) }.onLeft { Timber.e(it) - uiState.update { YieldSupplyUM.Unavailable } + uiState.update { YieldSupplyUM.Initial } } } } @@ -213,53 +181,56 @@ internal class YieldSupplyModel @Inject constructor( @Suppress("MaximumLineLength") private fun onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus: CryptoCurrencyStatus) { val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus - val hasActiveTransaction = cryptoCurrencyStatus.value.hasCurrentNetworkTransactions - val yieldTransaction = cryptoCurrencyStatus.value.pendingTransactions.firstOrNull { - it.type is TxInfo.TransactionType.YieldSupply - }?.type as? TxInfo.TransactionType.YieldSupply - sendInfoAboutProtocolStatus(cryptoCurrencyStatus) + val tokenProtocolStatus = yieldSupplyRepository.getTokenProtocolStatus(cryptoCurrency) + val isActive = yieldSupplyStatus?.isActive == true when { - hasActiveTransaction && yieldTransaction != null -> { - coroutineScope.launch(dispatchers.io) { - delay(PROCESSING_UPDATE_DELAY) - singleNetworkStatusFetcher( - params = SingleNetworkStatusFetcher.Params( - userWalletId = userWallet.walletId, - network = cryptoCurrency.network, - ), - ) - } - uiState.update { - when (yieldTransaction) { - TxInfo.TransactionType.YieldSupply.Enter -> YieldSupplyUM.Processing.Enter - TxInfo.TransactionType.YieldSupply.Exit -> YieldSupplyUM.Processing.Exit - } - } + !isActive && tokenProtocolStatus == YieldSupplyEnterStatus.Enter -> { + uiState.update { YieldSupplyUM.Processing.Enter } + fetchCurrencyWithDelay() } - yieldSupplyStatus?.isActive == true -> { - val cryptoCurrencyToken = cryptoCurrency as? CryptoCurrency.Token ?: return - if (!yieldSupplyStatus.isAllowedToSpend) { - analyticsEventsHandler.send( - YieldSupplyAnalytics.NoticeApproveNeeded( - token = cryptoCurrency.symbol, - blockchain = cryptoCurrency.network.name, - ), - ) - } - loadActiveState( - cryptoCurrencyToken = cryptoCurrencyToken, - yieldSupplyStatus = yieldSupplyStatus, - ) + isActive && tokenProtocolStatus == YieldSupplyEnterStatus.Exit -> { + uiState.update { YieldSupplyUM.Processing.Exit } + fetchCurrencyWithDelay() } - else -> { - loadTokenStatus() + sendInfoAboutProtocolStatus(cryptoCurrencyStatus) + if (isActive) { + loadActiveState( + cryptoCurrencyStatus = cryptoCurrencyStatus, + yieldSupplyStatus = requireNotNull(yieldSupplyStatus), + ) + } else { + loadTokenStatus() + } } } } - private fun loadActiveState(cryptoCurrencyToken: CryptoCurrency.Token, yieldSupplyStatus: YieldSupplyStatus) { + private fun fetchCurrencyWithDelay() { + coroutineScope.launch(dispatchers.io) { + delay(PROCESSING_UPDATE_DELAY) + singleNetworkStatusFetcher( + params = SingleNetworkStatusFetcher.Params( + userWalletId = userWallet.walletId, + network = cryptoCurrency.network, + ), + ) + } + } + + private fun loadActiveState(cryptoCurrencyStatus: CryptoCurrencyStatus, yieldSupplyStatus: YieldSupplyStatus) { + val cryptoCurrencyToken = cryptoCurrency as? CryptoCurrency.Token ?: return + val showWarningIcon = !yieldSupplyStatus.isAllowedToSpend || + cryptoCurrencyStatus.yieldSupplyNotAllAmountSupplied() + if (!yieldSupplyStatus.isAllowedToSpend) { + analyticsEventsHandler.send( + YieldSupplyAnalytics.NoticeApproveNeeded( + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ), + ) + } modelScope.launch(dispatchers.default) { yieldSupplyGetTokenStatusUseCase(cryptoCurrencyToken) .onRight { tokenStatus -> @@ -278,7 +249,7 @@ internal class YieldSupplyModel @Inject constructor( stringReference(" ${tokenStatus.apy}%"), ), onClick = ::onActiveClick, - isAllowedToSpend = yieldSupplyStatus.isAllowedToSpend, + showWarningIcon = showWarningIcon, apy = tokenStatus.apy.toString(), ) } @@ -294,7 +265,7 @@ internal class YieldSupplyModel @Inject constructor( ), rewardsApy = TextReference.EMPTY, onClick = ::onActiveClick, - isAllowedToSpend = yieldSupplyStatus.isAllowedToSpend, + showWarningIcon = showWarningIcon, apy = "", ) } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt index 49ea1ef511..913def042b 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt @@ -132,7 +132,7 @@ private fun SupplyContent(supplyUM: YieldSupplyUM.Content) { ) } SpacerW8() - AnimatedVisibility(supplyUM.isAllowedToSpend.not()) { + AnimatedVisibility(supplyUM.showWarningIcon) { Icon( imageVector = ImageVector.vectorResource(R.drawable.ic_alert_triangle_20), contentDescription = null, @@ -317,7 +317,7 @@ private class PreviewProvider : PreviewParameterProvider { rewardsApy = stringReference("5.1 % APY"), onClick = {}, apy = "5.1", - isAllowedToSpend = false, + showWarningIcon = false, ), YieldSupplyUM.Content( title = stringReference("Aave lending is active"), @@ -325,7 +325,7 @@ private class PreviewProvider : PreviewParameterProvider { rewardsApy = stringReference("5.1 % APY"), onClick = {}, apy = "5.1", - isAllowedToSpend = true, + showWarningIcon = true, ), YieldSupplyUM.Loading, YieldSupplyUM.Processing.Enter, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveComponent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveComponent.kt index db0f137890..0dccc9df82 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveComponent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveComponent.kt @@ -50,6 +50,7 @@ internal class YieldSupplyActiveComponent( state = state, isBalanceHidden = isBalanceHidden, chartComponent = chartComponent, + onReadMoreClick = params.callback::onReadMoreClick, modifier = Modifier, ) } @@ -76,5 +77,6 @@ internal class YieldSupplyActiveComponent( fun onBackClick() fun onStopEarning() fun onApprove() + fun onReadMoreClick() } } \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/entity/YieldSupplyActiveContentUM.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/entity/YieldSupplyActiveContentUM.kt index 9b93df6c2a..eea128679c 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/entity/YieldSupplyActiveContentUM.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/entity/YieldSupplyActiveContentUM.kt @@ -2,6 +2,7 @@ package com.tangem.features.yield.supply.impl.subcomponents.active.entity import com.tangem.common.ui.notifications.NotificationUM import com.tangem.core.ui.extensions.TextReference +import kotlinx.collections.immutable.ImmutableList internal data class YieldSupplyActiveContentUM( val totalEarnings: TextReference, @@ -9,10 +10,11 @@ internal data class YieldSupplyActiveContentUM( val providerTitle: TextReference, val subtitle: TextReference, val subtitleLink: TextReference, - val notificationUM: NotificationUM?, + val notifications: ImmutableList, val minAmount: TextReference?, val currentFee: TextReference?, val feeDescription: TextReference?, + val minFeeDescription: TextReference?, val apy: TextReference? = null, val isHighFee: Boolean = false, ) \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveEntryModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveEntryModel.kt index 1d60926512..02fc956678 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveEntryModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveEntryModel.kt @@ -4,10 +4,12 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router +import com.tangem.core.navigation.url.UrlOpener import com.tangem.features.yield.supply.impl.subcomponents.active.YieldSupplyActiveComponent import com.tangem.features.yield.supply.impl.subcomponents.active.YieldSupplyActiveEntryComponent import com.tangem.features.yield.supply.impl.subcomponents.approve.YieldSupplyApproveComponent import com.tangem.features.yield.supply.impl.subcomponents.stopearning.YieldSupplyStopEarningComponent +import com.tangem.utils.TangemBlogUrlBuilder import com.tangem.utils.coroutines.CoroutineDispatcherProvider import javax.inject.Inject @@ -16,6 +18,7 @@ internal class YieldSupplyActiveEntryModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, paramsContainer: ParamsContainer, private val router: Router, + private val urlOpener: UrlOpener, ) : Model(), YieldSupplyActiveComponent.ModelCallback, YieldSupplyStopEarningComponent.ModelCallback, YieldSupplyApproveComponent.ModelCallback { @@ -37,4 +40,8 @@ internal class YieldSupplyActiveEntryModel @Inject constructor( override fun onApprove() { router.push(YieldSupplyActiveRoute.Approve) } + + override fun onReadMoreClick() { + urlOpener.openUrl(TangemBlogUrlBuilder.YIELD_SUPPLY_HOW_IT_WORKS_URL) + } } \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt index a74719003c..8d8bd96071 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt @@ -12,11 +12,11 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.format.bigdecimal.crypto -import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.yield.supply.usecase.YieldSupplyGetProtocolBalanceUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyGetTokenStatusUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyMinAmountUseCase @@ -24,14 +24,20 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyGetCurrentFeeUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyGetMaxFeeUseCase import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.R -import com.tangem.features.yield.supply.impl.common.formatter.YieldSupplyAmountFormatter import com.tangem.features.yield.supply.impl.subcomponents.active.YieldSupplyActiveComponent import com.tangem.features.yield.supply.impl.subcomponents.active.entity.YieldSupplyActiveContentUM +import com.tangem.features.yield.supply.impl.subcomponents.active.model.transformers.YieldSupplyActiveMinAmountTransformer +import com.tangem.features.yield.supply.impl.subcomponents.active.model.transformers.YieldSupplyActiveFeeContentTransformer import com.tangem.utils.StringsSigns.DASH_SIGN import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.transformer.update +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import timber.log.Timber +import java.math.BigDecimal import javax.inject.Inject @Suppress("LongParameterList") @@ -65,11 +71,12 @@ internal class YieldSupplyActiveModel @Inject constructor( formatArgs = wrappedList(cryptoCurrency.symbol, cryptoCurrency.symbol), ), subtitleLink = resourceReference(R.string.common_read_more), - notificationUM = null, + notifications = persistentListOf(), minAmount = null, currentFee = null, feeDescription = null, isHighFee = false, + minFeeDescription = null, ), ) @@ -108,27 +115,13 @@ internal class YieldSupplyActiveModel @Inject constructor( cryptoCurrency = cryptoCurrency, ).getOrNull() - val approvalNotification = if (cryptoCurrencyStatus.value.yieldSupplyStatus?.isAllowedToSpend != true) { - NotificationUM.Error( - title = resourceReference(R.string.yield_module_approve_needed_notification_title), - subtitle = resourceReference(R.string.yield_module_approve_needed_notification_description), - iconResId = R.drawable.ic_alert_triangle_20, - buttonState = NotificationConfig.ButtonsState.PrimaryButtonConfig( - text = resourceReference(R.string.yield_module_approve_needed_notification_cta), - onClick = params.callback::onApprove, - ), - ) - } else { - null - } - loadApy() loadMinAmount() loadFees() uiState.update { it.copy( - notificationUM = approvalNotification, + notifications = getNotifications(cryptoCurrencyStatus), availableBalance = stringReference( protocolBalance.format { crypto( @@ -153,31 +146,77 @@ internal class YieldSupplyActiveModel @Inject constructor( ) } }.onLeft { + uiState.update { + it.copy( + apy = TextReference.Str(DASH_SIGN), + ) + } Timber.e("Error loading token status") } } } + private fun getNotifications(cryptoCurrencyStatus: CryptoCurrencyStatus): ImmutableList { + val approvalNotification = if (cryptoCurrencyStatus.value.yieldSupplyStatus?.isAllowedToSpend != true) { + NotificationUM.Error( + title = resourceReference(R.string.yield_module_approve_needed_notification_title), + subtitle = resourceReference(R.string.yield_module_approve_needed_notification_description), + iconResId = R.drawable.ic_alert_triangle_20, + buttonState = NotificationConfig.ButtonsState.PrimaryButtonConfig( + text = resourceReference(R.string.yield_module_approve_needed_notification_cta), + onClick = params.callback::onApprove, + ), + ) + } else { + null + } + val notSuppliedNotification = getNotSuppliedNotification(cryptoCurrencyStatus) + return listOfNotNull( + approvalNotification, + notSuppliedNotification, + ).toPersistentList() + } + + private fun getNotSuppliedNotification(cryptoCurrencyStatus: CryptoCurrencyStatus): NotificationUM? { + val value = cryptoCurrencyStatus.value + val isActive = value.yieldSupplyStatus?.isActive == true + val effectiveProtocolBalance = value.yieldSupplyStatus?.effectiveProtocolBalance ?: null + val amount = value.amount + + if (!isActive || effectiveProtocolBalance == null || amount == null) return null + + val notDepositedAmount = amount.minus(effectiveProtocolBalance) + return if (notDepositedAmount > BigDecimal.ZERO) { + val formattedAmount = + notDepositedAmount.format { crypto(symbol = "", decimals = cryptoCurrencyStatus.currency.decimals) } + NotificationUM.Warning.YieldSupplyNotAllAmountSupplied( + formattedAmount = formattedAmount, + symbol = cryptoCurrency.symbol, + ) + } else { + null + } + } + private fun loadMinAmount() { modelScope.launch(dispatchers.default) { yieldSupplyMinAmountUseCase( params.userWallet, cryptoCurrencyStatusFlow.value, ).onRight { minAmount -> - val minAmountTextReference = YieldSupplyAmountFormatter( - cryptoCurrencyStatusFlow.value.currency, - appCurrency, - ).invoke( - feeValue = minAmount, - fiatRate = cryptoCurrencyStatusFlow.value.value.fiatRate, - showCrypto = false, + uiState.update( + YieldSupplyActiveMinAmountTransformer( + cryptoCurrencyStatus = cryptoCurrencyStatusFlow.value, + appCurrency = appCurrency, + minAmount = minAmount, + ), ) - uiState.update { - it.copy(minAmount = minAmountTextReference) - } }.onLeft { uiState.update { - it.copy(minAmount = TextReference.Str(DASH_SIGN)) + it.copy( + minAmount = TextReference.Str(DASH_SIGN), + feeDescription = null, + ) } } } @@ -197,33 +236,23 @@ internal class YieldSupplyActiveModel @Inject constructor( cryptoCurrencyStatus = cryptoStatus, ).getOrNull() - val currentFeeText = currentFee?.let { - YieldSupplyAmountFormatter( - cryptoStatus.currency, - appCurrency, - ).invoke( - feeValue = it, - fiatRate = cryptoStatus.value.fiatRate, - showCrypto = false, + if (currentFee != null && maxFee != null) { + uiState.update( + YieldSupplyActiveFeeContentTransformer( + cryptoCurrencyStatus = cryptoStatus, + appCurrency = appCurrency, + feeValue = currentFee, + maxNetworkFee = maxFee, + ), ) - } - - val isHighFee = if (currentFee != null && maxFee != null) currentFee > maxFee else false - - val maxFiatFee = maxFee?.multiply(cryptoStatus.value.fiatRate) - .format { fiat(appCurrency.code, appCurrency.symbol) } - val feeDescription = if (isHighFee) { - resourceReference(R.string.yield_module_earn_sheet_high_fee_description, wrappedList(maxFiatFee)) } else { - resourceReference(R.string.yield_module_earn_sheet_fee_description, wrappedList(maxFiatFee)) - } - - uiState.update { - it.copy( - currentFee = currentFeeText ?: stringReference(DASH_SIGN), - isHighFee = isHighFee, - feeDescription = feeDescription, - ) + uiState.update { + it.copy( + currentFee = stringReference(DASH_SIGN), + feeDescription = null, + isHighFee = false, + ) + } } } } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveFeeContentTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveFeeContentTransformer.kt new file mode 100644 index 0000000000..bcd2e22076 --- /dev/null +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveFeeContentTransformer.kt @@ -0,0 +1,57 @@ +package com.tangem.features.yield.supply.impl.subcomponents.active.model.transformers + +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.core.ui.format.bigdecimal.crypto +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.core.ui.extensions.TextReference +import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.features.yield.supply.impl.R +import com.tangem.features.yield.supply.impl.subcomponents.active.entity.YieldSupplyActiveContentUM +import com.tangem.utils.transformer.Transformer +import java.math.BigDecimal + +/** + * Computes fee description and current fee values for Active screen based on token rates. + */ +internal class YieldSupplyActiveFeeContentTransformer( + private val cryptoCurrencyStatus: CryptoCurrencyStatus, + private val appCurrency: AppCurrency, + private val feeValue: BigDecimal, + private val maxNetworkFee: BigDecimal, +) : Transformer { + + override fun transform(prevState: YieldSupplyActiveContentUM): YieldSupplyActiveContentUM { + val cryptoCurrency = cryptoCurrencyStatus.currency + val tokenFiatRate = cryptoCurrencyStatus.value.fiatRate + + val tokenCryptoFeeValueText = feeValue.format { crypto(cryptoCurrency) } + val tokenFiatFee = tokenFiatRate?.let(feeValue::multiply) + val tokenFiatFeeValueText = tokenFiatFee.format { fiat(appCurrency.code, appCurrency.symbol) } + + val maxFeeCryptoValueText = maxNetworkFee.format { crypto(cryptoCurrency) } + val maxFiatFee = tokenFiatRate?.let { rate -> maxNetworkFee.multiply(rate) } + val maxFiatFeeValueText = maxFiatFee.format { fiat(appCurrency.code, appCurrency.symbol) } + + val feeNoteValue: TextReference = resourceReference( + id = R.string.yield_module_fee_policy_sheet_fee_note, + formatArgs = wrappedList( + stringReference(tokenFiatFeeValueText), + stringReference(tokenCryptoFeeValueText), + stringReference(maxFiatFeeValueText), + stringReference(maxFeeCryptoValueText), + ), + ) + + val isHighFee = feeValue > maxNetworkFee + + return prevState.copy( + currentFee = stringReference(tokenFiatFeeValueText), + feeDescription = feeNoteValue, + isHighFee = isHighFee, + ) + } +} \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveMinAmountTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveMinAmountTransformer.kt new file mode 100644 index 0000000000..91fa089b91 --- /dev/null +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/transformers/YieldSupplyActiveMinAmountTransformer.kt @@ -0,0 +1,46 @@ +package com.tangem.features.yield.supply.impl.subcomponents.active.model.transformers + +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.core.ui.format.bigdecimal.crypto +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.features.yield.supply.impl.R +import com.tangem.features.yield.supply.impl.subcomponents.active.entity.YieldSupplyActiveContentUM +import com.tangem.utils.transformer.Transformer +import java.math.BigDecimal + +/** + * Computes and sets minimum amount (fiat) and fee description note + */ +internal class YieldSupplyActiveMinAmountTransformer( + private val cryptoCurrencyStatus: CryptoCurrencyStatus, + private val appCurrency: AppCurrency, + private val minAmount: BigDecimal, +) : Transformer { + + override fun transform(prevState: YieldSupplyActiveContentUM): YieldSupplyActiveContentUM { + val cryptoCurrency = cryptoCurrencyStatus.currency + val tokenFiatRate = cryptoCurrencyStatus.value.fiatRate + + val minAmountCryptoText = minAmount.format { crypto(cryptoCurrency) } + val minAmountFiat = tokenFiatRate?.let(minAmount::multiply) + val minAmountFiatText = minAmountFiat.format { fiat(appCurrency.code, appCurrency.symbol) } + + val minFeeNoteValue = resourceReference( + id = R.string.yield_module_fee_policy_sheet_min_amount_note, + formatArgs = wrappedList( + minAmountFiatText, + minAmountCryptoText, + ), + ) + + return prevState.copy( + minAmount = stringReference(minAmountFiatText), + minFeeDescription = minFeeNoteValue, + ) + } +} \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt index 9e2346fe2f..0654981fee 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt @@ -28,17 +28,20 @@ import androidx.compose.ui.unit.dp import com.tangem.common.ui.notifications.NotificationUM import com.tangem.core.ui.components.* import com.tangem.core.ui.components.notifications.Notification +import com.tangem.core.ui.components.notifications.NotificationConfig import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.impl.subcomponents.active.entity.YieldSupplyActiveContentUM +import kotlinx.collections.immutable.persistentListOf @Composable internal fun YieldSupplyActiveContent( state: YieldSupplyActiveContentUM, isBalanceHidden: Boolean, + onReadMoreClick: () -> Unit, chartComponent: ComposableContentComponent, modifier: Modifier = Modifier, ) { @@ -61,16 +64,23 @@ internal fun YieldSupplyActiveContent( chartComponent.Content(Modifier.padding(bottom = 12.dp)) } - AnimatedVisibility(state.notificationUM != null) { - val wrappedNotification = remember(this) { requireNotNull(state.notificationUM) } - Notification( - config = wrappedNotification.config, - iconTint = null, - containerColor = TangemTheme.colors.background.action, - ) + AnimatedVisibility(state.notifications.isNotEmpty()) { + val notifications = remember(state.notifications) { state.notifications } + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + notifications.forEach { notificationUM -> + Notification( + config = notificationUM.config, + containerColor = TangemTheme.colors.background.action, + ) + } + } } - YieldSupplyActiveMyFunds(state = state, isBalanceHidden = isBalanceHidden) + YieldSupplyActiveMyFunds( + state = state, + isBalanceHidden = isBalanceHidden, + onReadMoreClick = onReadMoreClick, + ) AnimatedVisibility(state.feeDescription != null) { Text( @@ -81,12 +91,14 @@ internal fun YieldSupplyActiveContent( ) } - Text( - modifier = Modifier.padding(horizontal = 12.dp), - text = stringResourceSafe(R.string.yield_module_fee_policy_sheet_min_amount_note), - style = TangemTheme.typography.caption2, - color = TangemTheme.colors.text.tertiary, - ) + AnimatedVisibility(state.minFeeDescription != null) { + Text( + modifier = Modifier.padding(horizontal = 12.dp), + text = state.minFeeDescription?.resolveReference().orEmpty(), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + ) + } } } @@ -108,7 +120,7 @@ private fun CurrentApy(apy: TextReference?, modifier: Modifier = Modifier) { TextShimmer( modifier = modifier.width(94.dp), text = "", - style = TangemTheme.typography.head, + style = TangemTheme.typography.h2, ) } else { Row(verticalAlignment = Alignment.CenterVertically) { @@ -123,7 +135,7 @@ private fun CurrentApy(apy: TextReference?, modifier: Modifier = Modifier) { Text( modifier = modifier, text = apyText, - style = TangemTheme.typography.body1, + style = TangemTheme.typography.h2, color = TangemTheme.colors.text.accent, ) } @@ -134,7 +146,11 @@ private fun CurrentApy(apy: TextReference?, modifier: Modifier = Modifier) { @Suppress("LongMethod") @Composable -private fun YieldSupplyActiveMyFunds(state: YieldSupplyActiveContentUM, isBalanceHidden: Boolean) { +private fun YieldSupplyActiveMyFunds( + state: YieldSupplyActiveContentUM, + onReadMoreClick: () -> Unit, + isBalanceHidden: Boolean, +) { Column( modifier = Modifier .clip(RoundedCornerShape(16.dp)) @@ -164,7 +180,7 @@ private fun YieldSupplyActiveMyFunds(state: YieldSupplyActiveContentUM, isBalanc ) } SpacerH8() - DescriptionText(state = state) + DescriptionText(state = state, onReadMoreClick = onReadMoreClick) SpacerH8() HorizontalDivider( thickness = 0.5.dp, @@ -206,14 +222,14 @@ private fun YieldSupplyActiveMyFunds(state: YieldSupplyActiveContentUM, isBalanc } @Composable -private fun DescriptionText(state: YieldSupplyActiveContentUM) { +private fun DescriptionText(state: YieldSupplyActiveContentUM, onReadMoreClick: () -> Unit) { val subtitle = annotatedReference { append(state.subtitle.resolveReference()) appendSpace() withLink( LinkAnnotation.Clickable( tag = "LINK_TAG", - linkInteractionListener = {}, + linkInteractionListener = { onReadMoreClick() }, ), { appendColored( @@ -324,6 +340,7 @@ private fun YieldSupplyActiveBottomSheet_Preview( state = params, isBalanceHidden = true, chartComponent = ComposableContentComponent.EMPTY, + onReadMoreClick = {}, ) } } @@ -340,15 +357,31 @@ private class YieldSupplyActiveBottomSheetPreviewProvider : PreviewParameterProv wrappedList("USDT", "USDT"), ), subtitleLink = resourceReference(R.string.common_read_more), - notificationUM = NotificationUM.Error.InvalidAmount, - apy = stringReference("5,14%"), + notifications = persistentListOf( + NotificationUM.Error.InvalidAmount, + NotificationUM.Info( + title = resourceReference( + R.string.yield_module_amount_not_transfered_to_aave_title, + wrappedList( + "0,03", + ), + ), + subtitle = TextReference.EMPTY, + iconTint = NotificationConfig.IconTint.Accent, + ), + ), minAmount = stringReference("50 USDT"), - isHighFee = true, + currentFee = stringReference("30 USDT"), feeDescription = stringReference( "The network fee is currently too high to execute lending." + "Funds will be supplied once it drops to \$12 or below. ", ), - currentFee = stringReference("30 USDT"), + apy = stringReference("5,14%"), + isHighFee = true, + minFeeDescription = stringReference( + "The network fee is currently too high to execute lending." + + "Funds will be supplied once it drops to \$12 or below. ", + ), ), ) } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt index 66f9d0f195..0be362037a 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt @@ -10,7 +10,6 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter import com.tangem.core.ui.extensions.* -import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase @@ -33,7 +32,7 @@ import com.tangem.features.yield.supply.impl.subcomponents.approve.YieldSupplyAp import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsComponent import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsUpdateTrigger import com.tangem.features.yield.supply.impl.subcomponents.notifications.entity.YieldSupplyNotificationData -import com.tangem.utils.StringsSigns.DOT +import com.tangem.core.ui.extensions.TextReference import com.tangem.utils.TangemBlogUrlBuilder import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.transformer.update @@ -220,7 +219,6 @@ internal class YieldSupplyApproveModel @Inject constructor( val feeFiatValue = feeCryptoCurrencyStatus.value.fiatRate?.let { rate -> feeCryptoValue?.multiply(rate) } - val cryptoFee = feeCryptoValue.format { crypto(feeCryptoCurrencyStatus.currency) } val fiatFee = feeFiatValue.format { fiat(appCurrency.code, appCurrency.symbol) } uiState.update { @@ -233,14 +231,11 @@ internal class YieldSupplyApproveModel @Inject constructor( transactionDataList = persistentListOf( approvalTransitionData.copy(fee = transactionFee.normal), ), - feeValue = combinedReference( - stringReference(cryptoFee), - stringReference(" $DOT "), - stringReference(fiatFee), - ), - currentNetworkFeeValue = TextReference.EMPTY, - maxNetworkFeeValue = TextReference.EMPTY, - minAmountFeeValue = TextReference.EMPTY, + feeFiatValue = stringReference(fiatFee), + tokenFeeFiatValue = TextReference.EMPTY, + maxNetworkFeeFiatValue = TextReference.EMPTY, + minTopUpFiatValue = TextReference.EMPTY, + feeNoteValue = TextReference.EMPTY, ), ) } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/YieldSupplyFeePolicyComponent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/YieldSupplyFeePolicyComponent.kt index 2e55b046d0..88976d67ff 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/YieldSupplyFeePolicyComponent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/YieldSupplyFeePolicyComponent.kt @@ -38,7 +38,6 @@ internal class YieldSupplyFeePolicyComponent( YieldSupplyFeePolicyContent( yieldSupplyFeeUM = uiState.yieldSupplyFeeUM, tokenSymbol = params.cryptoCurrency.symbol, - networkName = params.cryptoCurrency.network.name, modifier = modifier, ) } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt index b9fc7b1d23..e6f33bab56 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/feepolicy/ui/YieldSupplyFeePolicyContent.kt @@ -6,10 +6,12 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -34,7 +36,6 @@ import kotlinx.collections.immutable.persistentListOf internal fun YieldSupplyFeePolicyContent( yieldSupplyFeeUM: YieldSupplyFeeUM, tokenSymbol: String, - networkName: String, modifier: Modifier = Modifier, ) { Column( @@ -62,68 +63,51 @@ internal fun YieldSupplyFeePolicyContent( modifier = Modifier.padding(horizontal = 16.dp), ) SpacerH24() - FooterContainer( - footer = resourceReference( - id = R.string.yield_module_fee_policy_sheet_min_amount_note, - formatArgs = wrappedList(networkName), - ), - paddingValues = PaddingValues( - top = 8.dp, - start = 12.dp, - end = 12.dp, - ), - ) { - val minAmount = when (yieldSupplyFeeUM) { - is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.minAmountFeeValue - YieldSupplyFeeUM.Error -> stringReference(StringsSigns.DASH_SIGN) - YieldSupplyFeeUM.Loading -> null - } - YieldSupplyFeeRow( - title = resourceReference(R.string.yield_module_fee_policy_sheet_min_amount_title), - value = minAmount, - ) - } + MinFeeNote(yieldSupplyFeeUM) SpacerH16() + val feeNote = when (yieldSupplyFeeUM) { + is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.feeNoteValue + YieldSupplyFeeUM.Error -> null + YieldSupplyFeeUM.Loading -> null + } FooterContainer( - footer = resourceReference( - id = R.string.yield_module_fee_policy_sheet_current_fee_note, - formatArgs = wrappedList(networkName), - ), + footer = feeNote, paddingValues = PaddingValues( top = 8.dp, start = 12.dp, end = 12.dp, ), ) { - val currentFee = when (yieldSupplyFeeUM) { - is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.currentNetworkFeeValue - YieldSupplyFeeUM.Error -> stringReference(StringsSigns.DASH_SIGN) - YieldSupplyFeeUM.Loading -> null + Column( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(14.dp)) + .background(TangemTheme.colors.background.action) + .padding(horizontal = 16.dp), + ) { + val currentFee = when (yieldSupplyFeeUM) { + is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.tokenFeeFiatValue + YieldSupplyFeeUM.Error -> stringReference(StringsSigns.DASH_SIGN) + YieldSupplyFeeUM.Loading -> null + } + YieldSupplyFeeRow( + title = resourceReference(R.string.yield_module_fee_policy_sheet_current_fee_title), + value = currentFee, + modifier = Modifier.padding(vertical = 12.dp), + ) + val maxFee = when (yieldSupplyFeeUM) { + is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.maxNetworkFeeFiatValue + YieldSupplyFeeUM.Error -> stringReference(StringsSigns.DASH_SIGN) + YieldSupplyFeeUM.Loading -> null + } + YieldSupplyFeeRow( + title = resourceReference(R.string.yield_module_fee_policy_sheet_max_fee_title), + value = maxFee, + modifier = Modifier.padding(vertical = 12.dp), + ) } - YieldSupplyFeeRow( - title = resourceReference(R.string.yield_module_fee_policy_sheet_current_fee_title), - value = currentFee, - ) - } - SpacerH16() - FooterContainer( - footer = resourceReference(R.string.yield_module_fee_policy_sheet_max_fee_note), - paddingValues = PaddingValues( - top = 8.dp, - start = 12.dp, - end = 12.dp, - ), - ) { - val maxFee = when (yieldSupplyFeeUM) { - is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.maxNetworkFeeValue - YieldSupplyFeeUM.Error -> stringReference(StringsSigns.DASH_SIGN) - YieldSupplyFeeUM.Loading -> null - } - YieldSupplyFeeRow( - title = resourceReference(R.string.yield_module_fee_policy_sheet_max_fee_title), - value = maxFee, - ) } + SpacerH8() Text( text = stringResourceSafe(R.string.yield_module_fee_policy_tangem_service_fee_title), style = TangemTheme.typography.caption2, @@ -139,6 +123,38 @@ internal fun YieldSupplyFeePolicyContent( } } +@Composable +private fun MinFeeNote(yieldSupplyFeeUM: YieldSupplyFeeUM) { + val minFeeNote = when (yieldSupplyFeeUM) { + is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.minFeeNoteValue + YieldSupplyFeeUM.Error -> null + YieldSupplyFeeUM.Loading -> null + } + FooterContainer( + footer = minFeeNote, + paddingValues = PaddingValues( + top = 8.dp, + start = 12.dp, + end = 12.dp, + ), + ) { + val minAmount = when (yieldSupplyFeeUM) { + is YieldSupplyFeeUM.Content -> yieldSupplyFeeUM.minTopUpFiatValue + YieldSupplyFeeUM.Error -> stringReference(StringsSigns.DASH_SIGN) + YieldSupplyFeeUM.Loading -> null + } + YieldSupplyFeeRow( + title = resourceReference(R.string.yield_module_fee_policy_sheet_min_amount_title), + value = minAmount, + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(14.dp)) + .background(TangemTheme.colors.background.action) + .padding(horizontal = 16.dp, vertical = 12.dp), + ) + } +} + // region Preview @Composable @Preview(showBackground = true, widthDp = 360) @@ -148,13 +164,28 @@ private fun YieldSupplyFeePolicyContent_Preview() { YieldSupplyFeePolicyContent( yieldSupplyFeeUM = YieldSupplyFeeUM.Content( transactionDataList = persistentListOf(), - feeValue = stringReference("0.0001 ETH • \$1.45"), - maxNetworkFeeValue = stringReference("8.50 USDT • \$8.50"), - currentNetworkFeeValue = stringReference("1.45 USDT • \$1.45"), - minAmountFeeValue = stringReference("50 USDT • \$50"), + feeFiatValue = stringReference("$1.45"), + maxNetworkFeeFiatValue = stringReference("$8.50"), + tokenFeeFiatValue = stringReference("$1.45"), + minTopUpFiatValue = stringReference("$50"), + feeNoteValue = resourceReference( + id = R.string.yield_module_fee_policy_sheet_fee_note, + formatArgs = wrappedList( + stringReference("$1.45"), + stringReference("1.46 USDT"), + stringReference("$8.50"), + stringReference("8.50 USDT"), + ), + ), + minFeeNoteValue = resourceReference( + id = R.string.yield_module_fee_policy_sheet_min_amount_note, + formatArgs = wrappedList( + stringReference("$2.45"), + stringReference("2.46 USDT"), + ), + ), ), tokenSymbol = "USDT", - networkName = "Ethereum", modifier = Modifier.background(TangemTheme.colors.background.primary), ) } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt index aaa41615e2..8e409ddc3d 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt @@ -20,6 +20,8 @@ import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.usecase.SendTransactionUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase +import com.tangem.domain.yield.supply.YieldSupplyRepository +import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus import com.tangem.domain.yield.supply.usecase.YieldSupplyActivateUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyEstimateEnterFeeUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyGetTokenStatusUseCase @@ -28,7 +30,6 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyStartEarningUseCase import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory -import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolTrigger import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer @@ -66,7 +67,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor( private val yieldSupplyActivateUseCase: YieldSupplyActivateUseCase, private val yieldSupplyGetTokenStatusUseCase: YieldSupplyGetTokenStatusUseCase, private val yieldSupplyMinAmountUseCase: YieldSupplyMinAmountUseCase, - private val yieldSupplyProtocolTrigger: YieldSupplyProtocolTrigger, + private val yieldSupplyRepository: YieldSupplyRepository, ) : Model(), YieldSupplyNotificationsComponent.ModelCallback { private val params: YieldSupplyStartEarningComponent.Params = paramsContainer.require() @@ -252,7 +253,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor( ) }, ifRight = { - yieldSupplyProtocolTrigger.onEnterProtocol() + yieldSupplyRepository.saveTokenProtocolStatus(cryptoCurrency, YieldSupplyEnterStatus.Enter) analytics.send(YieldSupplyAnalytics.FundsEarned) yieldSupplyActivateUseCase(cryptoCurrency) modelScope.launch { diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/transformers/YieldSupplyStartEarningFeeContentTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/transformers/YieldSupplyStartEarningFeeContentTransformer.kt index 51e5126eb7..184f0fa198 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/transformers/YieldSupplyStartEarningFeeContentTransformer.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/transformers/YieldSupplyStartEarningFeeContentTransformer.kt @@ -1,17 +1,17 @@ package com.tangem.features.yield.supply.impl.subcomponents.startearning.model.transformers import com.tangem.blockchain.common.TransactionData -import com.tangem.core.ui.extensions.combinedReference +import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM -import com.tangem.features.yield.supply.impl.common.formatter.YieldSupplyAmountFormatter -import com.tangem.utils.StringsSigns.DOT import com.tangem.utils.transformer.Transformer import kotlinx.collections.immutable.toPersistentList import java.math.BigDecimal @@ -29,30 +29,46 @@ internal class YieldSupplyStartEarningFeeContentTransformer( ) : Transformer { override fun transform(prevState: YieldSupplyActionUM): YieldSupplyActionUM { val cryptoCurrency = cryptoCurrencyStatus.currency - val fiatRate = cryptoCurrencyStatus.value.fiatRate + val tokenFiatRate = cryptoCurrencyStatus.value.fiatRate val feeFiatRate = feeCryptoCurrencyStatus.value.fiatRate - val crypto = feeValue.format { crypto(feeCryptoCurrencyStatus.currency) } - val fiatFeeValue = feeFiatRate?.let(feeValue::multiply) + val feeFiat = feeFiatRate?.let(feeValue::multiply) + val feeFiatValueText = feeFiat.format { fiat(appCurrency.code, appCurrency.symbol) } - val fiat = fiatFeeValue.format { fiat(appCurrency.code, appCurrency.symbol) } - - val tokenCryptoFeeValue = fiatRate?.let { rate -> - fiatFeeValue?.divide(rate, cryptoCurrency.decimals, RoundingMode.HALF_UP) + val tokenCryptoFee = tokenFiatRate?.let { rate -> + feeFiat?.divide(rate, cryptoCurrency.decimals, RoundingMode.HALF_UP) } + val tokenCryptoFeeValueText = tokenCryptoFee.format { crypto(cryptoCurrency) } + val tokenFiatFee = feeFiat // same fiat amount + val tokenFiatFeeValueText = tokenFiatFee.format { fiat(appCurrency.code, appCurrency.symbol) } - val tokenCryptoFee = tokenCryptoFeeValue.format { crypto(cryptoCurrency) } - - val maxCryptoFee = maxNetworkFee.format { crypto(cryptoCurrency) } - val maxFiatFeeValue = fiatRate?.let { rate -> - maxNetworkFee.divide(rate, cryptoCurrency.decimals, RoundingMode.HALF_UP) + val maxFeeCryptoValueText = maxNetworkFee.format { crypto(cryptoCurrency) } + val maxFiatFee = tokenFiatRate?.let { rate -> + maxNetworkFee.multiply(rate) } - val maxFiatFee = maxFiatFeeValue.format { fiat(appCurrency.code, appCurrency.symbol) } + val maxFiatFeeValueText = maxFiatFee.format { fiat(appCurrency.code, appCurrency.symbol) } - val minAmountTextReference = YieldSupplyAmountFormatter( - cryptoCurrency, - appCurrency, - ).invoke(minAmount, cryptoCurrencyStatus.value.fiatRate) + val minAmountCryptoText = minAmount.format { crypto(cryptoCurrency) } + val minAmountFiat = tokenFiatRate?.let(minAmount::multiply) + val minAmountFiatText = minAmountFiat.format { fiat(appCurrency.code, appCurrency.symbol) } + + val feeNoteValue = resourceReference( + id = R.string.yield_module_fee_policy_sheet_fee_note, + formatArgs = wrappedList( + tokenFiatFeeValueText, + tokenCryptoFeeValueText, + maxFiatFeeValueText, + maxFeeCryptoValueText, + ), + ) + + val minFeeNoteValue = resourceReference( + id = R.string.yield_module_fee_policy_sheet_min_amount_note, + formatArgs = wrappedList( + minAmountFiatText, + minAmountCryptoText, + ), + ) return if (cryptoCurrencyStatus.value is CryptoCurrencyStatus.Loading) { prevState.copy(yieldSupplyFeeUM = YieldSupplyFeeUM.Loading) @@ -60,22 +76,12 @@ internal class YieldSupplyStartEarningFeeContentTransformer( prevState.copy( yieldSupplyFeeUM = YieldSupplyFeeUM.Content( transactionDataList = updatedTransactionList.toPersistentList(), - feeValue = combinedReference( - stringReference(crypto), - stringReference(" $DOT "), - stringReference(fiat), - ), - currentNetworkFeeValue = combinedReference( - stringReference(tokenCryptoFee), - stringReference(" $DOT "), - stringReference(fiat), - ), - maxNetworkFeeValue = combinedReference( - stringReference(maxCryptoFee), - stringReference(" $DOT "), - stringReference(maxFiatFee), - ), - minAmountFeeValue = minAmountTextReference, + feeFiatValue = stringReference(feeFiatValueText), + tokenFeeFiatValue = stringReference(tokenFiatFeeValueText), + maxNetworkFeeFiatValue = stringReference(maxFiatFeeValueText), + minTopUpFiatValue = stringReference(minAmountFiatText), + feeNoteValue = feeNoteValue, + minFeeNoteValue = minFeeNoteValue, ), ) } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt index 268ab35f31..4ab5059e24 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt @@ -16,12 +16,13 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase import com.tangem.domain.transaction.usecase.GetFeeUseCase import com.tangem.domain.transaction.usecase.SendTransactionUseCase +import com.tangem.domain.yield.supply.YieldSupplyRepository +import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus import com.tangem.domain.yield.supply.usecase.YieldSupplyDeactivateUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory -import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolTrigger import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer @@ -55,7 +56,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor( private val yieldSupplyNotificationsUpdateTrigger: YieldSupplyNotificationsUpdateTrigger, private val yieldSupplyAlertFactory: YieldSupplyAlertFactory, private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase, - private val yieldSupplyProtocolTrigger: YieldSupplyProtocolTrigger, + private val yieldSupplyRepository: YieldSupplyRepository, ) : Model(), YieldSupplyNotificationsComponent.ModelCallback { private val params: YieldSupplyStopEarningComponent.Params = paramsContainer.require() @@ -158,7 +159,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor( ) }, ifRight = { - yieldSupplyProtocolTrigger.onExitProtocol() + yieldSupplyRepository.saveTokenProtocolStatus(cryptoCurrency, YieldSupplyEnterStatus.Exit) analytics.send( YieldSupplyAnalytics.FundsWithdrawn( token = cryptoCurrency.symbol, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/transformer/YieldSupplyStopEarningFeeContentTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/transformer/YieldSupplyStopEarningFeeContentTransformer.kt index 4e44bb47e6..0f37c2194d 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/transformer/YieldSupplyStopEarningFeeContentTransformer.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/transformer/YieldSupplyStopEarningFeeContentTransformer.kt @@ -2,16 +2,13 @@ package com.tangem.features.yield.supply.impl.subcomponents.stopearning.model.tr import com.tangem.blockchain.common.TransactionData import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.combinedReference import com.tangem.core.ui.extensions.stringReference -import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM -import com.tangem.utils.StringsSigns.DOT import com.tangem.utils.transformer.Transformer import kotlinx.collections.immutable.toPersistentList import java.math.BigDecimal @@ -24,11 +21,10 @@ internal class YieldSupplyStopEarningFeeContentTransformer( private val feeValue: BigDecimal, ) : Transformer { override fun transform(prevState: YieldSupplyActionUM): YieldSupplyActionUM { - val feeFiatValue = feeCryptoCurrencyStatus.value.fiatRate?.let { rate -> + val feeFiatValueRaw = feeCryptoCurrencyStatus.value.fiatRate?.let { rate -> feeValue.multiply(rate) } - val cryptoFee = feeValue.format { crypto(feeCryptoCurrencyStatus.currency) } - val fiatFee = feeFiatValue.format { fiat(appCurrency.code, appCurrency.symbol) } + val fiatFeeText = feeFiatValueRaw.format { fiat(appCurrency.code, appCurrency.symbol) } return if (cryptoCurrencyStatus.value is CryptoCurrencyStatus.Loading) { prevState.copy(yieldSupplyFeeUM = YieldSupplyFeeUM.Loading) @@ -37,14 +33,11 @@ internal class YieldSupplyStopEarningFeeContentTransformer( isPrimaryButtonEnabled = true, yieldSupplyFeeUM = YieldSupplyFeeUM.Content( transactionDataList = transactions.toPersistentList(), - feeValue = combinedReference( - stringReference(cryptoFee), - stringReference(" $DOT "), - stringReference(fiatFee), - ), - currentNetworkFeeValue = TextReference.EMPTY, - maxNetworkFeeValue = TextReference.EMPTY, - minAmountFeeValue = TextReference.EMPTY, + feeFiatValue = stringReference(fiatFeeText), + tokenFeeFiatValue = TextReference.EMPTY, + maxNetworkFeeFiatValue = TextReference.EMPTY, + minTopUpFiatValue = TextReference.EMPTY, + feeNoteValue = TextReference.EMPTY, ), ) } diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 33246e6685..6adbcc9cf1 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -33,8 +33,8 @@ androidxWorkManager = "2.9.0" # endregion AndroidX # region Compose -compose-runtime = "1.7.4" -compose-foundation = "1.7.4" +compose-runtime = "1.7.8" +compose-foundation = "1.7.8" compose-material3 = "1.3.1" compose-constraint = "1.0.1" compose-navigation = "2.7.7"