diff --git a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt index 7112c00220..631f9a46a0 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/StakingDomainModule.kt @@ -8,6 +8,7 @@ import com.tangem.domain.staking.repositories.StakeKitRepository import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.staking.repositories.StakeKitTransactionHashRepository import com.tangem.domain.staking.single.SingleYieldBalanceFetcher +import com.tangem.domain.staking.toggles.StakingFeatureToggles import com.tangem.domain.staking.usecase.StakingApyFlowUseCase import com.tangem.domain.walletmanager.WalletManagersFacade import dagger.Module @@ -237,7 +238,10 @@ internal object StakingDomainModule { @Provides @Singleton - fun provideStakingApyFlowUseCase(stakeKitRepository: StakeKitRepository): StakingApyFlowUseCase { - return StakingApyFlowUseCase(stakeKitRepository) + fun provideStakingApyFlowUseCase( + stakeKitRepository: StakeKitRepository, + stakingFeatureToggles: StakingFeatureToggles, + ): StakingApyFlowUseCase { + return StakingApyFlowUseCase(stakeKitRepository, stakingFeatureToggles) } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingYieldsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingYieldsStore.kt index cdac7d46bf..546383ebc6 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingYieldsStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/token/DefaultStakingYieldsStore.kt @@ -23,20 +23,22 @@ internal class DefaultStakingYieldsStore( return withTimeoutOrNull(timeout = YIELDS_WAITING_TIMEOUT, block = { get().firstOrNull() }) } - override suspend fun store(items: List) { - dataStore.updateData { data -> - val updatedItems = data.toMutableList() - items.forEach { newItem -> - val existingItemIndex = data.indexOfFirst { it.id == newItem.id } - if (existingItemIndex != -1) { - // Update existing item - updatedItems[existingItemIndex] = newItem - } else { - // Add new item - updatedItems.add(newItem) + override suspend fun store(items: List, force: Boolean) { + if (force) { + dataStore.updateData { items } + } else { + dataStore.updateData { data -> + val updatedItems = data.toMutableList() + items.forEach { newItem -> + val existingItemIndex = data.indexOfFirst { it.id == newItem.id } + if (existingItemIndex != -1) { + updatedItems[existingItemIndex] = newItem + } else { + updatedItems.add(newItem) + } } + updatedItems } - updatedItems } } diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingYieldsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingYieldsStore.kt index 29d2e37b01..b63e1c239c 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingYieldsStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/token/StakingYieldsStore.kt @@ -11,5 +11,5 @@ interface StakingYieldsStore { suspend fun getSyncWithTimeout(): List? - suspend fun store(items: List) + suspend fun store(items: List, force: Boolean = false) } \ No newline at end of file diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 578eee799f..79198ec916 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -54,6 +54,8 @@ Bist Du sicher, dass Du das neue Konto verwerfen willst? Bist Du sicher, dass Du die Bearbeitungen verwerfen willst? Nicht gespeicherte Änderungen + Einige benutzerdefinierte Token wurden von „%1$s\" Zu \"%2$sda ihre Herleitung zu diesem Konto gehört. + Einige benutzerdefinierte Token wurden verschoben. Du kannst Deinen Token nicht finden? Gehe zum Bereich „Markt“ auf der Hauptseite und fügen diesen zum kaufen im Portfolio hinzu. Du kannst Deinen Token nicht finden? Gehe zum Bereich „Markt“ auf der Hauptseite und fügen diesen zum verkaufen im Portfolio hinzu. Verkaufen @@ -88,6 +90,7 @@ Tokens im %1$s -Netzwerk werden von dieser Karte oder Ring aufgrund einer Firmware-Einschränkung nicht unterstützt. Hast du Probleme beim Scannen deiner Karte oder Ring? Diese Karte oder Ring ist für die Zusammenarbeit mit Tangem nicht geeignet + Lege zunächst einen Zugangscode fest, um die Biometrie zu aktivieren. Verwende die %1$s um Deine Wallet zu entsperren und sensible Aktionen wie das Signieren von Transaktionen zu bestätigen. Bei Hardware-Wallets ist zum Signieren weiterhin eine Karte oder ein Ring erforderlich. Standardgebühr Aktiviere die Option Standardgebühr, um die Transaktionsgebühren automatisch festzulegen und die Gebührenseite beim Senden von Geldern zu überspringen. Du kannst bei Bedarf jederzeit zu dieser Seite zurückkehren. @@ -299,6 +302,7 @@ %1$s Netzwerke Neue Adresse + Nachrichten Weiter NFT Nein @@ -364,7 +368,7 @@ Transaktion fehlgeschlagen Transaktionsstatus Transaktionen - Überweiseung + Überweisung Die Daten konnten nicht geladen werden… Ich verstehe Es ist ein Fehler aufgetreten. Bitte versuche es erneut. @@ -517,6 +521,8 @@ ID: %s Transaktions-ID kopiert Tauschen jeden Vermögenswert in Deinem Portfolio gegen diesen Token + Markt & Nachrichten + Aktuelle Trends Die folgenden Angaben sind freiwillig. Du kannst diese löschen, wenn du sie nicht weitergeben möchtest. Teile uns mit, welche Funktionen du vermisst, und wir werden versuchen, dir zu helfen. Bitte sag uns, welche Karte oder Ring du hast @@ -768,6 +774,8 @@ Volumen Rufe dies auf oder tippe auf die Suchleiste, um Token direkt vom Markt hinzuzufügen Token hinzufügen + Alle Neuigkeiten + Auf dem Laufenden bleiben NFC ist auf deinem Gerät nicht verfügbar Über NFT NFT-Vermögenswert @@ -1370,6 +1378,7 @@ Abgeschlossen Abgelehnt Ausstehend + Bedingungen und Einschränkungen Die Bank hat diese Transaktionsanfrage abgelehnt. Diese Gebühr dient zur Deckung der Kosten für die Abwicklung Deiner Überweisung. Nutze Dein Geld weiterhin. Du kannst es jederzeit einfrieren. @@ -1403,6 +1412,7 @@ Tausche beliebige Vermögenswerte in Deinem Portfolio gegen eine Karte. Kartendetails Karte entsperren + Es dauert in der Regel bis zu 15 Minuten. Tangem Pay Status anzeigen KYC für Tangem Pay in Arbeit @@ -1951,9 +1961,12 @@ Ertragsmodus Bearbeitung Deiner Einzahlung Ertragsmodus - Ertragsmodus ein - Ertragsmodus aus - Aufstockung des Ertragsmodus + Ertragsmodus aktivieren + %1$s geliefert an Aave + Ertragsmodus deaktiviert + %1$s aus Aave zurücküberwiesen + Lieferung an Aave + %1$s geliefert an Aave Automatisch Einzahlung von %1$s %2$s zur Deckung der Netzwerkgebühr für Transaktionen Die Gebühr %s kann nicht gedeckt werden diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 8e952b10f6..a944d94513 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -1568,8 +1568,11 @@ Procesando su depósito Modo Rendimiento Modo Rendimiento activado + %1$s suministrado a Aave Modo Rendimiento desactivado - Recarga del modo Rendimiento + %1$s retirado de Aave + Suministrar a Aave + %1$s suministrado a Aave 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 diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index b7f54cdaba..6b9fd987ef 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -1547,8 +1547,11 @@ Traitement de votre dépôt Mode Rendement Mode rendement activé + %1$s fourni à Aave Mode rendement désactivé - Recharger le mode Rendement + %1$s retiré d\'Aave + Approvisionnement à Aave + %1$s fourni à Aave Automatique Déposez %1$s %2$s pour couvrir les frais de réseau liés aux transactions. Impossible de couvrir les frais %s diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index afc248155a..a6478e3318 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -90,6 +90,7 @@ %1$s ネットワークのトークンは、ファームウェアの制限により、このカードまたはリングではサポートされていません。 カードまたはリングのスキャンに問題がありますか? このカードはこのアプリでは使用できません。 + まずアクセスコードを設定してから、生体認証を有効にしてください %1$sを使用してウォレットのロックを解除し、取引の署名などの機密性の高い操作を承認してください。ハードウェアウォレットの場合は、署名にカードまたはリングが必要です。 デフォルト手数料 デフォルト手数料を有効にすると、取引手数料が自動的に設定され、送金時に手数料ページを表示する必要がなくなります。必要に応じて、いつでもこのページに戻ることができます。 @@ -1910,9 +1911,12 @@ 利息モード 利息モードの有効化 利息モード - 利息モード オン - 利息モード オフ - 利息モードへの追加入金 + 利息モードが有効になりました + %1$sがAaveに供給されました + 利息モードが無効になりました + %1$sがAaveから引き出されました + Aaveへの供給 + %1$sがAaveに供給されました 自動 取引のネットワーク手数料をカバーするために、 %1$s %2$sを追加してください。 %s手数料を支払えません diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 07f0ff53e5..3d1a09fd10 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -1851,9 +1851,12 @@ Режим доходности Включение режима доходности Режим доходности - Доход включен - Доход выключен - Доход - пополнение + Режим доходности включен + %1$s отправлено в Aave + Режим доходности выключен + %1$s выведено из Aave + Перевод средств в Aave + %1$s отправлено в Aave Автоматически Внесите немного %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 8fc009f93b..3bb44e8897 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -1520,6 +1520,12 @@ Режим дохідності Відправка ваших коштів Режим прибутковості + Режим прибутковості увімкнено + %1$s постачено в Aave + Режим прибутковості вимкнено + %1$s виведено з Aave + Постачити в Aave + %1$s постачено в Aave Автоматично Внесіть трохи %1$s %2$s, щоб покрити комісію мережі за транзакції. Неможливо покрити комісію в %s diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index c28a5ef01e..6eaea7b176 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -90,6 +90,7 @@ Tokens in %1$s network are not supported by this card or ring due to firmware limitation. Are you having difficulty scanning your card or ring? This card is not designed to work with this app + Set an access code first to enable biometrics Use %1$s to unlock your wallet and approve sensitive actions, like signing transactions. For hardware wallets, a card or ring is still required to sign. Default Fee Enable Default Fee to set transaction fees automatically and skip the Fee page when sending funds. You can always go back to this page if necessary. @@ -1444,9 +1445,14 @@ A separate payment account will be created without disclosing your addresses and assets Unrivaled privacy Get your free Tangem Pay Card in minutes + Payment account + Payment account sync needed We’re fixing a technical issue. Please try again later. Service temporarily unavailable + The service is currently unreachable. Please try again later. + Tangem Pay is temporarily unavailable Tangem Pay + Use your card or ring to restore access to your payment account This is my wallet Balances hidden Balances shown @@ -1984,9 +1990,12 @@ Yield Mode Enabling Yield Mode Yield Mode - Yield Mode on - Yield Mode off - Yield Mode top-up + Yield Mode enabled + %1$s supplied to Aave + Yield Mode disabled + %1$s withdrawn from Aave + Supply to Aave + %1$s supplied to Aave Automatic Add some %1$s %2$s to cover the network fee for transactions. Unable to cover %s fee diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt index 761db501ac..53ec6c23b8 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/Transaction.kt @@ -240,6 +240,8 @@ private fun Subtitle(state: TransactionState, modifier: Modifier = Modifier) { textAlign = TextAlign.Start, color = TangemTheme.colors.text.tertiary, style = TangemTheme.typography.caption2, + maxLines = 1, + overflow = TextOverflow.Ellipsis, ) } is TransactionState.Loading -> { diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitRepository.kt index 65c3e14fd7..418992342d 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakeKitRepository.kt @@ -45,7 +45,6 @@ import com.tangem.domain.staking.model.stakekit.transaction.ActionParams import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction import com.tangem.domain.staking.repositories.StakeKitRepository -import com.tangem.domain.staking.toggles.StakingFeatureToggles import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.async @@ -60,7 +59,6 @@ internal class DefaultStakeKitRepository( private val stakingYieldsStore: StakingYieldsStore, private val dispatchers: CoroutineDispatcherProvider, private val walletManagersFacade: WalletManagersFacade, - private val stakingFeatureToggles: StakingFeatureToggles, moshi: Moshi, ) : StakeKitRepository { @@ -96,7 +94,8 @@ internal class DefaultStakeKitRepository( } } } - stakingYieldsStore.store(yields) + val shouldRewriteCache = yieldsResponses.all { it is ApiResponse.Success } + stakingYieldsStore.store(yields, shouldRewriteCache) } } @@ -161,9 +160,11 @@ internal class DefaultStakeKitRepository( } private fun getAvailableStakeKitIntegrationsIds(): List { - return StakingIntegrationID.StakeKit.entries.filterNot { - it.blockchain == Blockchain.Cardano && !stakingFeatureToggles.isCardanoStakingEnabled - } + return StakingIntegrationID.StakeKit.entries + // load all integrations for now and filter in use cases if needed + // .filterNot { + // it.blockchain == Blockchain.Cardano && !stakingFeatureToggles.isCardanoStakingEnabled + // } } private fun NetworkTypeDTO.extractJsonName(): String { diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index cfa19d6761..fd89978db8 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -6,7 +6,7 @@ import com.tangem.blockchainsdk.utils.toBlockchain import com.tangem.data.staking.store.YieldsBalancesStore import com.tangem.domain.card.common.TapWorkarounds.isWallet2 import com.tangem.domain.models.currency.CryptoCurrency -import com.tangem.domain.models.network.Network +import com.tangem.domain.models.staking.StakingID import com.tangem.domain.models.staking.YieldBalance import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId @@ -16,11 +16,14 @@ import com.tangem.domain.staking.repositories.P2PEthPoolRepository import com.tangem.domain.staking.repositories.StakeKitRepository import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.staking.toggles.StakingFeatureToggles +import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.lib.crypto.BlockchainUtils.isCardano import com.tangem.lib.crypto.BlockchainUtils.isSolana import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.channelFlow +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.withContext @Suppress("LargeClass", "LongParameterList", "TooManyFunctions") @@ -31,6 +34,7 @@ internal class DefaultStakingRepository( private val dispatchers: CoroutineDispatcherProvider, private val getUserWalletUseCase: GetUserWalletUseCase, private val stakingFeatureToggles: StakingFeatureToggles, + private val walletManagersFacade: WalletManagersFacade, ) : StakingRepository { override fun getStakingAvailability( @@ -38,7 +42,7 @@ internal class DefaultStakingRepository( cryptoCurrency: CryptoCurrency, ): Flow { return channelFlow { - if (!checkFeatureToggleEnabled(cryptoCurrency.network.id)) { + if (!checkFeatureToggleEnabled(userWalletId, cryptoCurrency)) { send(StakingAvailability.Unavailable) return@channelFlow } @@ -73,7 +77,7 @@ internal class DefaultStakingRepository( userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, ): StakingAvailability { - if (!checkFeatureToggleEnabled(cryptoCurrency.network.id)) { + if (!checkFeatureToggleEnabled(userWalletId, cryptoCurrency)) { return StakingAvailability.Unavailable } @@ -112,11 +116,26 @@ internal class DefaultStakingRepository( } } - private fun checkFeatureToggleEnabled(networkId: Network.ID): Boolean { - return when (networkId.toBlockchain()) { + private suspend fun checkFeatureToggleEnabled(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Boolean { + return when (cryptoCurrency.network.id.toBlockchain()) { Blockchain.TON -> stakingFeatureToggles.isTonStakingEnabled - Blockchain.Cardano -> stakingFeatureToggles.isCardanoStakingEnabled Blockchain.Ethereum -> stakingFeatureToggles.isEthStakingEnabled + Blockchain.Cardano -> { + val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty() + val balance = stakingBalanceStoreV2.getSyncOrNull( + userWalletId = userWalletId, + stakingId = StakingID( + integrationId = StakingIntegrationID.create(currencyId = cryptoCurrency.id)?.value + ?: return false, + address = address, + ), + ) + if (balance != null && balance is YieldBalance.Data && balance.balance.items.isNotEmpty()) { + return true + } else { + stakingFeatureToggles.isCardanoStakingEnabled + } + } else -> true } } diff --git a/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt b/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt index 6b51907e70..92c1ecf98d 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt @@ -3,12 +3,7 @@ package com.tangem.data.staking.di import com.squareup.moshi.Moshi import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.configtoggle.feature.FeatureTogglesManager -import com.tangem.data.staking.DefaultP2PEthPoolRepository -import com.tangem.data.staking.DefaultStakeKitActionRepository -import com.tangem.data.staking.DefaultStakingErrorResolver -import com.tangem.data.staking.DefaultStakeKitRepository -import com.tangem.data.staking.DefaultStakingRepository -import com.tangem.data.staking.DefaultStakeKitTransactionHashRepository +import com.tangem.data.staking.* import com.tangem.data.staking.converters.error.StakeKitErrorConverter import com.tangem.data.staking.store.YieldsBalancesStore import com.tangem.data.staking.toggles.DefaultStakingFeatureToggles @@ -21,12 +16,7 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.token.P2PEthPoolVaultsStore import com.tangem.datasource.local.token.StakingActionsStore import com.tangem.datasource.local.token.StakingYieldsStore -import com.tangem.domain.staking.repositories.P2PEthPoolRepository -import com.tangem.domain.staking.repositories.StakeKitActionRepository -import com.tangem.domain.staking.repositories.StakingErrorResolver -import com.tangem.domain.staking.repositories.StakeKitRepository -import com.tangem.domain.staking.repositories.StakingRepository -import com.tangem.domain.staking.repositories.StakeKitTransactionHashRepository +import com.tangem.domain.staking.repositories.* import com.tangem.domain.staking.toggles.StakingFeatureToggles import com.tangem.domain.staking.utils.StakingCleaner import com.tangem.domain.walletmanager.WalletManagersFacade @@ -49,7 +39,6 @@ internal object StakingDataModule { stakingYieldsStore: StakingYieldsStore, dispatchers: CoroutineDispatcherProvider, walletManagersFacade: WalletManagersFacade, - stakingFeatureToggles: StakingFeatureToggles, @NetworkMoshi moshi: Moshi, ): StakeKitRepository { return DefaultStakeKitRepository( @@ -57,7 +46,6 @@ internal object StakingDataModule { stakingYieldsStore = stakingYieldsStore, dispatchers = dispatchers, walletManagersFacade = walletManagersFacade, - stakingFeatureToggles = stakingFeatureToggles, moshi = moshi, ) } @@ -71,6 +59,7 @@ internal object StakingDataModule { dispatchers: CoroutineDispatcherProvider, getUserWalletUseCase: GetUserWalletUseCase, stakingFeatureToggles: StakingFeatureToggles, + walletManagersFacade: WalletManagersFacade, ): StakingRepository { return DefaultStakingRepository( stakeKitRepository = stakeKitRepository, @@ -78,6 +67,7 @@ internal object StakingDataModule { stakingBalanceStoreV2 = yieldsBalancesStore, dispatchers = dispatchers, getUserWalletUseCase = getUserWalletUseCase, + walletManagersFacade = walletManagersFacade, stakingFeatureToggles = stakingFeatureToggles, ) } diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt index 32edb6331c..22f83164b2 100644 --- a/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt +++ b/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt @@ -1,7 +1,10 @@ package com.tangem.domain.staking.usecase +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchainsdk.utils.toCoinId import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.domain.staking.repositories.StakeKitRepository +import com.tangem.domain.staking.toggles.StakingFeatureToggles import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map @@ -12,12 +15,18 @@ import kotlinx.coroutines.flow.map * - key: currency staking key (network.backendId + "_" + symbol) * - value: validators */ -class StakingApyFlowUseCase(private val stakeKitRepository: StakeKitRepository) { +class StakingApyFlowUseCase( + private val stakeKitRepository: StakeKitRepository, + private val stakingFeatureToggles: StakingFeatureToggles, +) { operator fun invoke(): Flow>> { return stakeKitRepository.getEnabledYields() .map { yields -> - yields.associate { yield -> + yields.filterNot { yield -> + val isCardanoYield = yield.token.coinGeckoId == Blockchain.Cardano.toCoinId() + isCardanoYield && !stakingFeatureToggles.isCardanoStakingEnabled + }.associate { yield -> val key = "${yield.token.coinGeckoId}_${yield.token.symbol}" val apy = yield.validators key to apy diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index f7fc2be325..3ef6e97629 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -1106,14 +1106,15 @@ internal class TokenDetailsModel @Inject constructor( private fun openStaking() { modelScope.launch { - val yield = getYieldUseCase.invoke( + getYieldUseCase.invoke( cryptoCurrencyId = cryptoCurrency.id, symbol = cryptoCurrency.symbol, - ).getOrElse { - error("Staking is unavailable for ${cryptoCurrency.name}") + ).onRight { yield -> + router.openStaking(userWalletId, cryptoCurrency, yield.id) + }.onLeft { + Timber.e("Staking is unavailable for ${cryptoCurrency.name}") + uiMessageSender.send(SnackbarMessage(resourceReference(R.string.staking_error_no_validators_title))) } - - router.openStaking(userWalletId, cryptoCurrency, yield.id) } } diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt index c575a8070d..0fc75e0d67 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt @@ -27,7 +27,7 @@ internal class TxHistoryItemToTransactionStateConverter( txHash = value.txHash, amount = value.getAmount(), time = value.timestampInMillis.toTimeFormat(), - status = value.status.tiUiStatus(), + status = value.status.toUiStatus(), direction = value.extractDirection(), iconRes = value.extractIcon(), title = value.extractTitle(), @@ -41,21 +41,21 @@ internal class TxHistoryItemToTransactionStateConverter( R.drawable.ic_close_24 } else { when (type) { - is TxInfo.TransactionType.Approve -> R.drawable.ic_doc_24 - is TxInfo.TransactionType.Staking.Stake, - is TxInfo.TransactionType.Staking.Vote, - is TxInfo.TransactionType.Staking.Restake, + is TransactionType.Approve -> R.drawable.ic_doc_24 + is TransactionType.Staking.Stake, + is TransactionType.Staking.Vote, + is TransactionType.Staking.Restake, -> R.drawable.ic_transaction_history_staking_24 - is TxInfo.TransactionType.Staking.ClaimRewards, + is TransactionType.Staking.ClaimRewards, -> R.drawable.ic_transaction_history_claim_rewards_24 - is TxInfo.TransactionType.Staking.Unstake, - is TxInfo.TransactionType.Staking.Withdraw, + is TransactionType.Staking.Unstake, + is TransactionType.Staking.Withdraw, -> R.drawable.ic_transaction_history_unstaking_24 - is TxInfo.TransactionType.Operation, - is TxInfo.TransactionType.Swap, - is TxInfo.TransactionType.Transfer, - is TxInfo.TransactionType.YieldSupply, - is TxInfo.TransactionType.UnknownOperation, + is TransactionType.Operation, + is TransactionType.Swap, + is TransactionType.Transfer, + is TransactionType.YieldSupply, + is TransactionType.UnknownOperation, -> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24 } } @@ -78,43 +78,67 @@ internal class TxHistoryItemToTransactionStateConverter( is TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation) } - private fun TxInfo.extractSubtitle(): TextReference = when (val interactionAddress = interactionAddressType) { - is TxInfo.InteractionAddressType.Contract -> resourceReference( - id = R.string.transaction_history_contract_address, - formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), - ) - is TxInfo.InteractionAddressType.Multiple -> resourceReference( - id = if (isOutgoing) { - R.string.transaction_history_transaction_to_address - } else { - R.string.transaction_history_transaction_from_address - }, - formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)), - ) - is TxInfo.InteractionAddressType.User -> resourceReference( - id = if (isOutgoing) { - R.string.transaction_history_transaction_to_address - } else { - R.string.transaction_history_transaction_from_address - }, - formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), - ) - is TxInfo.InteractionAddressType.Validator -> resourceReference( - id = R.string.transaction_history_transaction_validator, - formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), - ) - null -> { - TextReference.EMPTY + private fun TxInfo.extractSubtitle(): TextReference { + return when (this.type) { + is TransactionType.YieldSupply.Enter -> { + val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } + resourceReference(R.string.yield_module_transaction_enter_subtitle, wrappedList(amount)) + } + is TransactionType.YieldSupply.Topup, + -> { + val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } + resourceReference(R.string.yield_module_transaction_topup_subtitle, wrappedList(amount)) + } + is TransactionType.YieldSupply.Exit -> { + val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } + resourceReference(R.string.yield_module_transaction_exit_subtitle, wrappedList(amount)) + } + else -> extractSubtitleByAddressType() } } + private fun TxInfo.extractSubtitleByAddressType(): TextReference = + when (val interactionAddress = interactionAddressType) { + is TxInfo.InteractionAddressType.Contract -> resourceReference( + id = R.string.transaction_history_contract_address, + formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), + ) + is TxInfo.InteractionAddressType.Multiple -> resourceReference( + id = if (isOutgoing) { + R.string.transaction_history_transaction_to_address + } else { + R.string.transaction_history_transaction_from_address + }, + formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)), + ) + is TxInfo.InteractionAddressType.User -> resourceReference( + id = if (isOutgoing) { + R.string.transaction_history_transaction_to_address + } else { + R.string.transaction_history_transaction_from_address + }, + formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), + ) + is TxInfo.InteractionAddressType.Validator -> resourceReference( + id = R.string.transaction_history_transaction_validator, + formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), + ) + null -> { + TextReference.EMPTY + } + } + private fun TxInfo.extractDirection() = if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING + @Suppress("ComplexCondition") private fun TxInfo.getAmount(): String { - if (type is TxInfo.TransactionType.Staking.Vote || - type == TxInfo.TransactionType.Staking.ClaimRewards || - type == TxInfo.TransactionType.Staking.Withdraw + if (type is TransactionType.Staking.Vote || + type == TransactionType.Staking.ClaimRewards || + type == TransactionType.Staking.Withdraw || + type == TransactionType.YieldSupply.Enter || + type == TransactionType.YieldSupply.Exit || + type == TransactionType.YieldSupply.Topup ) { return "" } @@ -126,7 +150,7 @@ internal class TxHistoryItemToTransactionStateConverter( return prefix + amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) } } - private fun TxInfo.TransactionStatus.tiUiStatus() = when (this) { + private fun TxInfo.TransactionStatus.toUiStatus() = when (this) { TxInfo.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed TxInfo.TransactionStatus.Failed -> TransactionState.Content.Status.Failed TxInfo.TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt index be2bd415fe..db435626e8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt @@ -10,7 +10,8 @@ import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.utils.toTimeFormat import com.tangem.domain.models.network.TxInfo -import com.tangem.domain.models.network.TxInfo.* +import com.tangem.domain.models.network.TxInfo.TransactionStatus +import com.tangem.domain.models.network.TxInfo.TransactionType import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.impl.R import com.tangem.utils.StringsSigns.MINUS @@ -85,36 +86,56 @@ internal class TxHistoryItemStateConverter( is TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation) } - private fun TxInfo.extractSubtitle(): TextReference = when (val interactionAddress = interactionAddressType) { - is InteractionAddressType.Contract -> resourceReference( - id = R.string.transaction_history_contract_address, - formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), - ) - is InteractionAddressType.Multiple -> resourceReference( - id = if (isOutgoing) { - R.string.transaction_history_transaction_to_address - } else { - R.string.transaction_history_transaction_from_address - }, - formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)), - ) - is InteractionAddressType.User -> resourceReference( - id = if (isOutgoing) { - R.string.transaction_history_transaction_to_address - } else { - R.string.transaction_history_transaction_from_address - }, - formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), - ) - is InteractionAddressType.Validator -> resourceReference( - id = R.string.transaction_history_transaction_validator, - formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), - ) - null -> { - TextReference.EMPTY + private fun TxInfo.extractSubtitle(): TextReference { + return when (this.type) { + is TransactionType.YieldSupply.Enter -> { + val amount = amount.format { crypto(symbol = symbol, decimals = decimals) } + resourceReference(R.string.yield_module_transaction_enter_subtitle, wrappedList(amount)) + } + is TransactionType.YieldSupply.Topup, + -> { + val amount = amount.format { crypto(symbol = symbol, decimals = decimals) } + resourceReference(R.string.yield_module_transaction_topup_subtitle, wrappedList(amount)) + } + is TransactionType.YieldSupply.Exit -> { + val amount = amount.format { crypto(symbol = symbol, decimals = decimals) } + resourceReference(R.string.yield_module_transaction_exit_subtitle, wrappedList(amount)) + } + else -> extractSubtitleByAddressType() } } + private fun TxInfo.extractSubtitleByAddressType(): TextReference = + when (val interactionAddress = interactionAddressType) { + is TxInfo.InteractionAddressType.Contract -> resourceReference( + id = R.string.transaction_history_contract_address, + formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), + ) + is TxInfo.InteractionAddressType.Multiple -> resourceReference( + id = if (isOutgoing) { + R.string.transaction_history_transaction_to_address + } else { + R.string.transaction_history_transaction_from_address + }, + formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)), + ) + is TxInfo.InteractionAddressType.User -> resourceReference( + id = if (isOutgoing) { + R.string.transaction_history_transaction_to_address + } else { + R.string.transaction_history_transaction_from_address + }, + formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), + ) + is TxInfo.InteractionAddressType.Validator -> resourceReference( + id = R.string.transaction_history_transaction_validator, + formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()), + ) + null -> { + TextReference.EMPTY + } + } + private fun TxInfo.extractDirection() = if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING @@ -124,10 +145,14 @@ internal class TxHistoryItemStateConverter( TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed } + @Suppress("ComplexCondition") private fun TxInfo.getAmount(): String { if (type is TransactionType.Staking.Vote || type == TransactionType.Staking.ClaimRewards || - type == TransactionType.Staking.Withdraw + type == TransactionType.Staking.Withdraw || + type == TransactionType.YieldSupply.Enter || + type == TransactionType.YieldSupply.Exit || + type == TransactionType.YieldSupply.Topup ) { return "" } 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 f56722b5ec..cb5c7464d9 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 @@ -110,7 +110,18 @@ internal class YieldSupplyModel @Inject constructor( bottomSheetNavigation.activate(Unit) } } else { - onStartEarningClick() + uiState + .filterIsInstance() + .take(1) + .onEach { state -> + appRouter.push( + YieldSupplyPromo( + userWalletId = params.userWalletId, + cryptoCurrency = params.cryptoCurrency, + apy = state.apy, + ), + ) + }.launchIn(modelScope) } } }