diff --git a/app/src/main/java/com/tangem/tap/common/images/Coil.kt b/app/src/main/java/com/tangem/tap/common/images/Coil.kt index cda97eebe7..4b269bdca4 100644 --- a/app/src/main/java/com/tangem/tap/common/images/Coil.kt +++ b/app/src/main/java/com/tangem/tap/common/images/Coil.kt @@ -4,6 +4,7 @@ import android.content.Context import android.util.Log import coil.ImageLoader import coil.memory.MemoryCache +import coil.request.CachePolicy import coil.util.Logger import com.tangem.datasource.api.common.createNetworkLoggingInterceptor import okhttp3.OkHttpClient @@ -24,6 +25,7 @@ fun createCoilImageLoader(context: Context, logEnabled: Boolean = false): ImageL .build() } } + .memoryCachePolicy(CachePolicy.ENABLED) .memoryCache { MemoryCache.Builder(context) .maxSizePercent(COIL_MEMORY_CACHE_SIZE) diff --git a/app/src/main/java/com/tangem/tap/common/images/DefaultImagePreloader.kt b/app/src/main/java/com/tangem/tap/common/images/DefaultImagePreloader.kt index f27ffcfb95..ab8c4410f8 100644 --- a/app/src/main/java/com/tangem/tap/common/images/DefaultImagePreloader.kt +++ b/app/src/main/java/com/tangem/tap/common/images/DefaultImagePreloader.kt @@ -2,6 +2,7 @@ package com.tangem.tap.common.images import android.content.Context import coil.imageLoader +import coil.request.CachePolicy import coil.request.ImageRequest import com.tangem.core.ui.coil.ImagePreloader @@ -12,6 +13,8 @@ internal class DefaultImagePreloader( appContext.imageLoader.enqueue( ImageRequest.Builder(appContext) .data(url) + .memoryCacheKey(url) + .memoryCachePolicy(CachePolicy.ENABLED) .build(), ) } diff --git a/app/src/main/java/com/tangem/tap/di/domain/PromoDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/PromoDomainModule.kt index b741fef075..9e969c71de 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/PromoDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/PromoDomainModule.kt @@ -27,8 +27,8 @@ internal object PromoDomainModule { @Provides @Singleton - fun provideShouldShowSwapStoriesUseCase(promoRepository: PromoRepository): ShouldShowSwapStoriesUseCase { - return ShouldShowSwapStoriesUseCase(promoRepository) + fun provideShouldShowSwapStoriesUseCase(promoRepository: PromoRepository): ShouldShowStoriesUseCase { + return ShouldShowStoriesUseCase(promoRepository) } @Provides diff --git a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt index aef69796f6..a21fee2f05 100644 --- a/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/main/MainViewModel.kt @@ -30,6 +30,7 @@ import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase import com.tangem.domain.staking.FetchStakingTokensUseCase import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.features.onramp.OnrampFeatureToggles +import com.tangem.features.swap.SwapFeatureToggles import com.tangem.tap.common.extensions.setContext import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.hilt.android.lifecycle.HiltViewModel @@ -58,6 +59,7 @@ internal class MainViewModel @Inject constructor( private val getStoryContentUseCase: GetStoryContentUseCase, private val imagePreloader: ImagePreloader, private val fetchHotCryptoUseCase: FetchHotCryptoUseCase, + private val swapFeatureToggles: SwapFeatureToggles, onrampFeatureToggles: OnrampFeatureToggles, getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, ) : ViewModel() { @@ -298,12 +300,16 @@ internal class MainViewModel @Inject constructor( private fun preloadImages() { try { viewModelScope.launch { - val swapStories = getStoryContentUseCase(StoryContentIds.STORY_FIRST_TIME_SWAP.id).getOrNull() - ?: return@launch - val storiesImages = swapStories.getImageUrls() + val swapStories = if (swapFeatureToggles.isPromoStoriesEnabled) { + getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id) + .getOrNull() + } else { + null + } + val storiesImages = swapStories?.getImageUrls() // try to preload images for stories - storiesImages.forEach(imagePreloader::preload) + storiesImages?.forEach(imagePreloader::preload) } } catch (ex: Exception) { Timber.e(ex.message) diff --git a/common/ui/src/main/java/com/tangem/common/ui/swapStoriesScreen/SwapStoriesScreen.kt b/common/ui/src/main/java/com/tangem/common/ui/swapStoriesScreen/SwapStoriesScreen.kt index ef8fd5f9b6..f69585d2eb 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/swapStoriesScreen/SwapStoriesScreen.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/swapStoriesScreen/SwapStoriesScreen.kt @@ -3,10 +3,7 @@ package com.tangem.common.ui.swapStoriesScreen import android.content.res.Configuration import androidx.activity.compose.BackHandler import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -23,8 +20,8 @@ import androidx.compose.ui.unit.TextUnitType import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil.compose.SubcomposeAsyncImage +import coil.request.CachePolicy import coil.request.ImageRequest -import com.tangem.core.ui.components.SpacerH16 import com.tangem.core.ui.components.SystemBarsIconsDisposable import com.tangem.core.ui.components.stories.StoriesContainer import com.tangem.core.ui.extensions.resolveReference @@ -35,7 +32,7 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import kotlinx.collections.immutable.persistentListOf -private val SubtitleColor = Color(0xFF868692) +private val SubtitleColor = Color(0xFFB0B0B0) private const val STORIES_RELATIVE_PADDING = 0.7 @Composable @@ -60,45 +57,57 @@ fun SwapStoriesScreen(config: SwapStoriesUM) { .data(current.imageUrl) .crossfade(enable = false) .allowHardware(true) + .memoryCacheKey(current.imageUrl) + .memoryCachePolicy(CachePolicy.ENABLED) .build(), loading = { }, error = { }, contentDescription = null, ) - val height = LocalWindowSize.current.height.value - val textAlign = (height.dp.value * STORIES_RELATIVE_PADDING).dp - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .padding( - top = textAlign, - start = 56.dp, - end = 56.dp, - ), - ) { - Text( - text = current.title.resolveReference(), - style = TangemTheme.typography.head, - color = TangemColorPalette.SoftWhite, - textAlign = TextAlign.Center, - ) - SpacerH16() - Text( - text = current.subtitle.resolveReference(), - style = TextStyle( - fontSize = 16.sp, - fontWeight = FontWeight.Normal, - letterSpacing = TextUnit(value = 0.1f, type = TextUnitType.Sp), - lineHeight = TextUnit(value = 20f, type = TextUnitType.Sp), - ), - color = SubtitleColor, - textAlign = TextAlign.Center, - ) - } + SwapStoriesText(current) } } } +@Composable +private fun SwapStoriesText(current: SwapStoriesUM.Content.Config) { + val height = LocalWindowSize.current.height.value + val textAlign = (height.dp.value * STORIES_RELATIVE_PADDING).dp + Column( + verticalArrangement = Arrangement.spacedBy(14.dp), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .padding( + top = textAlign, + start = 44.dp, + end = 44.dp, + ), + ) { + Text( + text = current.title.resolveReference(), + style = TextStyle( + fontSize = 28.sp, + fontWeight = FontWeight.Bold, + letterSpacing = TextUnit(value = 0.1f, type = TextUnitType.Sp), + lineHeight = TextUnit(value = 34f, type = TextUnitType.Sp), + ), + color = TangemTheme.colors.text.constantWhite, + textAlign = TextAlign.Center, + ) + Text( + text = current.subtitle.resolveReference(), + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Normal, + letterSpacing = TextUnit(value = 0.1f, type = TextUnitType.Sp), + lineHeight = TextUnit(value = 20f, type = TextUnitType.Sp), + ), + color = SubtitleColor, + textAlign = TextAlign.Center, + ) + } +} + // region Preview @Preview(showBackground = true, widthDp = 360, heightDp = 720) @Preview(showBackground = true, widthDp = 360, heightDp = 720, uiMode = Configuration.UI_MODE_NIGHT_YES) diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt index 4f3b58d971..44e90009b0 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt @@ -127,10 +127,7 @@ interface TangemTechApi { suspend fun getHotCrypto(@Query("currency") currencyId: String): ApiResponse @GET("stories/{story_id}") - suspend fun getStoryById( - @Path("story_id") storyId: String, - @Query("language") language: String, - ): ApiResponse + suspend fun getStoryById(@Path("story_id") storyId: String): ApiResponse companion object { val marketsQuoteFields = listOf( diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index bcabd0214c..00e2ab95b4 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -119,7 +119,7 @@ object PreferencesKeys { val WAS_LOG_FILE_CLEARED by lazy { booleanPreferencesKey(name = "wasLogFileCleared") } - val SHOULD_SHOW_SWAP_STORIES_KEY by lazy { booleanPreferencesKey("shouldShowSwapStories") } + fun getShouldShowStoriesKey(storyId: String) = booleanPreferencesKey("shouldShowStories_$storyId") // region Permission fun getShouldShowPermission(permission: String) = booleanPreferencesKey("shouldShowPushPermission_$permission") diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/promo/DefaultPromoStoriesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/promo/DefaultPromoStoriesStore.kt index 858f591581..b558879687 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/promo/DefaultPromoStoriesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/promo/DefaultPromoStoriesStore.kt @@ -2,6 +2,7 @@ package com.tangem.datasource.local.promo import com.tangem.datasource.api.promotion.models.StoryContentResponse import com.tangem.datasource.local.datastore.core.StringKeyDataStore +import kotlinx.coroutines.flow.Flow internal class DefaultPromoStoriesStore( private val dataStore: StringKeyDataStore, @@ -10,6 +11,10 @@ internal class DefaultPromoStoriesStore( return dataStore.getSyncOrNull(storyId) } + override fun get(storyId: String): Flow { + return dataStore.get(storyId) + } + override suspend fun store(storyId: String, item: StoryContentResponse) { dataStore.store(storyId, item) } diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/promo/PromoStoriesStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/promo/PromoStoriesStore.kt index 73e2fb1d46..bcf6617b16 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/promo/PromoStoriesStore.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/promo/PromoStoriesStore.kt @@ -1,9 +1,12 @@ package com.tangem.datasource.local.promo import com.tangem.datasource.api.promotion.models.StoryContentResponse +import kotlinx.coroutines.flow.Flow interface PromoStoriesStore { suspend fun getSyncOrNull(storyId: String): StoryContentResponse? + fun get(storyId: String): Flow + suspend fun store(storyId: String, item: StoryContentResponse) } \ 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 a7ba510f5a..277b47bbf2 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -344,7 +344,7 @@ Karte oder Ring bestellen Karte oder Ring scannen An %s - In %s + Im %s Netzwerk Diese Informationen wurden mithilfe von KI generiert.\nTippe hier, wenn Du Fehler finden. Um den Zugangscode zu ändern, halte die Karte oder Ring wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs. Um den Passcode zu ändern, halte die Karte oder Ring wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs. @@ -571,7 +571,7 @@ Benachrichtigungen Eine Backupgerät hinzugefügt Bereite deine Karte oder Ring vor - Zweis Backupgerät hinzugefügt + Zweites Backupgerät hinzugefügt Um zu beginnen, lade einfach die wallet mit einem beliebigen Betrag auf Um zu beginnen, lade die Wallet einfach mit mehr als %1$s %2$s auf. Krypto kaufen @@ -786,13 +786,15 @@ Der Zeitraum, den du nach der Beantragung der Abhebung von Geldern aus dem Staking warten musst, bevor die Token verfügbar werden. Aufwärmphase Die zugewiesene Zeit für die Aktivierung der Teilnahme am Staking. + Zurzeit sind keine Validierer verfügbar. Bitte versuche es später noch einmal. + Staking nicht verfügbar Das Netzwerk erhebt eine Token-Genehmigungsgebühr, um zu überprüfen, ob Du die Verwendung Deines Tokens für das Staking genehmigst. Indem Du die Staking-Funktionalität nutzt, stimmst Du den %1$s und %2$s des Anbieters zu. Gesperrt Migrieren Natives Staking Derzeit sind keine aktiven Validatoren für das Staking verfügbar. Bitte versuchen Sie es später erneut. - Beim Staking im Cardano Netzwerk wird das gesamte Guthaben genutzt. Zusätzlich werden 2 ADA reserviert und nach dem Unstaking zurückgegeben. Deine ADA sind während des Stakings nicht gesperrt. + Beim Staking im Cardano-Netzwerk wird Dein gesamtes Guthaben verwendet. Weitere 2 ADA werden reserviert und nach dem Unstaking zurückgegeben. Deine ADA bleiben während des Stakings freigeschaltet. Einzelheiten zum ADA-Staking Verdiente Belohnungen werden an Deine Wallet gesendet und stehen Dir sofort zur Verfügung Stake sicher und verdienen Belohnungen @@ -810,7 +812,7 @@ Für erneutes Staking sind mindestens %1$s %2$s erforderlich. Bitte lade Dein Guthaben auf. Nicht genug %s Aufgrund von Netzwerkproblemen ist Staking derzeit nicht verfügbar. Bitte versuche es später erneut. - Beim Staking im %1$s -Netzwerk mit einem neuen Validator werden alle zuvor eingesetzten Kryptos automatisch an diesen Validator übertragen + Wenn Du im %1$s -Netzwerk mit einem neuen Validator stakest, werden alle zuvor eingesetzten Gelder automatisch an diesen Validator übertragen. Reinvestiert Deine verdienten Prämien in Deinen Einsatzbetrag und erhöht so den potenziellen Gewinn. Mit Restake kannst Du Dein Guthaben von einem Validator zu einem anderen verschieben, ohne dass Du den Stake aufheben musst. Du bist dabei, Dein gesamtes Guthaben zu staken. Wir empfehlen, einen kleinen Betrag übrig zu lassen, um die Netzwerkgebühren für die Aufhebung des Stakes oder das Einfordern von Prämien abzudecken. @@ -879,6 +881,16 @@ Das Netzwerk erhebt eine Token-Genehmigungsgebühr, um zu überprüfen, ob Sie die Verwendung Ihres Tokens für den Swap genehmigen. Tausche mehr Token zu besseren Kursen direkt in deiner Brieftasche. Neuer Swap-Anbieter verfügbar! + Du kannst Dich darauf verlassen, dass Deine Transaktionen jederzeit reibungslos ablaufen, da Sie ständig geprüft werden + Hilfe rund um die Uhr + Mit vertrauenswürdigen Börsenanbietern kannst Du mühelos Vermögenswerte tauschen, wobei alles sicher in Deiner Wallet verbleibt + Tausche sich mit uns + Höchste Sicherheit und geprüfte Anbieter gewährleisten, dass Deine Vermögenswerte bei jedem Swap geschützt sind + Sicherer denn je + Maximiere Deine Wert mit Tarifen aus einem breiten Netzwerk vertrauenswürdiger Anbieter und wähle immer den Besten aus + Bester Preis + Problemlos und intuitiv, sodass Deine Token mit nur wenigen Handgriffen getauscht werden können + Einfacher als je zuvor Der Betrag umfasst:\n- Gebühr des Dienstanbieters\n- Netzgebühr für die Rücksendung von %s von der Vermittlungsstelle an die Adresse des Nutzers. Der Betrag beinhaltet:\n• Honorar des Dienstleisters\n• Netzwerkgebühr für das Senden %1$s von der Börse zurück an die Adresse des Benutzers. \n\n Provider-Slippage kann bis zu %2$s Der Betrag enthält die Gebühren des Dienstleisters. @@ -904,7 +916,7 @@ Du hast kein Guthaben um dies zu Verkaufen. Lade dein Konto auf, um Geld von dort zu verkaufen. Du hast kein Guthaben zum Versenden. Lade dein Konto auf, um Geld von dort aus senden zu können. Das Tauschen von %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen. - Das Geld für den Verkauf steht zur Verfügung, sobald die ausstehende(n) Transaktion(en) im Netzwerk %s abgeschlossen ist/sind. + Der Verkauf von Geldmitteln ist möglich, sobald die ausstehende(n) Transaktion(en) im %s -Netzwerk abgeschlossen ist/sind. Die Geldsendung wird verfügbar, sobald die ausstehende(n) Transaktion(en) im Netzwerk %s abgeschlossen ist/sind. Der Verkauf von %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen. Staking %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen. diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 4975fb172e..e8f5fd1f79 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -87,6 +87,8 @@ ADA insuficiente Aceptar Acceso denegado + Añadir al portafolio + Agregar token Todos Autorizar Analítica @@ -140,6 +142,7 @@ Sincronizar direcciones Ir al proveedor Ir al token + Ocultar hora Importe En progreso @@ -311,6 +314,9 @@ Comprado %s Comprando %s Comprando %s... + Ocultar esta transacción + Una vez oculto, el estado de la transacción no se puede volver a ver. En su lugar, basta con deslizar el dedo para descartarla. + ¿Ocultar el estado de la transacción? No se encontraron fichas. Por favor intenta con otra solicitud ID : %s ID de transacción copiado @@ -337,6 +343,8 @@ Ilimitado Pedir Tangem Escanee + a %s + En la red %s Esta información fue generada con IA.\nPulse aquí si encuentra algún error. Para cambiar el código de acceso coloque la tarjeta o el anillo como se muestra arriba y no lo retire hasta el fin de la operación Toque para cambiar la contraseña @@ -778,12 +786,16 @@ El período que debes esperar después de solicitar el retiro de fondos del staking antes de que los tokens estén disponibles. Periodo de calentamiento El tiempo permitido para activar la participación en la apuesta. + No hay validadores disponibles en este momento. Por favor, inténtelo de nuevo más tarde. + Staking no disponible La red cobrará una tarifa de aprobación de token para verificar que usted está autorizando el uso de su token para el staking. Al utilizar la función de staking, usted acepta %1$s y %2$s del proveedor Bloqueado Migrar Native staking No hay validadores activos disponibles para hacer staking en este momento. Por favor, inténtalo de nuevo más tarde. + Al hacer staking en la red Cardano, se utiliza todo su saldo. Se reservarán 2 ADA adicionales y se devolverán después del staking. Su ADA permanece desbloqueado mientras hace staking. + Detalles del staking de ADA Recomp. won se le enviará y estará disponible para su uso inmediato Haga staking de forma segura y comience a ganar recompensas Haga de forma segura y comience a ganar recompensas diarias @@ -797,6 +809,8 @@ Gane recompensas por staking Su saldo de staking será demasiado bajo para cancelar el staking. Necesitará hacer staking más para alcanzar la cantidad mínima para cancelarlo. Saldo de staking bajo + Un mínimo de %1$s %2$s es necesario para añadir más staking. Por favor recargue su saldo. + No tiene suficiente %s El staking no está disponible actualmente debido a las condiciones de la red. Inténtelo de nuevo más tarde. El staking en la red %1$s con un nuevo validador transferirá automáticamente todos los fondos previamente en staking a este validador. Reinvierta las recompensas obtenidas en el monto apostado, aumentando las ganancias potenciales. @@ -867,6 +881,16 @@ La red cobrará una tarifa de aprobación de token para verificar que está autorizando el uso de su token para el swap. Intercambie más tokens a mejores tasas directamente en su billetera. ¡Nuevo proveedor de intercambio disponible! + Siéntase seguro con un soporte constante, lo que garantiza que sus transacciones se realicen sin problemas en cualquier momento + Asistencia 24 horas al día + Los proveedores de intercambio de confianza le permiten intercambiar activos sin esfuerzo, manteniendo todo seguro en su billetera + Intercambie con nosotros + La seguridad de alto nivel y los proveedores verificados garantizan la protección de sus activos en cada intercambio + Más seguro que nunca + Maximice su valor con tarifas de una amplia red de proveedores de confianza, eligiendo siempre la mejor + Las mejores tarifas + Sencillo e intuitivo, permite cambiar tokens con solo unos cuantos toques + Más fácil que nunca La cantidad incluye:\n• Tarifas del proveedor de servicios\n• Tarifas de red por enviar %s desde el intercambio a la dirección del usuario. El monto incluye:\n• tarifas del proveedor de servicios\n• tarifas de red por enviar %1$s desde el intercambio a la dirección del usuario. \n\nEl slippage del proveedor puede alcanzar el %2$s El importe incluye los honorarios del proveedor de servicios. @@ -1043,6 +1067,7 @@ ¿Está seguro(a) de que desea cancelar la transacción? No podrá volver a intentar realizarla. Su transacción con un importe de %1$s %2$s no se ha completado. Puede volver a intentarlo para completarla. Tiene una transacción sin terminar + Última actualización hace %s Solo quedan %s firmas en esta tarjeta. Deba retirar todos sus fondos. Recuento de firmas bajo Los tokens en diferentes redes pueden tener direcciones diferentes. Verifique que su dirección coincida con la red cuando transfieras fondos. @@ -1075,6 +1100,7 @@ La red Solana cobra un alquiler de %1$s cada %2$s días. Las cuentas que no pueden pagar el alquiler son eliminadas de la red. Deposite en su cuenta más de 2 para usarla de forma gratuita. Deslice hacia abajo para refrescar o inténtelo de nuevo más tarde. Algunas redes no están disponibles + No se han podido actualizar los saldos de algunos tokens Esta es una tarjeta de Testnet. No puede procesar transacciones y solo deba usarse para pruebas y desarrollo. Solo para fines de prueba Ignorar diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 501ad765fb..60fe380d48 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -786,6 +786,8 @@ La période que vous devez attendre après avoir demandé le retrait des fonds du staking avant que les jetons ne soient disponibles. Période d\'échauffement Le temps imparti pour activer la participation au staking. + Aucun validateur disponible pour le moment. Veuillez réessayer plus tard. + Staking indisponible Le réseau facturera des frais d’approbation de jeton pour vérifier que vous autorisez l’utilisation de votre jeton pour le jalonnement. En utilisant la fonctionnalité de staking, vous acceptez les %1$s et %2$s du fournisseur Bloqué @@ -879,6 +881,16 @@ 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. Nouveau fournisseur d\'échange disponible ! + Ayez confiance en bénéficiant d\'un support constant, garantissant que vos transactions se déroulent sans problème à tout moment + Assistance 24 heures sur 24 + Les fournisseurs d\'échange de confiance vous permettent d\'échanger des actifs sans effort, en gardant tout en sécurité dans votre portefeuille + Échangez Avec Nous + Une sécurité de haut niveau et des fournisseurs vérifiés garantissant que vos actifs sont protégés à chaque échange + Plus Sûr Que Jamais + Maximisez votre valeur avec des tarifs provenant d\'un large réseau de fournisseurs de confiance, en choisissant toujours le meilleur + Meilleurs Tarifs + Simple et intuitif, vous permettant d\'échanger des jetons en quelques clics + Plus Simple Que Jamais Le montant comprend :\n• les frais du fournisseur de services\n• les frais de réseau pour l\'envoi de %s depuis l\'échange vers l\'adresse de l\'utilisateur. Le montant comprend :\n• les frais du fournisseur de services\n• les frais de réseau pour l\'envoi de %1$s depuis l\'échange vers l\'adresse de l\'utilisateur. \n\nLe slippage du fournisseur peut atteindre %2$s Le montant comprend les frais du fournisseur de services. diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 508961e692..04c5129fac 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -89,6 +89,8 @@ Недостаточно ADA Принять Доступ запрещен + Добавить в портфель + Добавить токен Все Разрешить Аналитика @@ -146,6 +148,7 @@ Синхронизировать адреса К провайдеру Перейти в токен + Скрыть час Импортировать В процессе @@ -317,6 +320,9 @@ Куплено %s Покупка %s Покупка %s... + Скрыть эту транзакцию + После скрытия статус транзакции нельзя будет просмотреть снова. Вместо этого вы можете просто свайпнуть плашку вниз, чтобы закрыть её. + Скрыть статус транзакции? Токены не найдены. Пожалуйста, попробуйте другой запрос ID: %s ID транзакции скопирован @@ -343,6 +349,7 @@ Безлимитно Купить Сканировать + в %s В сети %s Эта информация была сгенерирована ИИ.\nНажмите здесь, если обнаружили ошибку. Чтобы изменить код доступа, приложите карту или кольцо как показано выше и не убирайте до окончания операции @@ -374,6 +381,7 @@ Рыночная капитализация Блокчейн, в котором криптовалюта изначально была создана Основная сеть + Использование ненативных сетей для токенов обеспечивает кросс-блокчейн взаимодействие, позволяя использовать активы в различных децентрализованных приложениях и смарт-контрактах на разных платформах. Однако для безопасного хранения исходного актива часто требуется хранитель или смарт-контракт, что приводит к централизации и риску контрагента. Не основной или основной блокчейн, на котором размещен токен Не основные сети Выберите сети @@ -484,6 +492,7 @@ Динамика цены Репозиторий Оценка безопасности + Показатель безопасности токена — это метрика, которая оценивает уровень безопасности блокчейна или токена на основе различных факторов и составляется из перечисленных ниже источников. Социальные Общ. предл. Максимальное количество монет или токенов, которое может когда-либо существовать для выбранной криптовалюты @@ -797,12 +806,16 @@ Период, который необходимо подождать после запроса на вывод средств из стейкинга, прежде чем токены станут доступны. Период прогрева Время, необходимое для начала процесса стейкинга и активации процесса начисления наград + В данный момент нет доступных валидаторов. Попробуйте позже. + Стейкинг недоступен Комиссия сети за одобрение токена будет взиматься за подтверждение того, что именно вы разрешаете использовать ваш токен для стейкинга. Пользуясь стейкинг сервисом, вы соглашаетесь с %1$s и %2$s Заблокировано Переместить Нативный стейкинг В данный момент нет доступных активных валидаторов для стейкинга. Пожалуйста, попробуйте позже. + При стейкинге в сети Cardano используется весь ваш баланс. Дополнительные 2 ADA будут зарезервированы и возвращены после отмены стейкинга. Ваши ADA остаются разблокированными во время стейкинга. + Подробности стейкинга ADA Полученная награда отправится на ваш кошелек и сразу станет доступна для использования Стейкайте безопасно и начинайте получать ваши награды. Стейкайте безопасно и начинайте получать ежедневные награды. @@ -816,6 +829,8 @@ Получите награду за стейкинг Оставшийся застейканный баланс будет слишком мал для вывода. Вам потребуется застейкать больше средств, чтобы достичь минимальной суммы для вывода. Низкий баланс стейкинга + Для рестейкинга необходимо %1$s%2$s. Пожалуйста, пополните баланс. + Недостаточно %s Стейкинг временно недоступен из-за проблем в сети. Пожалуйста, попробуйте позже. Стейкинг в сети %1$s с новым валидатором автоматически переведет ваши текущие застейканные средства на него. Реинвестируйте свои заработанные награды в вашу застейканную сумму, увеличивая потенциальный доход @@ -885,16 +900,16 @@ Комиссия сети за одобрение токена будет взиматься за подтверждение того, что именно вы разрешаете использовать ваш токен для обмена. Обменивайте больше токенов по лучшим курсам прямо в вашем кошельке. Новый провайдер обмена! - Надёжная поддержка 24/7, чтобы ваши финансовые операции были быстрыми и безопасными! + Чувствуйте уверенность с круглосуточной поддержкой, готовой помочь в любой ситуации! Круглосуточная поддержка - Надёжные провайдеры позволяют легко обменивать активы, обеспечивая полную безопасность в вашем кошельке + Надежные провайдеры в одном месте — обменивайте любые активы легко и быстро прямо в своем кошельке! Обменивайте с нами - Высший уровень безопасности и проверенные поставщики гарантируют защиту ваших активов при каждой сделке - Безопаснее, чем когда-либо - Получайте максимальную выгоду с лучшими курсами от надёжных поставщиков + Высший уровень безопасности и проверенные партнёры защищают каждую транзакцию + Полная защита + Автоматически находим самые выгодные предложения среди проверенных провайдеров Лучшие курсы - Просто и удобно — обмен токенов всего в несколько касаний - Проще, чем когда-либо + Интуитивный обмен в пару касаний — без сложностей и ожидания + Проще простого В сумму включено: \n• комиссия провайдера сервиса\n• комиссия сети за отправку %s от биржи обратно на адрес пользователя. В сумму включено: \n• комиссия провайдера сервиса\n• комиссия сети за отправку %1$s от биржи обратно на адрес пользователя \n\nПроскальзывание провайдера составляет до %2$s В сумму включена комиссия провайдера сервиса. @@ -1071,6 +1086,7 @@ Вы уверены что хотите отменить эту транзакцию? Вы не сможете отправить ее еще раз Ваша транзакция %1$s %2$s не была завершена. Вы можете попробовать отправить ее еще раз. У вас есть незавершенная транзакция + Последнее обновление %s На этой карте осталось всего %s подписей. Вам следует вывести все ваши средства. Малое количество подписей Токены на разных сетях могут иметь разные адреса. Пожалуйста, убедитесь при переводе средств, что ваш адрес соответствует сети. @@ -1105,6 +1121,7 @@ Сеть Solana взимает арендную плату в размере %1$s каждые 2 дня. Аккаунты, которые не могут позволить себе арендную плату, удаляются из сети. Пополните свой счет более чем на %2$s, чтобы не платить арендную плату. Свайпните вниз для обновления или попробуйте позже. Некоторые сети недоступны + Некоторые балансы токенов не удалось обновить Это Testnet карта. Он не может обрабатывать транзакции и используется только в целях тестирования и разработки. Только для целей тестирования Отказаться 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 9d16de4189..016834185c 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -89,6 +89,8 @@ Недостатньо ADA Прийняти Доступ заборонено + Додати у портфель + Додати токен Усе Дозволити Аналітика @@ -146,6 +148,7 @@ Синхронізувати адреси Перейти до провайдера Перейти до токену + Приховати година Імпортувати В процесі @@ -317,6 +320,9 @@ Купив %s Купівля %s Купівля %s... + Приховати цю транзакцію + Після приховування статус транзакції більше не можна буде переглянути. Замість цього ви можете просто провести пальцем, щоб закрити. + Приховати статус транзакції? Токенів не знайдено. Будь ласка, спробуйте інший запит ID: %s ID транзакції скопійовано @@ -343,6 +349,8 @@ Необмежено Купити Сканувати + в %s + В мережі %s Ця інформація була створена за допомогою ШІ.\nНатисніть тут, якщо знайшли помилку. Щоб змінити код доступу, прикладіть картку або кільце, як показано вище, і не прибирайте її до закінчення операції Щоб змінити пароль, прикладіть картку, як показано вище, і не прибирайте її до закінчення операції @@ -798,12 +806,16 @@ Період, який ви повинні чекати після запиту на виведення коштів зі стейкінгу, перш ніж токени стануть доступними. Період блокування Відведений час для активації участі в стейкінгу. + Наразі немає вільних валідаторів. Повторіть спробу пізніше. + Стейкінг недоступний Комісія за схвалення токену, щоб верифікувати, що саме ви дозволяєте використання токена для стейкінгу. Використовуючи функцію стейкінгу, ви погоджуєтесь з %1$s та %2$s Заблоковано Перемістити Нативний стейкінг На даний момент немає доступних активних валідаторів для стейкінгу. Будь ласка, спробуйте пізніше. + Під час стейкінгу в мережі Cardano використовується весь ваш баланс. Додаткові 2 ADA будуть зарезервовані та повернуті після скасування стейкінгу. Ваша ADA залишається розблокованою під час стейкінгу. + Деталі стейкінгу ADA Зароблені винагороди будуть надіслані на ваш гаманець і доступні для використання відразу Стейкайте безпечно та почніть отримувати ваші винагороди Стейкайте безпечно та почніть отримувати винагороди щоденно @@ -817,6 +829,8 @@ Отримуйте винагороду за стейкінг Ваш баланс стейкінгу, що залишився, буде занадто низьким, щоб вивести його зі стейкінгу. Вам потрібно буде застейкати більше, щоб досягти мінімальної суми для виводу. Низький баланс стейкінгу + Мінімум %1$s %2$s потрібно для рестейкінгу. Будь ласка, поповніть баланс. + Недостатньо %s Стейкінг тимчасово недоступний через проблеми в мережі. Будь ласка, спробуйте пізніше. Стейкінг в мережі %1$s з новим валідатором автоматично переведе всі раніше застейкані кошти до цього валідатора Реінвестуйте зароблені винагороди у суму стейкінгу, щоб збільшити потенційний прибуток. @@ -887,6 +901,16 @@ Мережа стягує комісію за схвалення токену за підтвердження, що саме ви дозволяєте використовувати ваш токен для обміну. Обмінюйте більше токенів за вигіднішим курсом прямо у своєму гаманці. З\'явився новий провайдер обмінів! + Надійна підтримка 24/7, щоб ваші фінансові операції були швидкими та надійними! + Цілодобова підтримка + Надійні провайдери дозволяють легко обмінювати активи, забезпечуючи повну безпеку у вашому гаманці + Обмінюйте з нами + Найвищий рівень безпеки та перевірені провайдери гарантують захист ваших активів при кожному обміні. + Безпечніше, ніж будь-коли + Отримуйте максимальну вигоду з кращими курсами від надійних провайдерів + Найкращі тарифи + Просто та зручно — обмін токенів в декілька дотиків + Легше, ніж будь-коли Сума включає: \n• комісію постачальника послуг\n• комісію мережі за відправлення %s з біржі назад на адресу користувача. У суму входить:\n- комісія провайдера\n- мережева комісія за відправку %1$s з біржі назад на адресу користувача. \n\nПроскакування провайдера становить до %2$s Сума включає комісію постачальника послуг. @@ -1063,6 +1087,7 @@ Ви впевнені, що хочете скасувати цю транзакцію? Ви не зможете відправити її ще раз Ваша транзакція %1$s %2$s не була завершена. Ви можете спробувати відправити її ще раз. У вас є незавершена транзакція + Останнє оновлення було %s На цій картці залишається лише %s підписів. Ви повинні вивести всі свої кошти. Низька кількість підписів Токени в різних мережах можуть мати різні адреси. Переконайтеся, що ваша адреса відповідає мережі, коли переказуєте кошти. @@ -1097,6 +1122,7 @@ Мережа Solana стягує орендну плату у розмірі %1$s кожні 2 дні. Акаунти, які не можуть дозволити собі орендну плату, видаляються з мережі. Поповніть свій рахунок на суму понад %2$s, щоб не платити орендну плату. Проведіть пальцем вниз для оновлення або спробуйте пізніше. Деякі мережі недоступні + Деякі баланси токенів не вдалося оновити Це картка Testnet. Вона не може обробляти транзакції і повинна використовуватися лише для тестування та розробки. Лише для цілей тестування Відмовитися diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 7eda311e1b..dd9d95e11a 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -881,16 +881,16 @@ The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap. Exchange more tokens at better rates directly in your wallet. New Swap Provider Available! - Feel confident with constant support, ensuring your transactions go smoothly anytime - Around-the-Clock Assistance - Trusted exchange providers let you swap assets effortlessly, keeping everything safe in your wallet - Exchange With Us - Top-level security and verified providers ensure your assets are protected during every swap - Safer Then Ever + Feel confident with round-the-clock support to help with any issues + Always Here + Multiple trusted providers in one place—swap any asset effortlessly in your wallet + Swap With Us + No fumbles, no turnovers, no blind spots—your transaction is always protected + Impenetrable Defense Maximize your value with rates sourced from a wide network of trusted providers, always choosing the best one - Best Rates + Unbeatable Rates Hassle-free and intuitive, allowing you to swap tokens in just a few taps - Easier Than Ever + Simply Convenient The amount includes:\n• service provider\'s fee\n• network fee for sending %s from the exchange back to the user\'s address. The amount includes:\n• service provider\'s fee\n• network fee for sending %1$s from the exchange back to the user\'s address. \n\nProvider slippage is up to %2$s The amount includes the service provider\'s fee. diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemColorPalette.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemColorPalette.kt index 85bd9696ad..6c0bd9671f 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemColorPalette.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemColorPalette.kt @@ -7,7 +7,6 @@ object TangemColorPalette { // region Base val Black = Color(0xFF000000) val White = Color(0xFFFFFFFF) - val SoftWhite = Color(0xFFF1F1F1) // endregion Base // region Dark diff --git a/data/promo/build.gradle.kts b/data/promo/build.gradle.kts index 03bcb7be3b..e2dd74f43c 100644 --- a/data/promo/build.gradle.kts +++ b/data/promo/build.gradle.kts @@ -14,6 +14,8 @@ dependencies { implementation(deps.androidx.datastore) implementation(deps.jodatime) + implementation(deps.timber) + implementation(deps.hilt.android) kapt(deps.hilt.kapt) diff --git a/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt index 0bf98afda0..1e0f94e8f0 100644 --- a/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt +++ b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt @@ -4,18 +4,19 @@ import com.tangem.data.promo.converters.StoryContentResponseConverter import com.tangem.datasource.api.common.response.getOrThrow import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.preferences.PreferencesKeys.SHOULD_SHOW_SWAP_STORIES_KEY +import com.tangem.datasource.local.preferences.PreferencesKeys.getShouldShowStoriesKey import com.tangem.datasource.local.preferences.utils.get import com.tangem.datasource.local.preferences.utils.getSyncOrDefault import com.tangem.datasource.local.preferences.utils.store import com.tangem.datasource.local.promo.PromoStoriesStore import com.tangem.domain.promo.PromoRepository import com.tangem.domain.promo.models.StoryContent -import com.tangem.utils.SupportedLanguages import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeoutOrNull internal class DefaultPromoRepository( private val tangemApi: TangemTechApi, @@ -42,35 +43,49 @@ internal class DefaultPromoRepository( // Use it on new promo action } - override suspend fun getStoryById(id: String): StoryContent = withContext(dispatchers.io) { + override fun getStoryById(id: String): Flow = isReadyToShowStories(id).mapLatest { + getStoryByIdSync(id) + } + + override suspend fun getStoryByIdSync(id: String): StoryContent? = withContext(dispatchers.io) { + if (!isReadyToShowStoriesSync(id)) return@withContext null + val storedPromo = promoStoriesStore.getSyncOrNull(storyId = id) // Get last stored promo by id if possible or get from network val story = if (storedPromo == null) { - val storyContent = tangemApi.getStoryById( - storyId = id, - language = SupportedLanguages.getCurrentSupportedLanguageCode(), - ).getOrThrow() - promoStoriesStore.store(storyId = id, item = storyContent) + val storyContent = runCatching { + // Important to return + withTimeoutOrNull(STORIES_LOAD_DELAY) { + tangemApi.getStoryById(storyId = id).getOrThrow() + } + }.getOrNull() + if (storyContent != null) { + promoStoriesStore.store(id, storyContent) + } storyContent } else { storedPromo } - storyContentConverter.convert(story) + story?.let { storyContentConverter.convert(it) } } - override fun isReadyToShowSwapStories(): Flow { - return appPreferencesStore.get(SHOULD_SHOW_SWAP_STORIES_KEY, true) + override fun isReadyToShowStories(storyId: String): Flow { + return appPreferencesStore.get(getShouldShowStoriesKey(storyId), true) } - override suspend fun isReadyToShowSwapStoriesSync(): Boolean { - return appPreferencesStore.getSyncOrDefault(SHOULD_SHOW_SWAP_STORIES_KEY, true) + override suspend fun isReadyToShowStoriesSync(storyId: String): Boolean { + return appPreferencesStore.getSyncOrDefault(getShouldShowStoriesKey(storyId), true) } - override suspend fun setNeverToShowSwapStories() { + override suspend fun setNeverToShowStories(storyId: String) { appPreferencesStore.store( - key = SHOULD_SHOW_SWAP_STORIES_KEY, + key = getShouldShowStoriesKey(storyId), value = false, ) } + + private companion object { + const val STORIES_LOAD_DELAY = 1000L + } } \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/GetStoryContentUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/GetStoryContentUseCase.kt index 6866cd558b..1964bb9b6e 100644 --- a/domain/promo/src/main/java/com/tangem/domain/promo/GetStoryContentUseCase.kt +++ b/domain/promo/src/main/java/com/tangem/domain/promo/GetStoryContentUseCase.kt @@ -1,13 +1,24 @@ package com.tangem.domain.promo import arrow.core.Either +import arrow.core.left +import arrow.core.right import com.tangem.domain.promo.models.StoryContent +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEmpty class GetStoryContentUseCase( private val promoRepository: PromoRepository, ) { - suspend operator fun invoke(id: String): Either = Either.catch { - promoRepository.getStoryById(id) + operator fun invoke(id: String): Flow> = promoRepository.getStoryById(id) + .map> { it.right() } + .catch { emit(it.left()) } + .onEmpty { emit(null.right()) } + + suspend fun invokeSync(id: String): Either = Either.catch { + promoRepository.getStoryByIdSync(id) } } \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/PromoRepository.kt b/domain/promo/src/main/java/com/tangem/domain/promo/PromoRepository.kt index 012806c3f9..d785801863 100644 --- a/domain/promo/src/main/java/com/tangem/domain/promo/PromoRepository.kt +++ b/domain/promo/src/main/java/com/tangem/domain/promo/PromoRepository.kt @@ -16,12 +16,14 @@ interface PromoRepository { // endregion // region Stories - suspend fun getStoryById(id: String): StoryContent + fun getStoryById(id: String): Flow - fun isReadyToShowSwapStories(): Flow + suspend fun getStoryByIdSync(id: String): StoryContent? - suspend fun isReadyToShowSwapStoriesSync(): Boolean + fun isReadyToShowStories(storyId: String): Flow - suspend fun setNeverToShowSwapStories() + suspend fun isReadyToShowStoriesSync(storyId: String): Boolean + + suspend fun setNeverToShowStories(storyId: String) // endregion } \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowStoriesUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowStoriesUseCase.kt new file mode 100644 index 0000000000..cc5357db2a --- /dev/null +++ b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowStoriesUseCase.kt @@ -0,0 +1,10 @@ +package com.tangem.domain.promo + +import kotlinx.coroutines.flow.Flow + +class ShouldShowStoriesUseCase(private val promoRepository: PromoRepository) { + operator fun invoke(storyId: String): Flow = promoRepository.isReadyToShowStories(storyId) + suspend fun invokeSync(storyId: String): Boolean = promoRepository.isReadyToShowStoriesSync(storyId) + + suspend fun neverToShow(storyId: String) = promoRepository.setNeverToShowStories(storyId) +} \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapStoriesUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapStoriesUseCase.kt deleted file mode 100644 index 35d46bbf27..0000000000 --- a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapStoriesUseCase.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.domain.promo - -import kotlinx.coroutines.flow.Flow - -class ShouldShowSwapStoriesUseCase(private val promoRepository: PromoRepository) { - operator fun invoke(): Flow = promoRepository.isReadyToShowSwapStories() - suspend fun invokeSync(): Boolean = promoRepository.isReadyToShowSwapStoriesSync() - - suspend fun neverToShow() = promoRepository.setNeverToShowSwapStories() -} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyActionsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyActionsUseCase.kt index fb593d3249..02cfa6dc4d 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyActionsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyActionsUseCase.kt @@ -3,6 +3,7 @@ package com.tangem.domain.tokens import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.exchange.RampStateManager import com.tangem.domain.promo.PromoRepository +import com.tangem.domain.promo.models.StoryContentIds import com.tangem.domain.staking.model.StakingAvailability import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.tokens.model.* @@ -66,14 +67,14 @@ class GetCryptoCurrencyActionsUseCase( } val flow = combine( flow = networkFlow, - flow2 = promoRepository.isReadyToShowSwapStories().distinctUntilChanged(), - ) { maybeCoinStatus, shouldShowSwapStories -> + flow2 = promoRepository.getStoryById(StoryContentIds.STORY_FIRST_TIME_SWAP.id).conflate(), + ) { maybeCoinStatus, maybeSwapStories -> createTokenActionsState( userWallet = userWallet, coinStatus = maybeCoinStatus.getOrNull(), cryptoCurrencyStatus = cryptoCurrencyStatus, requirements = requirements, - shouldShowSwapStories = shouldShowSwapStories, + shouldShowSwapStories = maybeSwapStories != null, ) } diff --git a/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/model/StoriesModel.kt b/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/model/StoriesModel.kt index 92bd730669..814997e992 100644 --- a/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/model/StoriesModel.kt +++ b/features/stories/impl/src/main/java/com/tangem/feature/stories/impl/model/StoriesModel.kt @@ -6,7 +6,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.domain.promo.GetStoryContentUseCase -import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase +import com.tangem.domain.promo.ShouldShowStoriesUseCase import com.tangem.domain.promo.models.StoryContentIds import com.tangem.feature.stories.api.StoriesComponent import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -22,7 +22,7 @@ internal class StoriesModel @Inject constructor( private val router: Router, override val dispatchers: CoroutineDispatcherProvider, private val getStoryContentUseCase: GetStoryContentUseCase, - private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase, + private val shouldShowStoriesUseCase: ShouldShowStoriesUseCase, ) : Model() { val state: StateFlow get() = _state @@ -38,7 +38,7 @@ internal class StoriesModel @Inject constructor( private fun openScreen(hideStories: Boolean = true) { modelScope.launch { if (hideStories) { - shouldShowSwapStoriesUseCase.neverToShow() + shouldShowStoriesUseCase.neverToShow(StoryContentIds.STORY_FIRST_TIME_SWAP.id) } router.pop() router.push(params.nextScreen) @@ -47,17 +47,21 @@ internal class StoriesModel @Inject constructor( private fun initStories() { modelScope.launch { - getStoryContentUseCase(params.storyId).fold( + getStoryContentUseCase.invokeSync(params.storyId).fold( ifLeft = { Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}") openScreen(hideStories = false) // Fallback to target screen }, ifRight = { swapStory -> - _state.update { - SwapStoriesFactory.createStoriesState( - swapStory = swapStory, - onStoriesClose = ::openScreen, - ) + if (swapStory == null) { + openScreen(hideStories = false) // Fallback to target screen + } else { + _state.update { + SwapStoriesFactory.createStoriesState( + swapStory = swapStory, + onStoriesClose = ::openScreen, + ) + } } }, ) diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index 5f87bbf478..d3e551ea25 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -28,7 +28,7 @@ import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.BlockchainErrorInfo import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.promo.GetStoryContentUseCase -import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase +import com.tangem.domain.promo.ShouldShowStoriesUseCase import com.tangem.domain.promo.models.StoryContentIds import com.tangem.domain.tokens.* import com.tangem.domain.tokens.model.CryptoCurrency @@ -90,7 +90,7 @@ internal class SwapViewModel @Inject constructor( private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val getMinimumTransactionAmountSyncUseCase: GetMinimumTransactionAmountSyncUseCase, - private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase, + private val shouldShowStoriesUseCase: ShouldShowStoriesUseCase, private val getStoryContentUseCase: GetStoryContentUseCase, private val featureToggles: SwapFeatureToggles, swapInteractorFactory: SwapInteractor.Factory, @@ -172,9 +172,7 @@ internal class SwapViewModel @Inject constructor( init { viewModelScope.launch { - val isShowPromoStories = shouldShowSwapStoriesUseCase.invokeSync() && featureToggles.isPromoStoriesEnabled - - if (isShowPromoStories) { + if (featureToggles.isPromoStoriesEnabled) { initStories() swapRouter.openScreen(SwapNavScreen.PromoStories) } @@ -289,12 +287,14 @@ internal class SwapViewModel @Inject constructor( private fun initStories() { viewModelScope.launch { - getStoryContentUseCase(StoryContentIds.STORY_FIRST_TIME_SWAP.id).fold( + getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id).fold( ifLeft = { Timber.e("Unable to load stories for ${StoryContentIds.STORY_FIRST_TIME_SWAP.id}") }, - ifRight = { - uiState = stateBuilder.createStoriesState(uiState, it) + ifRight = { story -> + story?.let { + uiState = stateBuilder.createStoriesState(uiState, story) + } }, ) } @@ -1145,7 +1145,7 @@ internal class SwapViewModel @Inject constructor( swapRouter.openScreen(SwapNavScreen.Success) }, onStoriesClose = { - viewModelScope.launch { shouldShowSwapStoriesUseCase.neverToShow() } + viewModelScope.launch { shouldShowStoriesUseCase.neverToShow(StoryContentIds.STORY_FIRST_TIME_SWAP.id) } swapRouter.openScreen(SwapNavScreen.Main) }, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt index 87438f6260..b5c157f8b4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoader.kt @@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase -import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase +import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.ApplyTokenListSortingUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet @@ -34,13 +34,13 @@ internal class MultiWalletContentLoader( private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase, private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory, private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, - private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase, + private val getStoryContentUseCase: GetStoryContentUseCase, private val swapFeatureToggles: SwapFeatureToggles, private val deepLinksRegistry: DeepLinksRegistry, ) : WalletContentLoader(id = userWallet.walletId) { override fun create(): List { - return listOfNotNull( + return buildList { MultiWalletTokenListSubscriber( userWallet = userWallet, stateHolder = stateHolder, @@ -52,7 +52,7 @@ internal class MultiWalletContentLoader( applyTokenListSortingUseCase = applyTokenListSortingUseCase, runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase, deepLinksRegistry = deepLinksRegistry, - ), + ).let(::add) MultiWalletWarningsSubscriber( userWallet = userWallet, stateHolder = stateHolder, @@ -60,13 +60,14 @@ internal class MultiWalletContentLoader( getMultiWalletWarningsFactory = getMultiWalletWarningsFactory, walletWarningsAnalyticsSender = walletWarningsAnalyticsSender, walletWarningsSingleEventSender = walletWarningsSingleEventSender, - ), - MultiWalletActionButtonsSubscriber( - userWallet = userWallet, - stateHolder = stateHolder, - shouldShowSwapStoriesUseCase = shouldShowSwapStoriesUseCase, - swapFeatureToggles = swapFeatureToggles, - ), - ) + ).let(::add) + if (swapFeatureToggles.isPromoStoriesEnabled) { + MultiWalletActionButtonsSubscriber( + userWallet = userWallet, + stateHolder = stateHolder, + getStoryContentUseCase = getStoryContentUseCase, + ).let(::add) + } + } } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt index 3107bd8568..0196a960d0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/MultiWalletContentLoaderFactory.kt @@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase -import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase +import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.ApplyTokenListSortingUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet @@ -31,7 +31,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor( private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender, private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, - private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase, + private val getStoryContentUseCase: GetStoryContentUseCase, private val swapFeatureToggles: SwapFeatureToggles, private val deepLinksRegistry: DeepLinksRegistry, ) { @@ -50,7 +50,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor( walletWarningsSingleEventSender = walletWarningsSingleEventSender, applyTokenListSortingUseCase = applyTokenListSortingUseCase, runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase, - shouldShowSwapStoriesUseCase = shouldShowSwapStoriesUseCase, + getStoryContentUseCase = getStoryContentUseCase, swapFeatureToggles = swapFeatureToggles, deepLinksRegistry = deepLinksRegistry, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt index f8c8dc9ea5..e87a5d2d10 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoader.kt @@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase -import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase +import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender @@ -32,13 +32,13 @@ internal class SingleWalletWithTokenContentLoader( private val tokenListStore: MultiWalletTokenListStore, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, - private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase, + private val getStoryContentUseCase: GetStoryContentUseCase, private val swapFeatureToggles: SwapFeatureToggles, private val deepLinksRegistry: DeepLinksRegistry, ) : WalletContentLoader(id = userWallet.walletId) { override fun create(): List { - return listOf( + return buildList { SingleWalletWithTokenListSubscriber( userWallet = userWallet, stateHolder = stateHolder, @@ -49,7 +49,7 @@ internal class SingleWalletWithTokenContentLoader( getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase, runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase, deepLinksRegistry = deepLinksRegistry, - ), + ).let(::add) MultiWalletWarningsSubscriber( userWallet = userWallet, stateHolder = stateHolder, @@ -57,13 +57,14 @@ internal class SingleWalletWithTokenContentLoader( getMultiWalletWarningsFactory = getMultiWalletWarningsFactory, walletWarningsAnalyticsSender = walletWarningsAnalyticsSender, walletWarningsSingleEventSender = walletWarningsSingleEventSender, - ), - MultiWalletActionButtonsSubscriber( - userWallet = userWallet, - stateHolder = stateHolder, - shouldShowSwapStoriesUseCase = shouldShowSwapStoriesUseCase, - swapFeatureToggles = swapFeatureToggles, - ), - ) + ).let(::add) + if (swapFeatureToggles.isPromoStoriesEnabled) { + MultiWalletActionButtonsSubscriber( + userWallet = userWallet, + stateHolder = stateHolder, + getStoryContentUseCase = getStoryContentUseCase, + ).let(::add) + } + } } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt index 8d16529907..002f3fc487 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/loaders/implementors/SingleWalletWithTokenContentLoaderFactory.kt @@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase -import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase +import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender @@ -28,7 +28,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor( private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender, private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase, - private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase, + private val getStoryContentUseCase: GetStoryContentUseCase, private val swapFeatureToggles: SwapFeatureToggles, private val deepLinksRegistry: DeepLinksRegistry, ) { @@ -46,7 +46,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor( walletWarningsAnalyticsSender = walletWarningsAnalyticsSender, walletWarningsSingleEventSender = walletWarningsSingleEventSender, runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase, - shouldShowSwapStoriesUseCase = shouldShowSwapStoriesUseCase, + getStoryContentUseCase = getStoryContentUseCase, swapFeatureToggles = swapFeatureToggles, deepLinksRegistry = deepLinksRegistry, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletActionButtonsSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletActionButtonsSubscriber.kt index 9c44ec3c2e..577a28180c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletActionButtonsSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/MultiWalletActionButtonsSubscriber.kt @@ -1,30 +1,28 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers -import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase +import com.tangem.domain.promo.GetStoryContentUseCase +import com.tangem.domain.promo.models.StoryContentIds import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.UpdateMultiWalletActionButtonBadgeTransformer -import com.tangem.features.swap.SwapFeatureToggles import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map internal class MultiWalletActionButtonsSubscriber( private val userWallet: UserWallet, private val stateHolder: WalletStateController, - private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase, - private val swapFeatureToggles: SwapFeatureToggles, + private val getStoryContentUseCase: GetStoryContentUseCase, ) : WalletSubscriber() { - override fun create(coroutineScope: CoroutineScope): Flow<*> = shouldShowSwapStoriesUseCase() - .distinctUntilChanged() - .map { showSwapBadge -> - val showBadge = swapFeatureToggles.isPromoStoriesEnabled && showSwapBadge - stateHolder.update( - UpdateMultiWalletActionButtonBadgeTransformer( - userWalletId = userWallet.walletId, - showSwapBadge = showBadge, - ), - ) - } + override fun create(coroutineScope: CoroutineScope): Flow<*> = getStoryContentUseCase( + id = StoryContentIds.STORY_FIRST_TIME_SWAP.id, + ).map { maybeSwapStories -> + val isSwapStoriesNotNull = maybeSwapStories.getOrNull() != null + stateHolder.update( + UpdateMultiWalletActionButtonBadgeTransformer( + userWalletId = userWallet.walletId, + showSwapBadge = isSwapStoriesNotNull, + ), + ) + } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt index 1e4152a1a0..e8e8c519b8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt @@ -28,7 +28,7 @@ import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.exchange.RampStateManager import com.tangem.domain.markets.TokenMarketParams import com.tangem.domain.onramp.model.OnrampSource -import com.tangem.domain.promo.ShouldShowSwapStoriesUseCase +import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.promo.models.StoryContentIds import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.staking.model.stakekit.Yield @@ -113,7 +113,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( private val removeCurrencyUseCase: RemoveCurrencyUseCase, private val getExploreUrlUseCase: GetExploreUrlUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, - private val shouldShowSwapStoriesUseCase: ShouldShowSwapStoriesUseCase, + private val getStoryContentUseCase: GetStoryContentUseCase, private val analyticsEventHandler: AnalyticsEventHandler, private val dispatchers: CoroutineDispatcherProvider, private val reduxStateHolder: ReduxStateHolder, @@ -610,8 +610,8 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( private suspend fun getSwapRoute(targetRoute: AppRoute): AppRoute { val isSwapStoriesEnabled = swapFeatureToggles.isPromoStoriesEnabled - val shouldShowSwapStories = shouldShowSwapStoriesUseCase.invokeSync() - val showSwapStories = shouldShowSwapStories && isSwapStoriesEnabled + val maybeSwapStories = getStoryContentUseCase.invokeSync(StoryContentIds.STORY_FIRST_TIME_SWAP.id) + val showSwapStories = maybeSwapStories.getOrNull() != null && isSwapStoriesEnabled return if (showSwapStories) { AppRoute.Stories(