Updated on 2026-08-14
This commit is contained in:
parent
69754e4159
commit
34cfc843ab
31 changed files with 322 additions and 170 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -127,10 +127,7 @@ interface TangemTechApi {
|
|||
suspend fun getHotCrypto(@Query("currency") currencyId: String): ApiResponse<HotCryptoResponse>
|
||||
|
||||
@GET("stories/{story_id}")
|
||||
suspend fun getStoryById(
|
||||
@Path("story_id") storyId: String,
|
||||
@Query("language") language: String,
|
||||
): ApiResponse<StoryContentResponse>
|
||||
suspend fun getStoryById(@Path("story_id") storyId: String): ApiResponse<StoryContentResponse>
|
||||
|
||||
companion object {
|
||||
val marketsQuoteFields = listOf(
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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<StoryContentResponse>,
|
||||
|
|
@ -10,6 +11,10 @@ internal class DefaultPromoStoriesStore(
|
|||
return dataStore.getSyncOrNull(storyId)
|
||||
}
|
||||
|
||||
override fun get(storyId: String): Flow<StoryContentResponse?> {
|
||||
return dataStore.get(storyId)
|
||||
}
|
||||
|
||||
override suspend fun store(storyId: String, item: StoryContentResponse) {
|
||||
dataStore.store(storyId, item)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<StoryContentResponse?>
|
||||
|
||||
suspend fun store(storyId: String, item: StoryContentResponse)
|
||||
}
|
||||
|
|
@ -344,7 +344,7 @@
|
|||
<string name="home_button_order">Karte oder Ring bestellen</string>
|
||||
<string name="home_button_scan">Karte oder Ring scannen</string>
|
||||
<string name="hot_crypto_add_token_subtitle">An %s</string>
|
||||
<string name="hot_crypto_token_network">In %s</string>
|
||||
<string name="hot_crypto_token_network">Im %s Netzwerk</string>
|
||||
<string name="information_generated_with_ai">Diese Informationen wurden mithilfe von KI generiert.\nTippe hier, wenn Du Fehler finden.</string>
|
||||
<string name="initial_message_change_access_code_body">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.</string>
|
||||
<string name="initial_message_change_passcode_body">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.</string>
|
||||
|
|
@ -571,7 +571,7 @@
|
|||
<string name="onboarding_title_notifications">Benachrichtigungen</string>
|
||||
<string name="onboarding_title_one_backup_card">Eine Backupgerät hinzugefügt</string>
|
||||
<string name="onboarding_title_scan_origin_card">Bereite deine Karte oder Ring vor</string>
|
||||
<string name="onboarding_title_two_backup_cards">Zweis Backupgerät hinzugefügt</string>
|
||||
<string name="onboarding_title_two_backup_cards">Zweites Backupgerät hinzugefügt</string>
|
||||
<string name="onboarding_top_up_body">Um zu beginnen, lade einfach die wallet mit einem beliebigen Betrag auf</string>
|
||||
<string name="onboarding_top_up_body_no_account_error">Um zu beginnen, lade die Wallet einfach mit mehr als %1$s %2$s auf.</string>
|
||||
<string name="onboarding_top_up_button_but_crypto">Krypto kaufen</string>
|
||||
|
|
@ -786,13 +786,15 @@
|
|||
<string name="staking_details_unbonding_period_info">Der Zeitraum, den du nach der Beantragung der Abhebung von Geldern aus dem Staking warten musst, bevor die Token verfügbar werden.</string>
|
||||
<string name="staking_details_warmup_period">Aufwärmphase</string>
|
||||
<string name="staking_details_warmup_period_info">Die zugewiesene Zeit für die Aktivierung der Teilnahme am Staking.</string>
|
||||
<string name="staking_error_no_validators_message">Zurzeit sind keine Validierer verfügbar. Bitte versuche es später noch einmal.</string>
|
||||
<string name="staking_error_no_validators_title">Staking nicht verfügbar</string>
|
||||
<string name="staking_give_permission_fee_footer">Das Netzwerk erhebt eine Token-Genehmigungsgebühr, um zu überprüfen, ob Du die Verwendung Deines Tokens für das Staking genehmigst.</string>
|
||||
<string name="staking_legal">Indem Du die Staking-Funktionalität nutzt, stimmst Du den %1$s und %2$s des Anbieters zu.</string>
|
||||
<string name="staking_locked">Gesperrt</string>
|
||||
<string name="staking_migrate">Migrieren</string>
|
||||
<string name="staking_native">Natives Staking</string>
|
||||
<string name="staking_no_validators_error_message">Derzeit sind keine aktiven Validatoren für das Staking verfügbar. Bitte versuchen Sie es später erneut.</string>
|
||||
<string name="staking_notification_additional_ada_deposit_text">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.</string>
|
||||
<string name="staking_notification_additional_ada_deposit_text">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.</string>
|
||||
<string name="staking_notification_additional_ada_deposit_title">Einzelheiten zum ADA-Staking</string>
|
||||
<string name="staking_notification_claim_rewards_text">Verdiente Belohnungen werden an Deine Wallet gesendet und stehen Dir sofort zur Verfügung</string>
|
||||
<string name="staking_notification_earn_rewards_text">Stake sicher und verdienen Belohnungen</string>
|
||||
|
|
@ -810,7 +812,7 @@
|
|||
<string name="staking_notification_minimum_balance_error_text">Für erneutes Staking sind mindestens %1$s %2$s erforderlich. Bitte lade Dein Guthaben auf.</string>
|
||||
<string name="staking_notification_minimum_balance_error_title">Nicht genug %s</string>
|
||||
<string name="staking_notification_network_error_text">Aufgrund von Netzwerkproblemen ist Staking derzeit nicht verfügbar. Bitte versuche es später erneut.</string>
|
||||
<string name="staking_notification_new_validator_funds_transfer">Beim Staking im %1$s -Netzwerk mit einem neuen Validator werden alle zuvor eingesetzten Kryptos automatisch an diesen Validator übertragen</string>
|
||||
<string name="staking_notification_new_validator_funds_transfer">Wenn Du im %1$s -Netzwerk mit einem neuen Validator stakest, werden alle zuvor eingesetzten Gelder automatisch an diesen Validator übertragen.</string>
|
||||
<string name="staking_notification_restake_rewards_text">Reinvestiert Deine verdienten Prämien in Deinen Einsatzbetrag und erhöht so den potenziellen Gewinn.</string>
|
||||
<string name="staking_notification_restake_text">Mit Restake kannst Du Dein Guthaben von einem Validator zu einem anderen verschieben, ohne dass Du den Stake aufheben musst.</string>
|
||||
<string name="staking_notification_stake_entire_balance_text">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.</string>
|
||||
|
|
@ -879,6 +881,16 @@
|
|||
<string name="swap_give_permission_fee_footer">Das Netzwerk erhebt eine Token-Genehmigungsgebühr, um zu überprüfen, ob Sie die Verwendung Ihres Tokens für den Swap genehmigen.</string>
|
||||
<string name="swap_promo_text">Tausche mehr Token zu besseren Kursen direkt in deiner Brieftasche.</string>
|
||||
<string name="swap_promo_title">Neuer Swap-Anbieter verfügbar!</string>
|
||||
<string name="swap_story_fifth_subtitle">Du kannst Dich darauf verlassen, dass Deine Transaktionen jederzeit reibungslos ablaufen, da Sie ständig geprüft werden</string>
|
||||
<string name="swap_story_fifth_title">Hilfe rund um die Uhr</string>
|
||||
<string name="swap_story_first_subtitle">Mit vertrauenswürdigen Börsenanbietern kannst Du mühelos Vermögenswerte tauschen, wobei alles sicher in Deiner Wallet verbleibt</string>
|
||||
<string name="swap_story_first_title">Tausche sich mit uns</string>
|
||||
<string name="swap_story_forth_subtitle">Höchste Sicherheit und geprüfte Anbieter gewährleisten, dass Deine Vermögenswerte bei jedem Swap geschützt sind</string>
|
||||
<string name="swap_story_forth_title">Sicherer denn je</string>
|
||||
<string name="swap_story_second_subtitle">Maximiere Deine Wert mit Tarifen aus einem breiten Netzwerk vertrauenswürdiger Anbieter und wähle immer den Besten aus</string>
|
||||
<string name="swap_story_second_title">Bester Preis</string>
|
||||
<string name="swap_story_third_subtitle">Problemlos und intuitiv, sodass Deine Token mit nur wenigen Handgriffen getauscht werden können</string>
|
||||
<string name="swap_story_third_title">Einfacher als je zuvor</string>
|
||||
<string name="swapping_alert_cex_description">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.</string>
|
||||
<string name="swapping_alert_cex_description_with_slippage">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</string>
|
||||
<string name="swapping_alert_dex_description">Der Betrag enthält die Gebühren des Dienstleisters.</string>
|
||||
|
|
@ -904,7 +916,7 @@
|
|||
<string name="token_button_unavailability_reason_empty_balance_sell">Du hast kein Guthaben um dies zu Verkaufen. Lade dein Konto auf, um Geld von dort zu verkaufen.</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_send">Du hast kein Guthaben zum Versenden. Lade dein Konto auf, um Geld von dort aus senden zu können.</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">Das Tauschen von %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen.</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_sell">Das Geld für den Verkauf steht zur Verfügung, sobald die ausstehende(n) Transaktion(en) im Netzwerk %s abgeschlossen ist/sind.</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_sell">Der Verkauf von Geldmitteln ist möglich, sobald die ausstehende(n) Transaktion(en) im %s -Netzwerk abgeschlossen ist/sind.</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_send">Die Geldsendung wird verfügbar, sobald die ausstehende(n) Transaktion(en) im Netzwerk %s abgeschlossen ist/sind.</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">Der Verkauf von %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen.</string>
|
||||
<string name="token_button_unavailability_reason_staking_unavailable">Staking %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen.</string>
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@
|
|||
<string name="cardano_max_amount_has_token_title">ADA insuficiente</string>
|
||||
<string name="common_accept">Aceptar</string>
|
||||
<string name="common_access_denied">Acceso denegado</string>
|
||||
<string name="common_add_to_portfolio">Añadir al portafolio</string>
|
||||
<string name="common_add_token">Agregar token</string>
|
||||
<string name="common_all">Todos</string>
|
||||
<string name="common_allow">Autorizar</string>
|
||||
<string name="common_analytics">Analítica</string>
|
||||
|
|
@ -140,6 +142,7 @@
|
|||
<string name="common_generate_addresses">Sincronizar direcciones</string>
|
||||
<string name="common_go_to_provider">Ir al proveedor</string>
|
||||
<string name="common_go_to_token">Ir al token</string>
|
||||
<string name="common_hide">Ocultar</string>
|
||||
<string name="common_hour">hora</string>
|
||||
<string name="common_import">Importe</string>
|
||||
<string name="common_in_progress">En progreso</string>
|
||||
|
|
@ -311,6 +314,9 @@
|
|||
<string name="express_status_bought">Comprado %s</string>
|
||||
<string name="express_status_buying">Comprando %s</string>
|
||||
<string name="express_status_buying_active">Comprando %s...</string>
|
||||
<string name="express_status_hide_button_text">Ocultar esta transacción</string>
|
||||
<string name="express_status_hide_dialog_text">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.</string>
|
||||
<string name="express_status_hide_dialog_title">¿Ocultar el estado de la transacción?</string>
|
||||
<string name="express_token_list_empty_search">No se encontraron fichas. Por favor intenta con otra solicitud</string>
|
||||
<string name="express_transaction_id">ID : %s</string>
|
||||
<string name="express_transaction_id_copied">ID de transacción copiado</string>
|
||||
|
|
@ -337,6 +343,8 @@
|
|||
<string name="give_permission_unlimited">Ilimitado</string>
|
||||
<string name="home_button_order">Pedir Tangem</string>
|
||||
<string name="home_button_scan">Escanee</string>
|
||||
<string name="hot_crypto_add_token_subtitle">a %s</string>
|
||||
<string name="hot_crypto_token_network">En la red %s</string>
|
||||
<string name="information_generated_with_ai">Esta información fue generada con IA.\nPulse aquí si encuentra algún error.</string>
|
||||
<string name="initial_message_change_access_code_body">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</string>
|
||||
<string name="initial_message_change_passcode_body">Toque para cambiar la contraseña</string>
|
||||
|
|
@ -778,12 +786,16 @@
|
|||
<string name="staking_details_unbonding_period_info">El período que debes esperar después de solicitar el retiro de fondos del staking antes de que los tokens estén disponibles.</string>
|
||||
<string name="staking_details_warmup_period">Periodo de calentamiento</string>
|
||||
<string name="staking_details_warmup_period_info">El tiempo permitido para activar la participación en la apuesta.</string>
|
||||
<string name="staking_error_no_validators_message">No hay validadores disponibles en este momento. Por favor, inténtelo de nuevo más tarde.</string>
|
||||
<string name="staking_error_no_validators_title">Staking no disponible</string>
|
||||
<string name="staking_give_permission_fee_footer">La red cobrará una tarifa de aprobación de token para verificar que usted está autorizando el uso de su token para el staking.</string>
|
||||
<string name="staking_legal">Al utilizar la función de staking, usted acepta %1$s y %2$s del proveedor</string>
|
||||
<string name="staking_locked">Bloqueado</string>
|
||||
<string name="staking_migrate">Migrar</string>
|
||||
<string name="staking_native">Native staking</string>
|
||||
<string name="staking_no_validators_error_message">No hay validadores activos disponibles para hacer staking en este momento. Por favor, inténtalo de nuevo más tarde.</string>
|
||||
<string name="staking_notification_additional_ada_deposit_text">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.</string>
|
||||
<string name="staking_notification_additional_ada_deposit_title">Detalles del staking de ADA</string>
|
||||
<string name="staking_notification_claim_rewards_text">Recomp. won se le enviará y estará disponible para su uso inmediato</string>
|
||||
<string name="staking_notification_earn_rewards_text">Haga staking de forma segura y comience a ganar recompensas</string>
|
||||
<string name="staking_notification_earn_rewards_text_daily">Haga de forma segura y comience a ganar recompensas diarias</string>
|
||||
|
|
@ -797,6 +809,8 @@
|
|||
<string name="staking_notification_earn_rewards_title">Gane recompensas por staking</string>
|
||||
<string name="staking_notification_low_staked_balance_text">Su saldo de staking será demasiado bajo para cancelar el staking. Necesitará hacer staking más para alcanzar la cantidad mínima para cancelarlo.</string>
|
||||
<string name="staking_notification_low_staked_balance_title">Saldo de staking bajo</string>
|
||||
<string name="staking_notification_minimum_balance_error_text">Un mínimo de %1$s %2$s es necesario para añadir más staking. Por favor recargue su saldo.</string>
|
||||
<string name="staking_notification_minimum_balance_error_title">No tiene suficiente %s</string>
|
||||
<string name="staking_notification_network_error_text">El staking no está disponible actualmente debido a las condiciones de la red. Inténtelo de nuevo más tarde.</string>
|
||||
<string name="staking_notification_new_validator_funds_transfer">El staking en la red %1$s con un nuevo validador transferirá automáticamente todos los fondos previamente en staking a este validador.</string>
|
||||
<string name="staking_notification_restake_rewards_text">Reinvierta las recompensas obtenidas en el monto apostado, aumentando las ganancias potenciales.</string>
|
||||
|
|
@ -867,6 +881,16 @@
|
|||
<string name="swap_give_permission_fee_footer">La red cobrará una tarifa de aprobación de token para verificar que está autorizando el uso de su token para el swap.</string>
|
||||
<string name="swap_promo_text">Intercambie más tokens a mejores tasas directamente en su billetera.</string>
|
||||
<string name="swap_promo_title">¡Nuevo proveedor de intercambio disponible!</string>
|
||||
<string name="swap_story_fifth_subtitle">Siéntase seguro con un soporte constante, lo que garantiza que sus transacciones se realicen sin problemas en cualquier momento</string>
|
||||
<string name="swap_story_fifth_title">Asistencia 24 horas al día</string>
|
||||
<string name="swap_story_first_subtitle">Los proveedores de intercambio de confianza le permiten intercambiar activos sin esfuerzo, manteniendo todo seguro en su billetera</string>
|
||||
<string name="swap_story_first_title">Intercambie con nosotros</string>
|
||||
<string name="swap_story_forth_subtitle">La seguridad de alto nivel y los proveedores verificados garantizan la protección de sus activos en cada intercambio</string>
|
||||
<string name="swap_story_forth_title">Más seguro que nunca</string>
|
||||
<string name="swap_story_second_subtitle">Maximice su valor con tarifas de una amplia red de proveedores de confianza, eligiendo siempre la mejor</string>
|
||||
<string name="swap_story_second_title">Las mejores tarifas</string>
|
||||
<string name="swap_story_third_subtitle">Sencillo e intuitivo, permite cambiar tokens con solo unos cuantos toques</string>
|
||||
<string name="swap_story_third_title">Más fácil que nunca</string>
|
||||
<string name="swapping_alert_cex_description">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.</string>
|
||||
<string name="swapping_alert_cex_description_with_slippage">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</string>
|
||||
<string name="swapping_alert_dex_description">El importe incluye los honorarios del proveedor de servicios.</string>
|
||||
|
|
@ -1043,6 +1067,7 @@
|
|||
<string name="warning_kaspa_unfinished_token_transaction_discard_message">¿Está seguro(a) de que desea cancelar la transacción? No podrá volver a intentar realizarla.</string>
|
||||
<string name="warning_kaspa_unfinished_token_transaction_message">Su transacción con un importe de %1$s %2$s no se ha completado. Puede volver a intentarlo para completarla.</string>
|
||||
<string name="warning_kaspa_unfinished_token_transaction_title">Tiene una transacción sin terminar</string>
|
||||
<string name="warning_last_balance_updated_time">Última actualización hace %s</string>
|
||||
<string name="warning_low_signatures_message">Solo quedan %s firmas en esta tarjeta. Deba retirar todos sus fondos.</string>
|
||||
<string name="warning_low_signatures_title">Recuento de firmas bajo</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Los tokens en diferentes redes pueden tener direcciones diferentes. Verifique que su dirección coincida con la red cuando transfieras fondos.</string>
|
||||
|
|
@ -1075,6 +1100,7 @@
|
|||
<string name="warning_solana_rent_fee_message">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.</string>
|
||||
<string name="warning_some_networks_unreachable_message">Deslice hacia abajo para refrescar o inténtelo de nuevo más tarde.</string>
|
||||
<string name="warning_some_networks_unreachable_title">Algunas redes no están disponibles</string>
|
||||
<string name="warning_some_token_balances_not_updated">No se han podido actualizar los saldos de algunos tokens</string>
|
||||
<string name="warning_testnet_card_message">Esta es una tarjeta de Testnet. No puede procesar transacciones y solo deba usarse para pruebas y desarrollo.</string>
|
||||
<string name="warning_testnet_card_title">Solo para fines de prueba</string>
|
||||
<string name="welcome_interrupted_backup_alert_discard">Ignorar</string>
|
||||
|
|
|
|||
|
|
@ -786,6 +786,8 @@
|
|||
<string name="staking_details_unbonding_period_info">La période que vous devez attendre après avoir demandé le retrait des fonds du staking avant que les jetons ne soient disponibles.</string>
|
||||
<string name="staking_details_warmup_period">Période d\'échauffement</string>
|
||||
<string name="staking_details_warmup_period_info">Le temps imparti pour activer la participation au staking.</string>
|
||||
<string name="staking_error_no_validators_message">Aucun validateur disponible pour le moment. Veuillez réessayer plus tard.</string>
|
||||
<string name="staking_error_no_validators_title">Staking indisponible</string>
|
||||
<string name="staking_give_permission_fee_footer">Le réseau facturera des frais d’approbation de jeton pour vérifier que vous autorisez l’utilisation de votre jeton pour le jalonnement.</string>
|
||||
<string name="staking_legal">En utilisant la fonctionnalité de staking, vous acceptez les %1$s et %2$s du fournisseur</string>
|
||||
<string name="staking_locked">Bloqué</string>
|
||||
|
|
@ -879,6 +881,16 @@
|
|||
<string name="swap_give_permission_fee_footer">Le réseau facturera des frais d\'approbation de jeton pour vérifier que vous autorisez l\'utilisation de votre jeton pour l\'échange.</string>
|
||||
<string name="swap_promo_text">Échangez plus de jetons à de meilleurs taux directement dans votre portefeuille.</string>
|
||||
<string name="swap_promo_title">Nouveau fournisseur d\'échange disponible !</string>
|
||||
<string name="swap_story_fifth_subtitle">Ayez confiance en bénéficiant d\'un support constant, garantissant que vos transactions se déroulent sans problème à tout moment</string>
|
||||
<string name="swap_story_fifth_title">Assistance 24 heures sur 24</string>
|
||||
<string name="swap_story_first_subtitle">Les fournisseurs d\'échange de confiance vous permettent d\'échanger des actifs sans effort, en gardant tout en sécurité dans votre portefeuille</string>
|
||||
<string name="swap_story_first_title">Échangez Avec Nous</string>
|
||||
<string name="swap_story_forth_subtitle">Une sécurité de haut niveau et des fournisseurs vérifiés garantissant que vos actifs sont protégés à chaque échange</string>
|
||||
<string name="swap_story_forth_title">Plus Sûr Que Jamais</string>
|
||||
<string name="swap_story_second_subtitle">Maximisez votre valeur avec des tarifs provenant d\'un large réseau de fournisseurs de confiance, en choisissant toujours le meilleur</string>
|
||||
<string name="swap_story_second_title">Meilleurs Tarifs</string>
|
||||
<string name="swap_story_third_subtitle">Simple et intuitif, vous permettant d\'échanger des jetons en quelques clics</string>
|
||||
<string name="swap_story_third_title">Plus Simple Que Jamais</string>
|
||||
<string name="swapping_alert_cex_description">Le montant comprend :\n• les frais du fournisseur de services\n• les frais de réseau pour l\'envoi de %s depuis l\'échange vers l\'adresse de l\'utilisateur.</string>
|
||||
<string name="swapping_alert_cex_description_with_slippage">Le montant comprend :\n• les frais du fournisseur de services\n• les frais de réseau pour l\'envoi de %1$s depuis l\'échange vers l\'adresse de l\'utilisateur. \n\nLe slippage du fournisseur peut atteindre %2$s</string>
|
||||
<string name="swapping_alert_dex_description">Le montant comprend les frais du fournisseur de services.</string>
|
||||
|
|
|
|||
|
|
@ -89,6 +89,8 @@
|
|||
<string name="cardano_max_amount_has_token_title">Недостаточно ADA</string>
|
||||
<string name="common_accept">Принять</string>
|
||||
<string name="common_access_denied">Доступ запрещен</string>
|
||||
<string name="common_add_to_portfolio">Добавить в портфель</string>
|
||||
<string name="common_add_token">Добавить токен</string>
|
||||
<string name="common_all">Все</string>
|
||||
<string name="common_allow">Разрешить</string>
|
||||
<string name="common_analytics">Аналитика</string>
|
||||
|
|
@ -146,6 +148,7 @@
|
|||
<string name="common_generate_addresses">Синхронизировать адреса</string>
|
||||
<string name="common_go_to_provider">К провайдеру</string>
|
||||
<string name="common_go_to_token">Перейти в токен</string>
|
||||
<string name="common_hide">Скрыть</string>
|
||||
<string name="common_hour">час</string>
|
||||
<string name="common_import">Импортировать</string>
|
||||
<string name="common_in_progress">В процессе</string>
|
||||
|
|
@ -317,6 +320,9 @@
|
|||
<string name="express_status_bought">Куплено %s</string>
|
||||
<string name="express_status_buying">Покупка %s</string>
|
||||
<string name="express_status_buying_active">Покупка %s...</string>
|
||||
<string name="express_status_hide_button_text">Скрыть эту транзакцию</string>
|
||||
<string name="express_status_hide_dialog_text">После скрытия статус транзакции нельзя будет просмотреть снова. Вместо этого вы можете просто свайпнуть плашку вниз, чтобы закрыть её.</string>
|
||||
<string name="express_status_hide_dialog_title">Скрыть статус транзакции?</string>
|
||||
<string name="express_token_list_empty_search">Токены не найдены. Пожалуйста, попробуйте другой запрос</string>
|
||||
<string name="express_transaction_id">ID: %s</string>
|
||||
<string name="express_transaction_id_copied">ID транзакции скопирован</string>
|
||||
|
|
@ -343,6 +349,7 @@
|
|||
<string name="give_permission_unlimited">Безлимитно</string>
|
||||
<string name="home_button_order">Купить</string>
|
||||
<string name="home_button_scan">Сканировать</string>
|
||||
<string name="hot_crypto_add_token_subtitle">в %s</string>
|
||||
<string name="hot_crypto_token_network">В сети %s</string>
|
||||
<string name="information_generated_with_ai">Эта информация была сгенерирована ИИ.\nНажмите здесь, если обнаружили ошибку.</string>
|
||||
<string name="initial_message_change_access_code_body">Чтобы изменить код доступа, приложите карту или кольцо как показано выше и не убирайте до окончания операции</string>
|
||||
|
|
@ -374,6 +381,7 @@
|
|||
<string name="manage_tokens_list_header_title">Рыночная капитализация</string>
|
||||
<string name="manage_tokens_network_selector_native_subtitle">Блокчейн, в котором криптовалюта изначально была создана</string>
|
||||
<string name="manage_tokens_network_selector_native_title">Основная сеть</string>
|
||||
<string name="manage_tokens_network_selector_non_native_info">Использование ненативных сетей для токенов обеспечивает кросс-блокчейн взаимодействие, позволяя использовать активы в различных децентрализованных приложениях и смарт-контрактах на разных платформах. Однако для безопасного хранения исходного актива часто требуется хранитель или смарт-контракт, что приводит к централизации и риску контрагента.</string>
|
||||
<string name="manage_tokens_network_selector_non_native_subtitle">Не основной или основной блокчейн, на котором размещен токен</string>
|
||||
<string name="manage_tokens_network_selector_non_native_title">Не основные сети</string>
|
||||
<string name="manage_tokens_network_selector_title">Выберите сети</string>
|
||||
|
|
@ -484,6 +492,7 @@
|
|||
<string name="markets_token_details_price_performance">Динамика цены</string>
|
||||
<string name="markets_token_details_repository">Репозиторий</string>
|
||||
<string name="markets_token_details_security_score">Оценка безопасности</string>
|
||||
<string name="markets_token_details_security_score_description">Показатель безопасности токена — это метрика, которая оценивает уровень безопасности блокчейна или токена на основе различных факторов и составляется из перечисленных ниже источников.</string>
|
||||
<string name="markets_token_details_social">Социальные</string>
|
||||
<string name="markets_token_details_total_supply">Общ. предл.</string>
|
||||
<string name="markets_token_details_total_supply_description">Максимальное количество монет или токенов, которое может когда-либо существовать для выбранной криптовалюты</string>
|
||||
|
|
@ -797,12 +806,16 @@
|
|||
<string name="staking_details_unbonding_period_info">Период, который необходимо подождать после запроса на вывод средств из стейкинга, прежде чем токены станут доступны.</string>
|
||||
<string name="staking_details_warmup_period">Период прогрева</string>
|
||||
<string name="staking_details_warmup_period_info">Время, необходимое для начала процесса стейкинга и активации процесса начисления наград</string>
|
||||
<string name="staking_error_no_validators_message">В данный момент нет доступных валидаторов. Попробуйте позже.</string>
|
||||
<string name="staking_error_no_validators_title">Стейкинг недоступен</string>
|
||||
<string name="staking_give_permission_fee_footer">Комиссия сети за одобрение токена будет взиматься за подтверждение того, что именно вы разрешаете использовать ваш токен для стейкинга.</string>
|
||||
<string name="staking_legal">Пользуясь стейкинг сервисом, вы соглашаетесь с %1$s и %2$s</string>
|
||||
<string name="staking_locked">Заблокировано</string>
|
||||
<string name="staking_migrate">Переместить</string>
|
||||
<string name="staking_native">Нативный стейкинг</string>
|
||||
<string name="staking_no_validators_error_message">В данный момент нет доступных активных валидаторов для стейкинга. Пожалуйста, попробуйте позже.</string>
|
||||
<string name="staking_notification_additional_ada_deposit_text">При стейкинге в сети Cardano используется весь ваш баланс. Дополнительные 2 ADA будут зарезервированы и возвращены после отмены стейкинга. Ваши ADA остаются разблокированными во время стейкинга.</string>
|
||||
<string name="staking_notification_additional_ada_deposit_title">Подробности стейкинга ADA</string>
|
||||
<string name="staking_notification_claim_rewards_text">Полученная награда отправится на ваш кошелек и сразу станет доступна для использования</string>
|
||||
<string name="staking_notification_earn_rewards_text">Стейкайте безопасно и начинайте получать ваши награды.</string>
|
||||
<string name="staking_notification_earn_rewards_text_daily">Стейкайте безопасно и начинайте получать ежедневные награды.</string>
|
||||
|
|
@ -816,6 +829,8 @@
|
|||
<string name="staking_notification_earn_rewards_title">Получите награду за стейкинг</string>
|
||||
<string name="staking_notification_low_staked_balance_text">Оставшийся застейканный баланс будет слишком мал для вывода. Вам потребуется застейкать больше средств, чтобы достичь минимальной суммы для вывода.</string>
|
||||
<string name="staking_notification_low_staked_balance_title">Низкий баланс стейкинга</string>
|
||||
<string name="staking_notification_minimum_balance_error_text">Для рестейкинга необходимо %1$s%2$s. Пожалуйста, пополните баланс.</string>
|
||||
<string name="staking_notification_minimum_balance_error_title">Недостаточно %s</string>
|
||||
<string name="staking_notification_network_error_text">Стейкинг временно недоступен из-за проблем в сети. Пожалуйста, попробуйте позже.</string>
|
||||
<string name="staking_notification_new_validator_funds_transfer">Стейкинг в сети %1$s с новым валидатором автоматически переведет ваши текущие застейканные средства на него.</string>
|
||||
<string name="staking_notification_restake_rewards_text">Реинвестируйте свои заработанные награды в вашу застейканную сумму, увеличивая потенциальный доход</string>
|
||||
|
|
@ -885,16 +900,16 @@
|
|||
<string name="swap_give_permission_fee_footer">Комиссия сети за одобрение токена будет взиматься за подтверждение того, что именно вы разрешаете использовать ваш токен для обмена.</string>
|
||||
<string name="swap_promo_text">Обменивайте больше токенов по лучшим курсам прямо в вашем кошельке.</string>
|
||||
<string name="swap_promo_title">Новый провайдер обмена!</string>
|
||||
<string name="swap_story_fifth_subtitle">Надёжная поддержка 24/7, чтобы ваши финансовые операции были быстрыми и безопасными!</string>
|
||||
<string name="swap_story_fifth_subtitle">Чувствуйте уверенность с круглосуточной поддержкой, готовой помочь в любой ситуации!</string>
|
||||
<string name="swap_story_fifth_title">Круглосуточная поддержка</string>
|
||||
<string name="swap_story_first_subtitle">Надёжные провайдеры позволяют легко обменивать активы, обеспечивая полную безопасность в вашем кошельке</string>
|
||||
<string name="swap_story_first_subtitle">Надежные провайдеры в одном месте — обменивайте любые активы легко и быстро прямо в своем кошельке!</string>
|
||||
<string name="swap_story_first_title">Обменивайте с нами</string>
|
||||
<string name="swap_story_forth_subtitle">Высший уровень безопасности и проверенные поставщики гарантируют защиту ваших активов при каждой сделке</string>
|
||||
<string name="swap_story_forth_title">Безопаснее, чем когда-либо</string>
|
||||
<string name="swap_story_second_subtitle">Получайте максимальную выгоду с лучшими курсами от надёжных поставщиков</string>
|
||||
<string name="swap_story_forth_subtitle">Высший уровень безопасности и проверенные партнёры защищают каждую транзакцию</string>
|
||||
<string name="swap_story_forth_title">Полная защита</string>
|
||||
<string name="swap_story_second_subtitle">Автоматически находим самые выгодные предложения среди проверенных провайдеров</string>
|
||||
<string name="swap_story_second_title">Лучшие курсы</string>
|
||||
<string name="swap_story_third_subtitle">Просто и удобно — обмен токенов всего в несколько касаний</string>
|
||||
<string name="swap_story_third_title">Проще, чем когда-либо</string>
|
||||
<string name="swap_story_third_subtitle">Интуитивный обмен в пару касаний — без сложностей и ожидания</string>
|
||||
<string name="swap_story_third_title">Проще простого</string>
|
||||
<string name="swapping_alert_cex_description">В сумму включено: \n• комиссия провайдера сервиса\n• комиссия сети за отправку %s от биржи обратно на адрес пользователя.</string>
|
||||
<string name="swapping_alert_cex_description_with_slippage">В сумму включено: \n• комиссия провайдера сервиса\n• комиссия сети за отправку %1$s от биржи обратно на адрес пользователя \n\nПроскальзывание провайдера составляет до %2$s</string>
|
||||
<string name="swapping_alert_dex_description">В сумму включена комиссия провайдера сервиса.</string>
|
||||
|
|
@ -1071,6 +1086,7 @@
|
|||
<string name="warning_kaspa_unfinished_token_transaction_discard_message">Вы уверены что хотите отменить эту транзакцию? Вы не сможете отправить ее еще раз</string>
|
||||
<string name="warning_kaspa_unfinished_token_transaction_message">Ваша транзакция %1$s %2$s не была завершена. Вы можете попробовать отправить ее еще раз.</string>
|
||||
<string name="warning_kaspa_unfinished_token_transaction_title">У вас есть незавершенная транзакция</string>
|
||||
<string name="warning_last_balance_updated_time">Последнее обновление %s</string>
|
||||
<string name="warning_low_signatures_message">На этой карте осталось всего %s подписей. Вам следует вывести все ваши средства.</string>
|
||||
<string name="warning_low_signatures_title">Малое количество подписей</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Токены на разных сетях могут иметь разные адреса. Пожалуйста, убедитесь при переводе средств, что ваш адрес соответствует сети.</string>
|
||||
|
|
@ -1105,6 +1121,7 @@
|
|||
<string name="warning_solana_rent_fee_message">Сеть Solana взимает арендную плату в размере %1$s каждые 2 дня. Аккаунты, которые не могут позволить себе арендную плату, удаляются из сети. Пополните свой счет более чем на %2$s, чтобы не платить арендную плату.</string>
|
||||
<string name="warning_some_networks_unreachable_message">Свайпните вниз для обновления или попробуйте позже.</string>
|
||||
<string name="warning_some_networks_unreachable_title">Некоторые сети недоступны</string>
|
||||
<string name="warning_some_token_balances_not_updated">Некоторые балансы токенов не удалось обновить</string>
|
||||
<string name="warning_testnet_card_message">Это Testnet карта. Он не может обрабатывать транзакции и используется только в целях тестирования и разработки.</string>
|
||||
<string name="warning_testnet_card_title">Только для целей тестирования</string>
|
||||
<string name="welcome_interrupted_backup_alert_discard">Отказаться</string>
|
||||
|
|
|
|||
|
|
@ -89,6 +89,8 @@
|
|||
<string name="cardano_max_amount_has_token_title">Недостатньо ADA</string>
|
||||
<string name="common_accept">Прийняти</string>
|
||||
<string name="common_access_denied">Доступ заборонено</string>
|
||||
<string name="common_add_to_portfolio">Додати у портфель</string>
|
||||
<string name="common_add_token">Додати токен</string>
|
||||
<string name="common_all">Усе</string>
|
||||
<string name="common_allow">Дозволити</string>
|
||||
<string name="common_analytics">Аналітика</string>
|
||||
|
|
@ -146,6 +148,7 @@
|
|||
<string name="common_generate_addresses">Синхронізувати адреси</string>
|
||||
<string name="common_go_to_provider">Перейти до провайдера</string>
|
||||
<string name="common_go_to_token">Перейти до токену</string>
|
||||
<string name="common_hide">Приховати</string>
|
||||
<string name="common_hour">година</string>
|
||||
<string name="common_import">Імпортувати</string>
|
||||
<string name="common_in_progress">В процесі</string>
|
||||
|
|
@ -317,6 +320,9 @@
|
|||
<string name="express_status_bought">Купив %s</string>
|
||||
<string name="express_status_buying">Купівля %s</string>
|
||||
<string name="express_status_buying_active">Купівля %s...</string>
|
||||
<string name="express_status_hide_button_text">Приховати цю транзакцію</string>
|
||||
<string name="express_status_hide_dialog_text">Після приховування статус транзакції більше не можна буде переглянути. Замість цього ви можете просто провести пальцем, щоб закрити.</string>
|
||||
<string name="express_status_hide_dialog_title">Приховати статус транзакції?</string>
|
||||
<string name="express_token_list_empty_search">Токенів не знайдено. Будь ласка, спробуйте інший запит</string>
|
||||
<string name="express_transaction_id">ID: %s</string>
|
||||
<string name="express_transaction_id_copied">ID транзакції скопійовано</string>
|
||||
|
|
@ -343,6 +349,8 @@
|
|||
<string name="give_permission_unlimited">Необмежено</string>
|
||||
<string name="home_button_order">Купити</string>
|
||||
<string name="home_button_scan">Сканувати</string>
|
||||
<string name="hot_crypto_add_token_subtitle">в %s</string>
|
||||
<string name="hot_crypto_token_network">В мережі %s</string>
|
||||
<string name="information_generated_with_ai">Ця інформація була створена за допомогою ШІ.\nНатисніть тут, якщо знайшли помилку.</string>
|
||||
<string name="initial_message_change_access_code_body">Щоб змінити код доступу, прикладіть картку або кільце, як показано вище, і не прибирайте її до закінчення операції</string>
|
||||
<string name="initial_message_change_passcode_body">Щоб змінити пароль, прикладіть картку, як показано вище, і не прибирайте її до закінчення операції</string>
|
||||
|
|
@ -798,12 +806,16 @@
|
|||
<string name="staking_details_unbonding_period_info">Період, який ви повинні чекати після запиту на виведення коштів зі стейкінгу, перш ніж токени стануть доступними.</string>
|
||||
<string name="staking_details_warmup_period">Період блокування</string>
|
||||
<string name="staking_details_warmup_period_info">Відведений час для активації участі в стейкінгу.</string>
|
||||
<string name="staking_error_no_validators_message">Наразі немає вільних валідаторів. Повторіть спробу пізніше.</string>
|
||||
<string name="staking_error_no_validators_title">Стейкінг недоступний</string>
|
||||
<string name="staking_give_permission_fee_footer">Комісія за схвалення токену, щоб верифікувати, що саме ви дозволяєте використання токена для стейкінгу.</string>
|
||||
<string name="staking_legal">Використовуючи функцію стейкінгу, ви погоджуєтесь з %1$s та %2$s</string>
|
||||
<string name="staking_locked">Заблоковано</string>
|
||||
<string name="staking_migrate">Перемістити</string>
|
||||
<string name="staking_native">Нативний стейкінг</string>
|
||||
<string name="staking_no_validators_error_message">На даний момент немає доступних активних валідаторів для стейкінгу. Будь ласка, спробуйте пізніше.</string>
|
||||
<string name="staking_notification_additional_ada_deposit_text">Під час стейкінгу в мережі Cardano використовується весь ваш баланс. Додаткові 2 ADA будуть зарезервовані та повернуті після скасування стейкінгу. Ваша ADA залишається розблокованою під час стейкінгу.</string>
|
||||
<string name="staking_notification_additional_ada_deposit_title">Деталі стейкінгу ADA</string>
|
||||
<string name="staking_notification_claim_rewards_text">Зароблені винагороди будуть надіслані на ваш гаманець і доступні для використання відразу</string>
|
||||
<string name="staking_notification_earn_rewards_text">Стейкайте безпечно та почніть отримувати ваші винагороди</string>
|
||||
<string name="staking_notification_earn_rewards_text_daily">Стейкайте безпечно та почніть отримувати винагороди щоденно</string>
|
||||
|
|
@ -817,6 +829,8 @@
|
|||
<string name="staking_notification_earn_rewards_title">Отримуйте винагороду за стейкінг</string>
|
||||
<string name="staking_notification_low_staked_balance_text">Ваш баланс стейкінгу, що залишився, буде занадто низьким, щоб вивести його зі стейкінгу. Вам потрібно буде застейкати більше, щоб досягти мінімальної суми для виводу.</string>
|
||||
<string name="staking_notification_low_staked_balance_title">Низький баланс стейкінгу</string>
|
||||
<string name="staking_notification_minimum_balance_error_text">Мінімум %1$s %2$s потрібно для рестейкінгу. Будь ласка, поповніть баланс.</string>
|
||||
<string name="staking_notification_minimum_balance_error_title">Недостатньо %s</string>
|
||||
<string name="staking_notification_network_error_text">Стейкінг тимчасово недоступний через проблеми в мережі. Будь ласка, спробуйте пізніше.</string>
|
||||
<string name="staking_notification_new_validator_funds_transfer">Стейкінг в мережі %1$s з новим валідатором автоматично переведе всі раніше застейкані кошти до цього валідатора</string>
|
||||
<string name="staking_notification_restake_rewards_text">Реінвестуйте зароблені винагороди у суму стейкінгу, щоб збільшити потенційний прибуток.</string>
|
||||
|
|
@ -887,6 +901,16 @@
|
|||
<string name="swap_give_permission_fee_footer">Мережа стягує комісію за схвалення токену за підтвердження, що саме ви дозволяєте використовувати ваш токен для обміну.</string>
|
||||
<string name="swap_promo_text">Обмінюйте більше токенів за вигіднішим курсом прямо у своєму гаманці.</string>
|
||||
<string name="swap_promo_title">З\'явився новий провайдер обмінів!</string>
|
||||
<string name="swap_story_fifth_subtitle">Надійна підтримка 24/7, щоб ваші фінансові операції були швидкими та надійними!</string>
|
||||
<string name="swap_story_fifth_title">Цілодобова підтримка</string>
|
||||
<string name="swap_story_first_subtitle">Надійні провайдери дозволяють легко обмінювати активи, забезпечуючи повну безпеку у вашому гаманці</string>
|
||||
<string name="swap_story_first_title">Обмінюйте з нами</string>
|
||||
<string name="swap_story_forth_subtitle">Найвищий рівень безпеки та перевірені провайдери гарантують захист ваших активів при кожному обміні.</string>
|
||||
<string name="swap_story_forth_title">Безпечніше, ніж будь-коли</string>
|
||||
<string name="swap_story_second_subtitle">Отримуйте максимальну вигоду з кращими курсами від надійних провайдерів</string>
|
||||
<string name="swap_story_second_title">Найкращі тарифи</string>
|
||||
<string name="swap_story_third_subtitle">Просто та зручно — обмін токенів в декілька дотиків</string>
|
||||
<string name="swap_story_third_title">Легше, ніж будь-коли</string>
|
||||
<string name="swapping_alert_cex_description">Сума включає: \n• комісію постачальника послуг\n• комісію мережі за відправлення %s з біржі назад на адресу користувача.</string>
|
||||
<string name="swapping_alert_cex_description_with_slippage">У суму входить:\n- комісія провайдера\n- мережева комісія за відправку %1$s з біржі назад на адресу користувача. \n\nПроскакування провайдера становить до %2$s</string>
|
||||
<string name="swapping_alert_dex_description">Сума включає комісію постачальника послуг.</string>
|
||||
|
|
@ -1063,6 +1087,7 @@
|
|||
<string name="warning_kaspa_unfinished_token_transaction_discard_message">Ви впевнені, що хочете скасувати цю транзакцію? Ви не зможете відправити її ще раз</string>
|
||||
<string name="warning_kaspa_unfinished_token_transaction_message">Ваша транзакція %1$s %2$s не була завершена. Ви можете спробувати відправити її ще раз.</string>
|
||||
<string name="warning_kaspa_unfinished_token_transaction_title">У вас є незавершена транзакція</string>
|
||||
<string name="warning_last_balance_updated_time">Останнє оновлення було %s</string>
|
||||
<string name="warning_low_signatures_message">На цій картці залишається лише %s підписів. Ви повинні вивести всі свої кошти.</string>
|
||||
<string name="warning_low_signatures_title">Низька кількість підписів</string>
|
||||
<string name="warning_manage_tokens_legacy_derivation_message">Токени в різних мережах можуть мати різні адреси. Переконайтеся, що ваша адреса відповідає мережі, коли переказуєте кошти.</string>
|
||||
|
|
@ -1097,6 +1122,7 @@
|
|||
<string name="warning_solana_rent_fee_message">Мережа Solana стягує орендну плату у розмірі %1$s кожні 2 дні. Акаунти, які не можуть дозволити собі орендну плату, видаляються з мережі. Поповніть свій рахунок на суму понад %2$s, щоб не платити орендну плату.</string>
|
||||
<string name="warning_some_networks_unreachable_message">Проведіть пальцем вниз для оновлення або спробуйте пізніше.</string>
|
||||
<string name="warning_some_networks_unreachable_title">Деякі мережі недоступні</string>
|
||||
<string name="warning_some_token_balances_not_updated">Деякі баланси токенів не вдалося оновити</string>
|
||||
<string name="warning_testnet_card_message">Це картка Testnet. Вона не може обробляти транзакції і повинна використовуватися лише для тестування та розробки.</string>
|
||||
<string name="warning_testnet_card_title">Лише для цілей тестування</string>
|
||||
<string name="welcome_interrupted_backup_alert_discard">Відмовитися</string>
|
||||
|
|
|
|||
|
|
@ -881,16 +881,16 @@
|
|||
<string name="swap_give_permission_fee_footer">The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap.</string>
|
||||
<string name="swap_promo_text">Exchange more tokens at better rates directly in your wallet.</string>
|
||||
<string name="swap_promo_title">New Swap Provider Available!</string>
|
||||
<string name="swap_story_fifth_subtitle">Feel confident with constant support, ensuring your transactions go smoothly anytime</string>
|
||||
<string name="swap_story_fifth_title">Around-the-Clock Assistance</string>
|
||||
<string name="swap_story_first_subtitle">Trusted exchange providers let you swap assets effortlessly, keeping everything safe in your wallet</string>
|
||||
<string name="swap_story_first_title">Exchange With Us</string>
|
||||
<string name="swap_story_forth_subtitle">Top-level security and verified providers ensure your assets are protected during every swap</string>
|
||||
<string name="swap_story_forth_title">Safer Then Ever</string>
|
||||
<string name="swap_story_fifth_subtitle">Feel confident with round-the-clock support to help with any issues</string>
|
||||
<string name="swap_story_fifth_title">Always Here</string>
|
||||
<string name="swap_story_first_subtitle">Multiple trusted providers in one place—swap any asset effortlessly in your wallet</string>
|
||||
<string name="swap_story_first_title">Swap With Us</string>
|
||||
<string name="swap_story_forth_subtitle">No fumbles, no turnovers, no blind spots—your transaction is always protected</string>
|
||||
<string name="swap_story_forth_title">Impenetrable Defense</string>
|
||||
<string name="swap_story_second_subtitle">Maximize your value with rates sourced from a wide network of trusted providers, always choosing the best one</string>
|
||||
<string name="swap_story_second_title">Best Rates</string>
|
||||
<string name="swap_story_second_title">Unbeatable Rates</string>
|
||||
<string name="swap_story_third_subtitle">Hassle-free and intuitive, allowing you to swap tokens in just a few taps</string>
|
||||
<string name="swap_story_third_title">Easier Than Ever</string>
|
||||
<string name="swap_story_third_title">Simply Convenient</string>
|
||||
<string name="swapping_alert_cex_description">The amount includes:\n• service provider\'s fee\n• network fee for sending %s from the exchange back to the user\'s address.</string>
|
||||
<string name="swapping_alert_cex_description_with_slippage">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</string>
|
||||
<string name="swapping_alert_dex_description">The amount includes the service provider\'s fee.</string>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ object TangemColorPalette {
|
|||
// region Base
|
||||
val Black = Color(0xFF000000)
|
||||
val White = Color(0xFFFFFFFF)
|
||||
val SoftWhite = Color(0xFFF1F1F1)
|
||||
// endregion Base
|
||||
|
||||
// region Dark
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ dependencies {
|
|||
implementation(deps.androidx.datastore)
|
||||
|
||||
implementation(deps.jodatime)
|
||||
implementation(deps.timber)
|
||||
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
|
|
|
|||
|
|
@ -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<StoryContent?> = 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<Boolean> {
|
||||
return appPreferencesStore.get(SHOULD_SHOW_SWAP_STORIES_KEY, true)
|
||||
override fun isReadyToShowStories(storyId: String): Flow<Boolean> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Throwable, StoryContent> = Either.catch {
|
||||
promoRepository.getStoryById(id)
|
||||
operator fun invoke(id: String): Flow<Either<Throwable, StoryContent?>> = promoRepository.getStoryById(id)
|
||||
.map<StoryContent?, Either<Throwable, StoryContent?>> { it.right() }
|
||||
.catch { emit(it.left()) }
|
||||
.onEmpty { emit(null.right()) }
|
||||
|
||||
suspend fun invokeSync(id: String): Either<Throwable, StoryContent?> = Either.catch {
|
||||
promoRepository.getStoryByIdSync(id)
|
||||
}
|
||||
}
|
||||
|
|
@ -16,12 +16,14 @@ interface PromoRepository {
|
|||
// endregion
|
||||
|
||||
// region Stories
|
||||
suspend fun getStoryById(id: String): StoryContent
|
||||
fun getStoryById(id: String): Flow<StoryContent?>
|
||||
|
||||
fun isReadyToShowSwapStories(): Flow<Boolean>
|
||||
suspend fun getStoryByIdSync(id: String): StoryContent?
|
||||
|
||||
suspend fun isReadyToShowSwapStoriesSync(): Boolean
|
||||
fun isReadyToShowStories(storyId: String): Flow<Boolean>
|
||||
|
||||
suspend fun setNeverToShowSwapStories()
|
||||
suspend fun isReadyToShowStoriesSync(storyId: String): Boolean
|
||||
|
||||
suspend fun setNeverToShowStories(storyId: String)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -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<Boolean> = promoRepository.isReadyToShowStories(storyId)
|
||||
suspend fun invokeSync(storyId: String): Boolean = promoRepository.isReadyToShowStoriesSync(storyId)
|
||||
|
||||
suspend fun neverToShow(storyId: String) = promoRepository.setNeverToShowStories(storyId)
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.domain.promo
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class ShouldShowSwapStoriesUseCase(private val promoRepository: PromoRepository) {
|
||||
operator fun invoke(): Flow<Boolean> = promoRepository.isReadyToShowSwapStories()
|
||||
suspend fun invokeSync(): Boolean = promoRepository.isReadyToShowSwapStoriesSync()
|
||||
|
||||
suspend fun neverToShow() = promoRepository.setNeverToShowSwapStories()
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<SwapStoriesUM> 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,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<WalletSubscriber> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<WalletSubscriber> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue