From f79fbcb530c2242aef2b9dd7f60932f9296688d4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 24 Apr 2025 19:25:15 +0500 Subject: [PATCH 01/21] Updated on 2026-08-14 --- app/src/main/AndroidManifest.xml | 11 +++++++++++ .../common/pushes/TangemPushNotificationService.kt | 14 +++++++++----- .../core/deeplink/global/ReferralDeepLink.kt | 13 +++++++++++++ .../deeplink/WalletDeepLinksHandler.kt | 14 ++++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/ReferralDeepLink.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b9e46866c1..21808cc1b9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -142,6 +142,17 @@ android:scheme="tangem" /> + + + + + + + + + diff --git a/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt b/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt index 9bdca56b66..c8dc6dda61 100644 --- a/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt +++ b/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt @@ -5,18 +5,19 @@ import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.content.Intent +import android.content.Intent.ACTION_VIEW import android.graphics.Bitmap import android.net.Uri import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toBitmap +import androidx.core.net.toUri import coil.executeBlocking import coil.request.ImageRequest import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import com.tangem.domain.common.LogConfig -import com.tangem.tap.MainActivity import com.tangem.tap.common.images.createCoilImageLoader import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler import com.tangem.wallet.R @@ -36,10 +37,11 @@ internal class TangemPushNotificationService : FirebaseMessagingService() { val notification = message.notification ?: return val channelId = notification.channelId ?: TANGEM_CHANNEL_ID - // TODO refactoring: [REDACTED_JIRA] - val intent = Intent(applicationContext, MainActivity::class.java) - intent.putExtra(OnPushClickedIntentHandler.OPENED_FROM_GCM_PUSH, true) - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + val intent = Intent(ACTION_VIEW).apply { + data = message.data[DEEPLINK_KEY]?.toUri() + putExtra(OnPushClickedIntentHandler.OPENED_FROM_GCM_PUSH, true) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + } val pendingIntent = PendingIntent.getActivity( /* context = */ this, /* requestCode = */ PUSH_NOTIFICATION_REQUEST_CODE, @@ -101,5 +103,7 @@ internal class TangemPushNotificationService : FirebaseMessagingService() { private companion object { const val TANGEM_CHANNEL_ID = "Tangem General" // General channel for notifications const val PUSH_NOTIFICATION_REQUEST_CODE = 123 + + const val DEEPLINK_KEY = "deeplink" } } \ No newline at end of file diff --git a/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/ReferralDeepLink.kt b/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/ReferralDeepLink.kt new file mode 100644 index 0000000000..763a6d80f7 --- /dev/null +++ b/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/ReferralDeepLink.kt @@ -0,0 +1,13 @@ +package com.tangem.core.deeplink.global + +import com.tangem.core.deeplink.DeepLink + +class ReferralDeepLink( + val onReceive: () -> Unit, +) : DeepLink(shouldHandleDelayed = true) { + override val uri: String = "tangem://referral" + + override fun onReceive(params: Map) { + onReceive() + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt index a0b28f06fd..75075d1d24 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt @@ -6,6 +6,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.deeplink.DeepLink import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.core.deeplink.global.BuyCurrencyDeepLink +import com.tangem.core.deeplink.global.ReferralDeepLink import com.tangem.core.deeplink.global.SellCurrencyDeepLink import com.tangem.domain.tokens.GetCryptoCurrencyUseCase import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent @@ -54,6 +55,7 @@ internal class WalletDeepLinksHandler @Inject constructor( ) return buildList { + addReferralDeepLink(userWallet.walletId) add(sellCurrencyDeepLink) if (onrampFeatureToggles.isFeatureEnabled || !userWallet.isMultiCurrency) { add( @@ -95,4 +97,16 @@ internal class WalletDeepLinksHandler @Inject constructor( analyticsEventHandler.send(TokenScreenAnalyticsEvent.Bought(cryptoCurrency.symbol)) } } + + private fun MutableList.addReferralDeepLink(userWalletId: UserWalletId) { + add( + ReferralDeepLink( + onReceive = { + router.push( + AppRoute.ReferralProgram(userWalletId = userWalletId), + ) + }, + ), + ) + } } \ No newline at end of file From 7bdbd18cadf90b94937aec7a98a66d093f0ceec7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 25 Apr 2025 16:42:18 +0500 Subject: [PATCH 02/21] Updated on 2026-08-14 --- .../tangem/tap/di/domain/PromoDomainModule.kt | 8 ++--- .../local/preferences/PreferencesKeys.kt | 4 +++ .../data/promo/DefaultPromoRepository.kt | 29 ++++++++++++++----- .../tangem/domain/promo/models/PromoBanner.kt | 4 +++ .../tangem/domain/promo/PromoRepository.kt | 10 ++++--- .../promo/ShouldShowPromoTokenUseCase.kt | 11 +++++++ .../promo/ShouldShowPromoWalletUseCase.kt | 14 +++++++++ .../promo/ShouldShowSwapPromoTokenUseCase.kt | 10 ------- .../promo/ShouldShowSwapPromoWalletUseCase.kt | 10 ------- domain/tokens/models/build.gradle.kts | 1 + .../model/warnings/CryptoCurrencyWarning.kt | 2 ++ .../model/TokenDetailsClickIntents.kt | 5 ++-- .../tokendetails/model/TokenDetailsModel.kt | 13 +++++---- .../TokenDetailsNotificationConverter.kt | 6 ++-- .../intents/WalletWarningsClickIntents.kt | 11 +++---- 15 files changed, 86 insertions(+), 52 deletions(-) create mode 100644 domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoTokenUseCase.kt create mode 100644 domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt delete mode 100644 domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapPromoTokenUseCase.kt delete mode 100644 domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapPromoWalletUseCase.kt 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 9e969c71de..8064273ab8 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 @@ -15,14 +15,14 @@ internal object PromoDomainModule { @Singleton fun provideShouldShowSwapPromoWalletUseCase( promoSettingsRepository: PromoRepository, - ): ShouldShowSwapPromoWalletUseCase { - return ShouldShowSwapPromoWalletUseCase(promoSettingsRepository) + ): ShouldShowPromoWalletUseCase { + return ShouldShowPromoWalletUseCase(promoSettingsRepository) } @Provides @Singleton - fun provideShouldShowSwapPromoTokenUseCase(promoRepository: PromoRepository): ShouldShowSwapPromoTokenUseCase { - return ShouldShowSwapPromoTokenUseCase(promoRepository) + fun provideShouldShowSwapPromoTokenUseCase(promoRepository: PromoRepository): ShouldShowPromoTokenUseCase { + return ShouldShowPromoTokenUseCase(promoRepository) } @Provides 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 50275788dd..e1cc610e17 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 @@ -123,8 +123,12 @@ object PreferencesKeys { val WALLETS_NFT_ENABLED_STATES_KEY by lazy { stringPreferencesKey(name = "walletsNftEnabledStates") } + // region Promo fun getShouldShowStoriesKey(storyId: String) = booleanPreferencesKey("shouldShowStories_$storyId") + fun getShouldShowPromoKey(promoId: String) = booleanPreferencesKey("shouldShowPromo_$promoId") + // endregion + // region Permission fun getShouldShowPermission(permission: String) = booleanPreferencesKey("shouldShowPushPermission_$permission") 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 5b14b75e9a..2c409f90fd 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,13 +4,16 @@ 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 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.PromoId import com.tangem.domain.promo.models.StoryContent +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf @@ -27,20 +30,30 @@ internal class DefaultPromoRepository( private val storyContentConverter = StoryContentResponseConverter() - override fun isReadyToShowWalletSwapPromo(): Flow { - return flowOf(false) // Use it on new promo action + override fun isReadyToShowWalletPromo(userWalletId: UserWalletId, promoId: PromoId): Flow { + return appPreferencesStore.get( + key = PreferencesKeys.getShouldShowPromoKey(promoId = promoId.name), + default = true, + ) } - override fun isReadyToShowTokenSwapPromo(): Flow { - return flowOf(false) // Use it on new promo action + override fun isReadyToShowTokenPromo(promoId: PromoId): Flow { + return if (promoId == PromoId.Referral) { + flowOf(false) + } else { + appPreferencesStore.get( + PreferencesKeys.getShouldShowPromoKey(promoId = promoId.name), + default = false, + ) + } } - override suspend fun setNeverToShowWalletSwapPromo() { - // Use it on new promo action + override suspend fun setNeverToShowWalletPromo(promoId: PromoId) { + appPreferencesStore.store(PreferencesKeys.getShouldShowPromoKey(promoId = promoId.name), false) } - override suspend fun setNeverToShowTokenSwapPromo() { - // Use it on new promo action + override suspend fun setNeverToShowTokenPromo(promoId: PromoId) { + appPreferencesStore.store(PreferencesKeys.getShouldShowPromoKey(promoId = promoId.name), false) } override fun getStoryById(id: String): Flow = isReadyToShowStories(id).mapLatest { diff --git a/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt b/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt index 42ecbd01d8..81f592f146 100644 --- a/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt +++ b/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt @@ -23,4 +23,8 @@ data class PromoBanner( private companion object { const val ACTIVE_STATUS = "active" } +} + +enum class PromoId { + Referral, } \ 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 4db7b9bf87..88682deae2 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 @@ -1,18 +1,20 @@ package com.tangem.domain.promo +import com.tangem.domain.promo.models.PromoId import com.tangem.domain.promo.models.StoryContent +import com.tangem.domain.wallets.models.UserWalletId import kotlinx.coroutines.flow.Flow interface PromoRepository { // region Promo - fun isReadyToShowWalletSwapPromo(): Flow + fun isReadyToShowWalletPromo(userWalletId: UserWalletId, promoId: PromoId): Flow - fun isReadyToShowTokenSwapPromo(): Flow + fun isReadyToShowTokenPromo(promoId: PromoId): Flow - suspend fun setNeverToShowWalletSwapPromo() + suspend fun setNeverToShowWalletPromo(promoId: PromoId) - suspend fun setNeverToShowTokenSwapPromo() + suspend fun setNeverToShowTokenPromo(promoId: PromoId) // endregion // region Stories diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoTokenUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoTokenUseCase.kt new file mode 100644 index 0000000000..e6ad0e7580 --- /dev/null +++ b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoTokenUseCase.kt @@ -0,0 +1,11 @@ +package com.tangem.domain.promo + +import com.tangem.domain.promo.models.PromoId +import kotlinx.coroutines.flow.Flow + +class ShouldShowPromoTokenUseCase(private val promoRepository: PromoRepository) { + + operator fun invoke(promoId: PromoId): Flow = promoRepository.isReadyToShowTokenPromo(promoId) + + suspend fun neverToShow(promoId: PromoId) = promoRepository.setNeverToShowTokenPromo(promoId) +} \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt new file mode 100644 index 0000000000..2a3a88329b --- /dev/null +++ b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt @@ -0,0 +1,14 @@ +package com.tangem.domain.promo + +import com.tangem.domain.promo.models.PromoId +import com.tangem.domain.wallets.models.UserWalletId +import kotlinx.coroutines.flow.Flow + +class ShouldShowPromoWalletUseCase(private val promoRepository: PromoRepository) { + + operator fun invoke(userWalletId: UserWalletId, promoId: PromoId): Flow { + return promoRepository.isReadyToShowWalletPromo(userWalletId, promoId) + } + + suspend fun neverToShow(promoId: PromoId) = promoRepository.setNeverToShowWalletPromo(promoId) +} \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapPromoTokenUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapPromoTokenUseCase.kt deleted file mode 100644 index 9bd3a02d7f..0000000000 --- a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapPromoTokenUseCase.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.domain.promo - -import kotlinx.coroutines.flow.Flow - -class ShouldShowSwapPromoTokenUseCase(private val promoRepository: PromoRepository) { - - operator fun invoke(): Flow = promoRepository.isReadyToShowTokenSwapPromo() - - suspend fun neverToShow() = promoRepository.setNeverToShowTokenSwapPromo() -} \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapPromoWalletUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapPromoWalletUseCase.kt deleted file mode 100644 index 5ed815ec9c..0000000000 --- a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowSwapPromoWalletUseCase.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.domain.promo - -import kotlinx.coroutines.flow.Flow - -class ShouldShowSwapPromoWalletUseCase(private val promoRepository: PromoRepository) { - - operator fun invoke(): Flow = promoRepository.isReadyToShowWalletSwapPromo() - - suspend fun neverToShow() = promoRepository.setNeverToShowWalletSwapPromo() -} \ No newline at end of file diff --git a/domain/tokens/models/build.gradle.kts b/domain/tokens/models/build.gradle.kts index 9a926341a8..f618dc0f3f 100644 --- a/domain/tokens/models/build.gradle.kts +++ b/domain/tokens/models/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { implementation(projects.domain.models) implementation(projects.domain.txhistory.models) implementation(projects.domain.staking.models) + implementation(projects.domain.promo.models) /** Other dependencies */ implementation(deps.kotlin.serialization) diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt index 623fbe5c1b..36cd8062dc 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt @@ -1,5 +1,6 @@ package com.tangem.domain.tokens.model.warnings +import com.tangem.domain.promo.models.PromoId import com.tangem.domain.tokens.model.CryptoCurrency import org.joda.time.DateTime import java.math.BigDecimal @@ -42,6 +43,7 @@ sealed class CryptoCurrencyWarning { data class Rent(val rent: BigDecimal, val exemptionAmount: BigDecimal) : CryptoCurrencyWarning() data class SwapPromo( + val promoId: PromoId, val startDateTime: DateTime, val endDateTime: DateTime, ) : CryptoCurrencyWarning() diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt index eeaaa1174a..c24e2e7736 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsClickIntents.kt @@ -2,6 +2,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.model import com.tangem.common.ui.bottomsheet.receive.AddressModel import com.tangem.core.ui.extensions.TextReference +import com.tangem.domain.promo.models.PromoId import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig @@ -49,9 +50,9 @@ interface TokenDetailsClickIntents { fun onGoToProviderClick(url: String) - fun onSwapPromoDismiss() + fun onSwapPromoDismiss(promoId: PromoId) - fun onSwapPromoClick() + fun onSwapPromoClick(promoId: PromoId) fun onGenerateExtendedKey() diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index 6ca825bee9..d76fff8838 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -35,7 +35,8 @@ import com.tangem.domain.card.NetworkHasDerivationUseCase import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.onramp.model.OnrampSource -import com.tangem.domain.promo.ShouldShowSwapPromoTokenUseCase +import com.tangem.domain.promo.ShouldShowPromoTokenUseCase +import com.tangem.domain.promo.models.PromoId import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.staking.GetStakingAvailabilityUseCase import com.tangem.domain.staking.GetStakingEntryInfoUseCase @@ -101,7 +102,7 @@ internal class TokenDetailsModel @Inject constructor( private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase, private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase, - private val shouldShowSwapPromoTokenUseCase: ShouldShowSwapPromoTokenUseCase, + private val shouldShowPromoTokenUseCase: ShouldShowPromoTokenUseCase, private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase, private val getExtendedPublicKeyForCurrencyUseCase: GetExtendedPublicKeyForCurrencyUseCase, private val getStakingEntryInfoUseCase: GetStakingEntryInfoUseCase, @@ -811,9 +812,9 @@ internal class TokenDetailsModel @Inject constructor( router.openUrl(url) } - override fun onSwapPromoDismiss() { + override fun onSwapPromoDismiss(promoId: PromoId) { modelScope.launch(dispatchers.main) { - shouldShowSwapPromoTokenUseCase.neverToShow() + shouldShowPromoTokenUseCase.neverToShow(promoId) analyticsEventsHandler.send( TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( source = AnalyticsParam.ScreensSources.Token, @@ -824,9 +825,9 @@ internal class TokenDetailsModel @Inject constructor( } } - override fun onSwapPromoClick() { + override fun onSwapPromoClick(promoId: PromoId) { modelScope.launch(dispatchers.main) { - shouldShowSwapPromoTokenUseCase.neverToShow() + shouldShowPromoTokenUseCase.neverToShow(promoId) analyticsEventsHandler.send( TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( source = AnalyticsParam.ScreensSources.Token, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt index 50b4710dd8..1413bff703 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt @@ -10,10 +10,10 @@ import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.domain.tokens.model.warnings.HederaWarnings import com.tangem.domain.tokens.model.warnings.KaspaWarnings +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification.* -import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R import com.tangem.utils.converter.Converter import com.tangem.utils.extensions.removeBy @@ -98,8 +98,8 @@ internal class TokenDetailsNotificationConverter( is CryptoCurrencyWarning.SwapPromo -> SwapPromo( startDateTime = warning.startDateTime, endDateTime = warning.endDateTime, - onSwapClick = clickIntents::onSwapPromoClick, - onCloseClick = clickIntents::onSwapPromoDismiss, + onSwapClick = { clickIntents.onSwapPromoClick(warning.promoId) }, + onCloseClick = { clickIntents.onSwapPromoDismiss(warning.promoId) }, ) is CryptoCurrencyWarning.BeaconChainShutdown -> NetworkShutdown( title = resourceReference(R.string.warning_beacon_chain_retirement_title), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 419db01ebc..2688e82b36 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -13,7 +13,8 @@ import com.tangem.domain.feedback.GetCardInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher -import com.tangem.domain.promo.ShouldShowSwapPromoWalletUseCase +import com.tangem.domain.promo.ShouldShowPromoWalletUseCase +import com.tangem.domain.promo.models.PromoId import com.tangem.domain.redux.LegacyAction import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.settings.NeverToSuggestRateAppUseCase @@ -67,7 +68,7 @@ internal interface WalletWarningsClickIntents { fun onCloseRateAppWarningClick() - fun onCloseSwapPromoClick() + fun onClosePromoClick(promoId: PromoId) fun onSupportClick() @@ -98,7 +99,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( private val analyticsEventHandler: AnalyticsEventHandler, private val reduxStateHolder: ReduxStateHolder, private val dispatchers: CoroutineDispatcherProvider, - private val shouldShowSwapPromoWalletUseCase: ShouldShowSwapPromoWalletUseCase, + private val shouldShowPromoWalletUseCase: ShouldShowPromoWalletUseCase, private val getCardInfoUseCase: GetCardInfoUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val seedPhraseNotificationUseCase: SeedPhraseNotificationUseCase, @@ -268,7 +269,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( } } - override fun onCloseSwapPromoClick() { + override fun onClosePromoClick(promoId: PromoId) { analyticsEventHandler.send( TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( source = AnalyticsParam.ScreensSources.Main, @@ -277,7 +278,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( ), ) modelScope.launch(dispatchers.main) { - shouldShowSwapPromoWalletUseCase.neverToShow() + shouldShowPromoWalletUseCase.neverToShow(promoId) } } From 13c3b6d4e286a296b67d4577232dc58f215af7ec Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 25 Apr 2025 12:29:47 +0300 Subject: [PATCH 03/21] Updated on 2026-08-14 --- .../wallet/child/wallet/model/WalletModel.kt | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 418cb39368..23569c3eee 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -15,6 +15,7 @@ import com.tangem.domain.nft.FetchNFTCollectionsUseCase import com.tangem.domain.settings.* import com.tangem.domain.tokens.FetchCurrencyStatusUseCase import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase @@ -356,9 +357,7 @@ internal class WalletModel @Inject constructor( coroutineScope = modelScope, ) - if (action.selectedWallet.scanResponse.cardTypesResolver.isSingleWallet()) { - fetchCurrencyStatusUseCase(userWalletId = action.selectedWallet.walletId) - } + fetchIfSingleWallet(action.selectedWallet) if (action.wallets.size > 1 && isWalletsScrollPreviewEnabled()) { withContext(dispatchers.io) { delay(timeMillis = 1_800) } @@ -385,6 +384,8 @@ internal class WalletModel @Inject constructor( coroutineScope = modelScope, ) + fetchIfSingleWallet(userWallet = action.selectedWallet) + stateHolder.update( ReinitializeWalletTransformer( prevWalletId = action.prevWalletId, @@ -402,12 +403,7 @@ internal class WalletModel @Inject constructor( coroutineScope = modelScope, ) - if (action.selectedWallet.scanResponse.cardTypesResolver.isSingleWallet()) { - modelScope.launch { - fetchCurrencyStatusUseCase(userWalletId = action.selectedWallet.walletId) - .onLeft { Timber.e(it.toString()) } - } - } + fetchIfSingleWallet(userWallet = action.selectedWallet) stateHolder.update( AddWalletTransformer( @@ -506,6 +502,15 @@ internal class WalletModel @Inject constructor( } } + private fun fetchIfSingleWallet(userWallet: UserWallet) { + if (userWallet.scanResponse.cardTypesResolver.isSingleWallet()) { + modelScope.launch { + fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId) + .onLeft { Timber.e(it.toString()) } + } + } + } + inner class AskBiometryModelCallbacks : AskBiometryComponent.ModelCallbacks { override fun onAllowed() { analyticsEventsHandler.send(MainScreenAnalyticsEvent.EnableBiometrics(AnalyticsParam.OnOffState.On)) From 2d2d1579439f659840e844e4195b594d8df8e0f3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 25 Apr 2025 16:56:19 +0500 Subject: [PATCH 04/21] Updated on 2026-08-14 --- core/res/src/main/res/values/strings.xml | 3 ++ .../components/notifications/Notification.kt | 7 +++- .../main/res/drawable/img_referral_promo.webp | Bin 0 -> 23568 bytes data/promo/build.gradle.kts | 1 + .../data/promo/DefaultPromoRepository.kt | 11 ++++++- .../tangem/data/promo/di/PromoDataModule.kt | 3 ++ .../referral/data/ReferralRepositoryImpl.kt | 4 +++ .../referral/domain/ReferralRepository.kt | 3 ++ .../intents/WalletWarningsClickIntents.kt | 30 +++++++++++++++--- .../analytics/WalletScreenAnalyticsEvent.kt | 6 ++++ .../utils/WalletWarningsAnalyticsSender.kt | 1 + .../domain/GetMultiWalletWarningsFactory.kt | 22 ++++++++++++- .../wallet/state/model/WalletNotification.kt | 16 ++++++++++ .../components/common/WalletNotifications.kt | 6 ++++ 14 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 core/ui/src/main/res/drawable/img_referral_promo.webp diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index a23e1b705f..48b2496729 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -520,6 +520,9 @@ NFT collections Unable to load the data Choose network + Join Now + Share your code - earn 5 USDT per sale. Your friend gets 10% OFF. + Get REWARDS for every friend! Last sale price Rarity label Rarity rank diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt index 7bd5322685..5d1f6b11fd 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt @@ -25,6 +25,8 @@ import androidx.compose.ui.semantics.Role import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import com.tangem.core.ui.R import com.tangem.core.ui.components.* import com.tangem.core.ui.components.buttons.common.TangemButtonSize @@ -55,6 +57,7 @@ fun Notification( subtitleColor: Color = TangemTheme.colors.text.tertiary, containerColor: Color? = null, iconTint: Color? = null, + iconSize: Dp = 20.dp, isEnabled: Boolean = true, ) { NotificationBaseContainer( @@ -68,6 +71,7 @@ fun Notification( MainContent( iconResId = config.iconResId, iconTint = iconTint, + iconSize = iconSize, title = config.title, subtitle = config.subtitle, subtitleColor = subtitleColor, @@ -127,6 +131,7 @@ internal fun NotificationBaseContainer( private fun MainContent( iconResId: Int, iconTint: Color?, + iconSize: Dp, title: TextReference?, subtitle: TextReference, subtitleColor: Color, @@ -137,7 +142,7 @@ private fun MainContent( iconResId = iconResId, tint = iconTint, modifier = Modifier - .size(size = TangemTheme.dimens.size20) + .size(size = iconSize) .align(alignment = Alignment.CenterVertically), ) diff --git a/core/ui/src/main/res/drawable/img_referral_promo.webp b/core/ui/src/main/res/drawable/img_referral_promo.webp new file mode 100644 index 0000000000000000000000000000000000000000..25a0af2e67b7940ed70ca4a32611a73c45d42ca3 GIT binary patch literal 23568 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 bysffr90MDRbFQE*Z?!>S2`~Ti3_t(?*7Kcz literal 0 HcmV?d00001 diff --git a/data/promo/build.gradle.kts b/data/promo/build.gradle.kts index e2dd74f43c..7573a1e454 100644 --- a/data/promo/build.gradle.kts +++ b/data/promo/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { implementation(projects.domain.promo) implementation(projects.domain.promo.models) implementation(projects.domain.wallets.models) + implementation(projects.features.referral.domain) implementation(projects.core.datasource) implementation(projects.core.utils) 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 2c409f90fd..c80337d42b 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 @@ -14,9 +14,11 @@ import com.tangem.domain.promo.PromoRepository import com.tangem.domain.promo.models.PromoId import com.tangem.domain.promo.models.StoryContent import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.feature.referral.domain.ReferralRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeoutOrNull @@ -26,6 +28,7 @@ internal class DefaultPromoRepository( private val appPreferencesStore: AppPreferencesStore, private val promoStoriesStore: PromoStoriesStore, private val dispatchers: CoroutineDispatcherProvider, + private val referralRepository: ReferralRepository, ) : PromoRepository { private val storyContentConverter = StoryContentResponseConverter() @@ -34,7 +37,13 @@ internal class DefaultPromoRepository( return appPreferencesStore.get( key = PreferencesKeys.getShouldShowPromoKey(promoId = promoId.name), default = true, - ) + ).map { shouldShow -> + if (promoId == PromoId.Referral) { + !referralRepository.isReferralParticipant(userWalletId) && shouldShow + } else { + shouldShow + } + } } override fun isReadyToShowTokenPromo(promoId: PromoId): Flow { diff --git a/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt b/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt index a564ef0509..69d489a2dc 100644 --- a/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt +++ b/data/promo/src/main/java/com/tangem/data/promo/di/PromoDataModule.kt @@ -5,6 +5,7 @@ import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.promo.PromoStoriesStore import com.tangem.domain.promo.PromoRepository +import com.tangem.feature.referral.domain.ReferralRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides @@ -23,12 +24,14 @@ internal object PromoDataModule { appPreferencesStore: AppPreferencesStore, promoStoriesStore: PromoStoriesStore, dispatchers: CoroutineDispatcherProvider, + referralRepository: ReferralRepository, ): PromoRepository { return DefaultPromoRepository( tangemApi = tangemTechApi, appPreferencesStore = appPreferencesStore, promoStoriesStore = promoStoriesStore, dispatchers = dispatchers, + referralRepository = referralRepository, ) } } \ No newline at end of file diff --git a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt index f33ab65ce4..714e0e29dc 100644 --- a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt +++ b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt @@ -39,6 +39,10 @@ internal class ReferralRepositoryImpl @Inject constructor( } } + override suspend fun isReferralParticipant(userWalletId: UserWalletId): Boolean { + return getReferralData(userWalletId.stringValue) is ReferralData.ParticipantData + } + override suspend fun startReferral( walletId: String, networkId: String, diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt index 760277f9f8..9c890ff038 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt @@ -10,6 +10,9 @@ interface ReferralRepository { /** Returns data object of [ReferralData] depends on user program status */ suspend fun getReferralData(walletId: String): ReferralData + /** Returns whether user is participating in referral program */ + suspend fun isReferralParticipant(userWalletId: UserWalletId): Boolean + /** Starts user referral program */ suspend fun startReferral(walletId: String, networkId: String, tokenId: String, address: String): ReferralData diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 2688e82b36..316ee31a8a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -2,6 +2,8 @@ package com.tangem.feature.wallet.child.wallet.model.intents import arrow.core.getOrElse import com.tangem.common.TangemBlogUrlBuilder +import com.tangem.common.routing.AppRoute +import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.decompose.di.ModelScoped @@ -70,6 +72,8 @@ internal interface WalletWarningsClickIntents { fun onClosePromoClick(promoId: PromoId) + fun onPromoClick(promoId: PromoId) + fun onSupportClick() fun onNoteMigrationButtonClick(url: String) @@ -106,6 +110,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( private val urlOpener: UrlOpener, private val tokensFeatureToggles: TokensFeatureToggles, private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher, + private val appRouter: AppRouter, ) : BaseWalletClickIntents(), WalletWarningsClickIntents { override fun onAddBackupCardClick() { @@ -271,17 +276,32 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( override fun onClosePromoClick(promoId: PromoId) { analyticsEventHandler.send( - TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( - source = AnalyticsParam.ScreensSources.Main, - programName = TokenSwapPromoAnalyticsEvent.ProgramName.Empty, // Use it on new promo action - action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed, - ), + if (promoId == PromoId.Referral) { + MainScreen.ReferralPromoButtonDismiss + } else { + TokenSwapPromoAnalyticsEvent.PromotionBannerClicked( + source = AnalyticsParam.ScreensSources.Main, + programName = TokenSwapPromoAnalyticsEvent.ProgramName.Empty, // Use it on new promo action + action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed, + ) + }, ) modelScope.launch(dispatchers.main) { shouldShowPromoWalletUseCase.neverToShow(promoId) } } + override fun onPromoClick(promoId: PromoId) { + if (promoId == PromoId.Referral) { + val userWallet = getSelectedUserWallet() ?: return + analyticsEventHandler.send(MainScreen.ReferralPromoButtonParticipate) + modelScope.launch { + shouldShowPromoWalletUseCase.neverToShow(promoId) + appRouter.push(AppRoute.ReferralProgram(userWalletId = userWallet.walletId)) + } + } + } + override fun onSupportClick() { val scanResponse = getSelectedUserWallet()?.scanResponse ?: return val cardInfo = getCardInfoUseCase(scanResponse).getOrNull() ?: return diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt index a07053ba04..523e8923de 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt @@ -137,5 +137,11 @@ sealed class WalletScreenAnalyticsEvent { data object NoticeSeedPhraseSupportButtonUsed : MainScreen(event = "Button - Support Used") data object NoticeSeedPhraseSupportButtonDeclined : MainScreen(event = "Button - Support Declined") + + // region Referral Promo + data object ReferralPromo : MainScreen(event = "Referral Banner") + data object ReferralPromoButtonParticipate : MainScreen(event = "Button - Referral Participate") + data object ReferralPromoButtonDismiss : MainScreen(event = "Button - Referral Dismiss") + //endregion } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt index 36ed315d4b..0db4af387d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt @@ -53,6 +53,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor( source = AnalyticsParam.ScreensSources.Main, programName = ProgramName.Empty, // Use it on new promo action ) + is WalletNotification.ReferralPromo -> MainScreen.ReferralPromo is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender] is WalletNotification.Informational.NoAccount, is WalletNotification.Warning.LowSignatures, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt index 5ca74067c5..f50c6ea080 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt @@ -6,6 +6,8 @@ import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.core.lce.Lce import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.models.StatusSource +import com.tangem.domain.promo.ShouldShowPromoWalletUseCase +import com.tangem.domain.promo.models.PromoId import com.tangem.domain.settings.IsReadyToShowRateAppUseCase import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.CryptoCurrency @@ -34,6 +36,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( private val isNeedToBackupUseCase: IsNeedToBackupUseCase, private val backupValidator: BackupValidator, private val seedPhraseNotificationUseCase: SeedPhraseNotificationUseCase, + private val shouldShowPromoWalletUseCase: ShouldShowPromoWalletUseCase, ) { @Suppress("MagicNumber", "MaximumLineLength") @@ -45,12 +48,15 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( flow2 = isReadyToShowRateAppUseCase(), flow3 = isNeedToBackupUseCase(userWallet.walletId), flow4 = seedPhraseNotificationUseCase(userWalletId = userWallet.walletId), - ) { maybeTokenList, isReadyToShowRating, isNeedToBackup, seedPhraseIssueStatus -> + flow5 = shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.Referral), + ) { maybeTokenList, isReadyToShowRating, isNeedToBackup, seedPhraseIssueStatus, shouldShowReferralPromo -> buildList { addUsedOutdatedDataNotification(maybeTokenList) addCriticalNotifications(userWallet, seedPhraseIssueStatus, clickIntents) + addReferralPromoNotification(cardTypesResolver, clickIntents, shouldShowReferralPromo) + addInformationalNotifications(cardTypesResolver, maybeTokenList, clickIntents) addWarningNotifications(cardTypesResolver, maybeTokenList, isNeedToBackup, clickIntents) @@ -187,6 +193,20 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( .map(CryptoCurrencyStatus::currency) } + private fun MutableList.addReferralPromoNotification( + cardTypesResolver: CardTypesResolver, + clickIntents: WalletClickIntents, + shouldShowPromo: Boolean, + ) { + addIf( + element = WalletNotification.ReferralPromo( + onCloseClick = { clickIntents.onClosePromoClick(promoId = PromoId.Referral) }, + onClick = { clickIntents.onPromoClick(promoId = PromoId.Referral) }, + ), + condition = shouldShowPromo && cardTypesResolver.isTangemWallet(), + ) + } + private fun MutableList.addWarningNotifications( cardTypesResolver: CardTypesResolver, tokenList: Lce, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt index 203a35a3a8..8315a590cd 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt @@ -254,4 +254,20 @@ sealed class WalletNotification(val config: NotificationConfig) { iconResId = R.drawable.ic_error_sync_24, ), ) + + data class ReferralPromo( + val onCloseClick: () -> Unit, + val onClick: () -> Unit, + ) : WalletNotification( + config = NotificationConfig( + title = resourceReference(R.string.notification_referral_promo_title), + subtitle = resourceReference(R.string.notification_referral_promo_text), + iconResId = R.drawable.img_referral_promo, + onCloseClick = onCloseClick, + buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( + text = resourceReference(R.string.notification_referral_promo_button), + onClick = onClick, + ), + ), + ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt index 211ce57e2d..0227a5339a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt @@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.common import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.items import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.notifications.NoteMigrationNotification import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.res.TangemTheme @@ -38,6 +39,11 @@ internal fun LazyListScope.notifications(configs: ImmutableList TangemTheme.colors.icon.warning is WalletNotification.Informational -> TangemTheme.colors.icon.accent From 231798622250af7bf56cff648b2b322c9d40d018 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 25 Apr 2025 17:03:35 +0500 Subject: [PATCH 05/21] Updated on 2026-08-14 --- .../common/pushes/TangemPushNotificationService.kt | 4 ++-- .../presentation/deeplink/WalletDeepLinksHandler.kt | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt b/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt index c8dc6dda61..6cf4e25783 100644 --- a/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt +++ b/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt @@ -5,7 +5,6 @@ import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.content.Intent -import android.content.Intent.ACTION_VIEW import android.graphics.Bitmap import android.net.Uri import android.os.Build @@ -18,6 +17,7 @@ import coil.request.ImageRequest import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import com.tangem.domain.common.LogConfig +import com.tangem.tap.MainActivity import com.tangem.tap.common.images.createCoilImageLoader import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler import com.tangem.wallet.R @@ -37,7 +37,7 @@ internal class TangemPushNotificationService : FirebaseMessagingService() { val notification = message.notification ?: return val channelId = notification.channelId ?: TANGEM_CHANNEL_ID - val intent = Intent(ACTION_VIEW).apply { + val intent = Intent(applicationContext, MainActivity::class.java).apply { data = message.data[DEEPLINK_KEY]?.toUri() putExtra(OnPushClickedIntentHandler.OPENED_FROM_GCM_PUSH, true) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt index 75075d1d24..241307e17c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt @@ -8,6 +8,7 @@ import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.core.deeplink.global.BuyCurrencyDeepLink import com.tangem.core.deeplink.global.ReferralDeepLink import com.tangem.core.deeplink.global.SellCurrencyDeepLink +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.tokens.GetCryptoCurrencyUseCase import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent import com.tangem.domain.wallets.models.UserWallet @@ -55,7 +56,7 @@ internal class WalletDeepLinksHandler @Inject constructor( ) return buildList { - addReferralDeepLink(userWallet.walletId) + addReferralDeepLink(userWallet) add(sellCurrencyDeepLink) if (onrampFeatureToggles.isFeatureEnabled || !userWallet.isMultiCurrency) { add( @@ -98,13 +99,15 @@ internal class WalletDeepLinksHandler @Inject constructor( } } - private fun MutableList.addReferralDeepLink(userWalletId: UserWalletId) { + private fun MutableList.addReferralDeepLink(userWallet: UserWallet) { add( ReferralDeepLink( onReceive = { - router.push( - AppRoute.ReferralProgram(userWalletId = userWalletId), - ) + if (userWallet.cardTypesResolver.isTangemWallet()) { + router.push( + AppRoute.ReferralProgram(userWalletId = userWallet.walletId), + ) + } }, ), ) From 1bc8d7e86f9fdf65110d75d6a97bbb63f077d893 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 25 Apr 2025 18:57:37 +0500 Subject: [PATCH 06/21] Updated on 2026-08-14 --- .../tangem/domain/promo/ShouldShowPromoWalletUseCase.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt index 2a3a88329b..4afa0bd2a7 100644 --- a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt +++ b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt @@ -3,11 +3,16 @@ package com.tangem.domain.promo import com.tangem.domain.promo.models.PromoId import com.tangem.domain.wallets.models.UserWalletId import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.flow class ShouldShowPromoWalletUseCase(private val promoRepository: PromoRepository) { operator fun invoke(userWalletId: UserWalletId, promoId: PromoId): Flow { - return promoRepository.isReadyToShowWalletPromo(userWalletId, promoId) + return flow { + emit(false) + emitAll(promoRepository.isReadyToShowWalletPromo(userWalletId, promoId)) + } } suspend fun neverToShow(promoId: PromoId) = promoRepository.setNeverToShowWalletPromo(promoId) From 9793f25aaf0ed3201ec3f01f6b090f92f116f727 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 25 Apr 2025 14:33:15 +0000 Subject: [PATCH 07/21] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 8c55070de7..76affe35f0 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,7 +5,7 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.23-1048" +tangemBlockchainSdk = "releases-5.23-1043" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.23-456" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From 5ec359867b621a41be14298b7a4d9aec2d1f08aa Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 25 Apr 2025 18:21:25 +0300 Subject: [PATCH 08/21] Updated on 2026-08-14 --- .../tangem/domain/managetokens/SaveManagedTokensUseCase.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/SaveManagedTokensUseCase.kt b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/SaveManagedTokensUseCase.kt index 9f78e90712..fb5ace8f5a 100644 --- a/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/SaveManagedTokensUseCase.kt +++ b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/SaveManagedTokensUseCase.kt @@ -41,15 +41,16 @@ class SaveManagedTokensUseCase( userWalletId = userWalletId, networks = currenciesToAdd.values.flatten(), ) - val newCurrenciesList = currenciesRepository - .getMultiCurrencyWalletCurrenciesSync(userWalletId) + + val existingCurrencies = currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId) + + val newCurrenciesList = existingCurrencies .filterNot(removingCurrencies::contains) .toMutableList() .also { it.addAll(addingCurrencies) } currenciesRepository.saveNewCurrenciesList(userWalletId, newCurrenciesList) - val existingCurrencies = currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId) removeCurrenciesFromWalletManager( userWalletId = userWalletId, currencies = removingCurrencies.filterNot(existingCurrencies::contains), From 68410e14b8ccd47627c2147db9e2477631ca2063 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 28 Apr 2025 15:50:09 +0500 Subject: [PATCH 09/21] Updated on 2026-08-14 --- .../tangem/core/deeplink/DeepLinksRegistry.kt | 4 ++-- .../deeplink/impl/DefaultDeepLinksRegistry.kt | 20 ++++++++++-------- .../wallet/child/wallet/model/WalletModel.kt | 21 +++++++++++++++++++ .../deeplink/WalletDeepLinksHandler.kt | 17 --------------- .../subscribers/BasicTokenListSubscriber.kt | 7 ++++++- 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt index fc56ae10a0..2f712579cc 100644 --- a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt +++ b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt @@ -44,9 +44,9 @@ interface DeepLinksRegistry { /** * Triggers run last launched [Intent] with deeplink handlers that can handle delayed deeplink - * after handle [Intent] clear that and second time no intent will be handled + * of specific [deepLinkClass] after handle [Intent] clear that and second time no intent will be handled */ - fun triggerDelayedDeeplink() + fun triggerDelayedDeeplink(deepLinkClass: Class) fun cancelDelayedDeeplink() } \ No newline at end of file diff --git a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt index 63f6f60d78..da6b6acfd8 100644 --- a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt +++ b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt @@ -105,16 +105,18 @@ internal class DefaultDeepLinksRegistry : DeepLinksRegistry { val intent = lastIntent val received = intent?.data ?: return var hasMatch = false - registries.forEach { deepLink -> - if (!deepLink.shouldHandleDelayed) return@forEach - val expected = deepLink.uri.toUri() - if (!isMatches(expected, received)) return@forEach - hasMatch = true + registries + .filterIsInstance(deepLinkClass) + .forEach { deepLink -> + if (!deepLink.shouldHandleDelayed) return@forEach + val expected = deepLink.uri.toUri() + if (!isMatches(expected, received)) return@forEach + hasMatch = true - val params = getParams(expected, received) - logMatch(hasMatch, expected, received, params) - deepLink.onReceive(params) - } + val params = getParams(expected, received) + logMatch(hasMatch, expected, received, params) + deepLink.onReceive(params) + } if (!hasMatch) { logMatch(hasMatch, null, received, null) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 23569c3eee..817d98825d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -4,11 +4,15 @@ import androidx.compose.runtime.Stable import arrow.core.getOrElse import com.arkivanov.decompose.router.slot.activate import com.arkivanov.decompose.router.slot.dismiss +import com.tangem.common.routing.AppRoute +import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model +import com.tangem.core.deeplink.DeepLinksRegistry +import com.tangem.core.deeplink.global.ReferralDeepLink import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.nft.FetchNFTCollectionsUseCase @@ -82,7 +86,9 @@ internal class WalletModel @Inject constructor( private val analyticsEventsHandler: AnalyticsEventHandler, private val fetchNFTCollectionsUseCase: FetchNFTCollectionsUseCase, private val walletsRepository: WalletsRepository, + private val deepLinksRegistry: DeepLinksRegistry, private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase, + private val appRouter: AppRouter, val screenLifecycleProvider: ScreenLifecycleProvider, val innerWalletRouter: InnerWalletRouter, ) : Model() { @@ -223,6 +229,7 @@ internal class WalletModel @Inject constructor( selectedWalletAnalyticsSender.send(selectedWallet) } + addReferralDeepLink(selectedWallet) walletDeepLinksHandler.registerForWallet(scope = modelScope, userWallet = selectedWallet) } .flowOn(dispatchers.main) @@ -230,6 +237,20 @@ internal class WalletModel @Inject constructor( } } + private fun addReferralDeepLink(userWallet: UserWallet) { + deepLinksRegistry.register( + ReferralDeepLink( + onReceive = { + if (userWallet.cardTypesResolver.isTangemWallet()) { + appRouter.push( + AppRoute.ReferralProgram(userWalletId = userWallet.walletId), + ) + } + }, + ), + ) + } + // We need to update the current wallet quotes if the application was in the background for more than 10 seconds // and then returned to the foreground private fun subscribeToScreenBackgroundState() { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt index 241307e17c..a0b28f06fd 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt @@ -6,9 +6,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.deeplink.DeepLink import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.core.deeplink.global.BuyCurrencyDeepLink -import com.tangem.core.deeplink.global.ReferralDeepLink import com.tangem.core.deeplink.global.SellCurrencyDeepLink -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.tokens.GetCryptoCurrencyUseCase import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent import com.tangem.domain.wallets.models.UserWallet @@ -56,7 +54,6 @@ internal class WalletDeepLinksHandler @Inject constructor( ) return buildList { - addReferralDeepLink(userWallet) add(sellCurrencyDeepLink) if (onrampFeatureToggles.isFeatureEnabled || !userWallet.isMultiCurrency) { add( @@ -98,18 +95,4 @@ internal class WalletDeepLinksHandler @Inject constructor( analyticsEventHandler.send(TokenScreenAnalyticsEvent.Bought(cryptoCurrency.symbol)) } } - - private fun MutableList.addReferralDeepLink(userWallet: UserWallet) { - add( - ReferralDeepLink( - onReceive = { - if (userWallet.cardTypesResolver.isTangemWallet()) { - router.push( - AppRoute.ReferralProgram(userWalletId = userWallet.walletId), - ) - } - }, - ), - ) - } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt index 34389c69a8..88c53fd3cf 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt @@ -2,6 +2,8 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers import arrow.core.getOrElse import com.tangem.core.deeplink.DeepLinksRegistry +import com.tangem.core.deeplink.global.ReferralDeepLink +import com.tangem.core.deeplink.global.SellCurrencyDeepLink import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.core.lce.Lce @@ -114,7 +116,10 @@ internal abstract class BasicTokenListSubscriber( protected open suspend fun onTokenListReceived(maybeTokenList: Lce) { /* no-op */ if (maybeTokenList.getOrNull(false) != null) { - deepLinksRegistry.triggerDelayedDeeplink() + deepLinksRegistry.triggerDelayedDeeplink(deepLinkClass = SellCurrencyDeepLink::class.java) + } + if (maybeTokenList.getOrNull(true) != null) { + deepLinksRegistry.triggerDelayedDeeplink(deepLinkClass = ReferralDeepLink::class.java) } } From 27b6caeaeb5a2aae666647f2fe9206c52b806ccf Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 28 Apr 2025 15:50:50 +0500 Subject: [PATCH 10/21] Updated on 2026-08-14 --- .../pushes/TangemPushNotificationService.kt | 6 ++--- .../tangem/core/deeplink/DeepLinksRegistry.kt | 5 ++++ .../deeplink/impl/DefaultDeepLinksRegistry.kt | 23 +++++++++++-------- .../data/promo/DefaultPromoRepository.kt | 4 +++- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt b/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt index 6cf4e25783..8f984c76f0 100644 --- a/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt +++ b/app/src/main/java/com/tangem/tap/common/pushes/TangemPushNotificationService.kt @@ -11,11 +11,11 @@ import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toBitmap -import androidx.core.net.toUri import coil.executeBlocking import coil.request.ImageRequest import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage +import com.tangem.core.deeplink.DEEPLINK_KEY import com.tangem.domain.common.LogConfig import com.tangem.tap.MainActivity import com.tangem.tap.common.images.createCoilImageLoader @@ -38,7 +38,7 @@ internal class TangemPushNotificationService : FirebaseMessagingService() { val channelId = notification.channelId ?: TANGEM_CHANNEL_ID val intent = Intent(applicationContext, MainActivity::class.java).apply { - data = message.data[DEEPLINK_KEY]?.toUri() + putExtra(DEEPLINK_KEY, message.data[DEEPLINK_KEY]) putExtra(OnPushClickedIntentHandler.OPENED_FROM_GCM_PUSH, true) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) } @@ -103,7 +103,5 @@ internal class TangemPushNotificationService : FirebaseMessagingService() { private companion object { const val TANGEM_CHANNEL_ID = "Tangem General" // General channel for notifications const val PUSH_NOTIFICATION_REQUEST_CODE = 123 - - const val DEEPLINK_KEY = "deeplink" } } \ No newline at end of file diff --git a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt index 2f712579cc..1d3ceb8718 100644 --- a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt +++ b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/DeepLinksRegistry.kt @@ -2,6 +2,11 @@ package com.tangem.core.deeplink import android.content.Intent +/** + * Key to pass deeplink via intent + */ +const val DEEPLINK_KEY = "deeplink" + // TODO: Add tests /** * Provides functionality to handle deep links. diff --git a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt index da6b6acfd8..ff0c60033b 100644 --- a/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt +++ b/core/deep-links/src/main/kotlin/com/tangem/core/deeplink/impl/DefaultDeepLinksRegistry.kt @@ -3,6 +3,7 @@ package com.tangem.core.deeplink.impl import android.content.Intent import android.net.Uri import androidx.core.net.toUri +import com.tangem.core.deeplink.DEEPLINK_KEY import com.tangem.core.deeplink.DeepLink import com.tangem.core.deeplink.DeepLinksRegistry import timber.log.Timber @@ -10,11 +11,14 @@ import timber.log.Timber internal class DefaultDeepLinksRegistry : DeepLinksRegistry { private var registries: List = emptyList() - private var lastIntent: Intent? = null + private var lastDeepLink: Uri? = null override fun launch(intent: Intent): Boolean { - lastIntent = intent - val received = intent.data ?: return false + // Try to get deeplink from data (direct deeplink flow) + // Otherwise, try to get from extras (notification deeplink flow) + val deepLinkExtras = intent.getStringExtra(DEEPLINK_KEY)?.toUri() + val received = intent.data ?: deepLinkExtras ?: return false + lastDeepLink = received var hasMatch = false Timber.i( @@ -35,7 +39,7 @@ internal class DefaultDeepLinksRegistry : DeepLinksRegistry { logMatch(hasMatch, expected, received, params) deepLink.onReceive(params) - lastIntent = null // clear intent if it was handled + lastDeepLink = null // clear deeplink if it was handled } if (!hasMatch) { @@ -100,10 +104,9 @@ internal class DefaultDeepLinksRegistry : DeepLinksRegistry { ) } - override fun triggerDelayedDeeplink() { - if (lastIntent != null) { - val intent = lastIntent - val received = intent?.data ?: return + override fun triggerDelayedDeeplink(deepLinkClass: Class) { + val received = lastDeepLink + if (received != null) { var hasMatch = false registries .filterIsInstance(deepLinkClass) @@ -121,12 +124,12 @@ internal class DefaultDeepLinksRegistry : DeepLinksRegistry { if (!hasMatch) { logMatch(hasMatch, null, received, null) } - lastIntent = null // clear intent in any case handle or not + lastDeepLink = null // clear deeplink in any case handle or not } } override fun cancelDelayedDeeplink() { - lastIntent = null + lastDeepLink = null } private fun logMatch(hasMatch: Boolean, expected: Uri?, received: Uri?, params: Map?) { 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 c80337d42b..f48446148f 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 @@ -39,7 +39,9 @@ internal class DefaultPromoRepository( default = true, ).map { shouldShow -> if (promoId == PromoId.Referral) { - !referralRepository.isReferralParticipant(userWalletId) && shouldShow + runCatching { + !referralRepository.isReferralParticipant(userWalletId) && shouldShow + }.getOrDefault(false) } else { shouldShow } From 3f55454b655d8b7ab4314ab6c1ddb4575095955c Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 28 Apr 2025 16:12:55 +0500 Subject: [PATCH 11/21] Updated on 2026-08-14 --- .../tangem/feature/wallet/child/wallet/model/WalletModel.kt | 3 ++- .../wallet/presentation/deeplink/WalletDeepLinksHandler.kt | 1 + .../wallet/subscribers/BasicTokenListSubscriber.kt | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 817d98825d..db7f71a7a5 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -228,7 +228,8 @@ internal class WalletModel @Inject constructor( if (selectedWallet.isMultiCurrency) { selectedWalletAnalyticsSender.send(selectedWallet) } - + // Registering here, because `WalletDeepLinksHandler` unregisters deeplink when scope is cancelled + // This is temporary solution, will be removed with complete deeplink navigation overhaul addReferralDeepLink(selectedWallet) walletDeepLinksHandler.registerForWallet(scope = modelScope, userWallet = selectedWallet) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt index a0b28f06fd..9e12ece174 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt @@ -38,6 +38,7 @@ internal class WalletDeepLinksHandler @Inject constructor( deepLinksRegistry.unregisterByIds(deepLinks.map { it.id }) deepLinksRegistry.register(deepLinks = deepLinks) + // When navigation to another screen scope is Cancelled and deeplinks are hot handled scope.launchOnCancellation { deepLinksRegistry.unregister(deepLinks) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt index 88c53fd3cf..e336654e43 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicTokenListSubscriber.kt @@ -115,9 +115,12 @@ internal abstract class BasicTokenListSubscriber( protected open suspend fun onTokenListReceived(maybeTokenList: Lce) { /* no-op */ + // Handling sell deeplink requires full content in order to correctly open Send screen if (maybeTokenList.getOrNull(false) != null) { deepLinksRegistry.triggerDelayedDeeplink(deepLinkClass = SellCurrencyDeepLink::class.java) } + // Handling referral deeplink requires only selected wallet to be loaded + // This is temporary solution, will be removed with complete deeplink navigation overhaul if (maybeTokenList.getOrNull(true) != null) { deepLinksRegistry.triggerDelayedDeeplink(deepLinkClass = ReferralDeepLink::class.java) } From 61d5ef1dc07716623d325a0c49177fd891a3ba46 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 28 Apr 2025 19:02:37 +0300 Subject: [PATCH 12/21] Updated on 2026-08-14 --- .../tangem/tap/di/domain/PromoDomainModule.kt | 8 +- .../com/tangem/tap/features/home/HomeModel.kt | 18 +++ .../tap/features/home/redux/HomeAction.kt | 3 + .../tap/features/home/redux/HomeReducer.kt | 12 ++ .../tap/features/home/redux/HomeState.kt | 9 +- .../main/res/values-de/strings-blockchain.xml | 25 --- core/res/src/main/res/values-de/strings.xml | 104 ++++++++++++- .../main/res/values-es/strings-blockchain.xml | 25 --- core/res/src/main/res/values-es/strings.xml | 34 +++- .../main/res/values-fr/strings-blockchain.xml | 25 --- core/res/src/main/res/values-fr/strings.xml | 88 ++++++++++- .../main/res/values-it/strings-blockchain.xml | 17 -- core/res/src/main/res/values-it/strings.xml | 23 +++ .../main/res/values-ja/strings-blockchain.xml | 25 --- core/res/src/main/res/values-ja/strings.xml | 101 +++++++++++- .../main/res/values-ru/strings-blockchain.xml | 25 --- core/res/src/main/res/values-ru/strings.xml | 41 ++++- .../res/values-uk-rUA/strings-blockchain.xml | 25 --- .../src/main/res/values-uk-rUA/strings.xml | 34 +++- .../res/values-zh-rTW/strings-blockchain.xml | 25 --- .../src/main/res/values-zh-rTW/strings.xml | 26 ++++ .../main/res/values/strings-blockchain.xml | 25 --- core/res/src/main/res/values/strings.xml | 146 ++++++++++++++---- .../settings/DefaultSettingsRepository.kt | 15 +- domain/promo/build.gradle.kts | 1 + .../domain/promo/GetStoryContentUseCase.kt | 46 ++++-- .../repositories/SettingsRepository.kt | 2 +- .../usercountry/GetUserCountryUseCase.kt | 2 +- .../usercountry/models/UserCountry.kt | 12 +- features/markets/impl/build.gradle.kts | 1 + .../impl/model/MarketsTokenDetailsModel.kt | 14 ++ .../model/converters/DescriptionConverter.kt | 3 + .../converters/TokenMarketInfoConverter.kt | 15 +- .../features/nft/receive/ui/NFTReceive.kt | 1 - .../providers/model/SelectProviderModel.kt | 15 +- .../SetInitialDataStateTransformer.kt | 2 +- .../ui/StakingClaimRewardsValidatorContent.kt | 38 +++-- .../ui/StakingInitialInfoContent.kt | 14 +- .../ui/StakingValidatorListContent.kt | 36 +++-- .../presentation/ui/block/ValidatorBlock.kt | 32 ++-- .../tangem/feature/swap/model/SwapModel.kt | 9 ++ .../tangem/feature/swap/ui/StateBuilder.kt | 5 +- .../tokendetails/TokenDetailsPreviewData.kt | 5 +- .../TokenDetailsStakingInfoConverter.kt | 7 +- 44 files changed, 798 insertions(+), 341 deletions(-) delete mode 100644 core/res/src/main/res/values-de/strings-blockchain.xml delete mode 100644 core/res/src/main/res/values-es/strings-blockchain.xml delete mode 100644 core/res/src/main/res/values-fr/strings-blockchain.xml delete mode 100644 core/res/src/main/res/values-it/strings-blockchain.xml delete mode 100644 core/res/src/main/res/values-ja/strings-blockchain.xml delete mode 100644 core/res/src/main/res/values-ru/strings-blockchain.xml delete mode 100644 core/res/src/main/res/values-uk-rUA/strings-blockchain.xml delete mode 100644 core/res/src/main/res/values-zh-rTW/strings-blockchain.xml delete mode 100644 core/res/src/main/res/values/strings-blockchain.xml 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 8064273ab8..e35089b9e9 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 @@ -1,6 +1,7 @@ package com.tangem.tap.di.domain import com.tangem.domain.promo.* +import com.tangem.domain.settings.repositories.SettingsRepository import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -33,7 +34,10 @@ internal object PromoDomainModule { @Provides @Singleton - fun provideGetStoryContentUseCase(promoRepository: PromoRepository): GetStoryContentUseCase { - return GetStoryContentUseCase(promoRepository) + fun provideGetStoryContentUseCase( + promoRepository: PromoRepository, + settingsRepository: SettingsRepository, + ): GetStoryContentUseCase { + return GetStoryContentUseCase(promoRepository, settingsRepository) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt b/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt index 58f8a67687..91c45b832a 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeModel.kt @@ -17,6 +17,8 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.settings.repositories.SettingsRepository +import com.tangem.domain.settings.usercountry.GetUserCountryUseCase +import com.tangem.domain.settings.usercountry.models.UserCountry import com.tangem.domain.tokens.TokensAction import com.tangem.domain.wallets.builder.UserWalletBuilder import com.tangem.domain.wallets.usecase.SaveWalletUseCase @@ -24,6 +26,7 @@ import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.analytics.events.Shop import com.tangem.tap.common.extensions.dispatchNavigationAction +import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.features.home.redux.HIDE_PROGRESS_DELAY @@ -33,8 +36,10 @@ import com.tangem.tap.store import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import timber.log.Timber +import java.util.Locale import javax.inject.Inject @Suppress("LongParameterList") @@ -44,6 +49,7 @@ internal class HomeModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val scanCardProcessor: ScanCardProcessor, private val saveWalletUseCase: SaveWalletUseCase, + private val getUserCountryUseCase: GetUserCountryUseCase, private val cardSdkConfigRepository: CardSdkConfigRepository, private val settingsRepository: SettingsRepository, private val urlOpener: UrlOpener, @@ -53,6 +59,18 @@ internal class HomeModel @Inject constructor( private val tangemErrorHandler = TangemTangemErrorsHandler(store) + init { + getUserCountryUseCase.invoke() + .distinctUntilChanged() + .filterNotNull() + .onEach { + val userCountry = it.getOrNull() ?: UserCountry.Other(Locale.getDefault().country) + store.dispatchOnMain(HomeAction.UserCountryLoaded(userCountry)) + } + .flowOn(dispatchers.io) + .launchIn(modelScope) + } + fun onScanClick() { analyticsEventHandler.send(IntroductionProcess.ButtonScanCard()) scanCard() diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt index 05ba17df63..9a449e938e 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeAction.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.home.redux +import com.tangem.domain.settings.usercountry.models.UserCountry import kotlinx.coroutines.CoroutineScope import org.rekotlin.Action @@ -15,4 +16,6 @@ sealed class HomeAction : Action { data class ReadCard(val scope: CoroutineScope) : HomeAction() data class ScanInProgress(val scanInProgress: Boolean) : HomeAction() + + data class UserCountryLoaded(val userCountry: UserCountry) : HomeAction() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt index ab41e3d89f..678de45d76 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeReducer.kt @@ -1,6 +1,8 @@ package com.tangem.tap.features.home.redux +import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions import com.tangem.tap.common.redux.AppState +import kotlinx.collections.immutable.toImmutableList import org.rekotlin.Action object HomeReducer { @@ -14,6 +16,16 @@ private fun internalReduce(action: Action, appState: AppState): HomeState { is HomeAction.ScanInProgress -> { appState.homeState.copy(scanInProgress = action.scanInProgress) } + is HomeAction.UserCountryLoaded -> { + val stories = if (action.userCountry.needApplyFCARestrictions()) { + getRestrictedStories() + } else { + Stories.entries + } + appState.homeState.copy( + stories = stories.toImmutableList(), + ) + } else -> appState.homeState } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt index 89d3c728a6..b1d45779ba 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeState.kt @@ -7,7 +7,7 @@ import org.rekotlin.StateType // todo refactor [REDACTED_TASK_KEY] data class HomeState( val scanInProgress: Boolean = false, - val stories: ImmutableList = Stories.entries.toImmutableList(), + val stories: ImmutableList = getRestrictedStories().toImmutableList(), ) : StateType { val firstStory: Stories get() = stories[0] @@ -22,4 +22,11 @@ enum class Stories(val duration: Int = 6000) { Currencies, Web3, WalletForEveryone, +} + +/** + * For FCA restriction stories + */ +fun getRestrictedStories(): List { + return Stories.entries.filterNot { it == Stories.Currencies } } \ No newline at end of file diff --git a/core/res/src/main/res/values-de/strings-blockchain.xml b/core/res/src/main/res/values-de/strings-blockchain.xml deleted file mode 100644 index adea1fc8ea..0000000000 --- a/core/res/src/main/res/values-de/strings-blockchain.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - Standard - Altbestand - Erhalt der Gebühr fehlgeschlagen - Aufgrund der Beschränkungen von %1$s können nur %2$d UTXOs in eine einzige Transaktion passen. Das bedeutet, dass du nur %3$s oder weniger senden kannst. Du musst den Betrag reduzieren. - Nicht genug Geld für die Transaktion. Bitte lade dein Konto auf. - Es ist ein Fehler aufgetreten. Code: %s. - Um das %1$s -Netzwerk nutzen zu können, must du die Kontoreserve ( %2$s %3$s ) bezahlen, die diesen Betrag auf unbestimmte Zeit sperrt und verbirgt - Das Zielkonto ist nicht aktiv. Sende %s oder mehr, um das Konto zu aktivieren. - Senden Sie Geld an diese Andresse um ein Konto zu erstellen - Minimaler Betrag ist %s - Die Veränderung ist zu gering - Falsche Gebühr - Mindestguthaben ist %s - Das Zielkonto ist nicht erstellt. Der abzusendende Betrag soll %s + Gebühr oder mehr sein - Unbekannter Fehler - Der Betrag geht über die Bilanz hinaus - Ungültiger Betrag - Die Gebühr geht über die Bilanz hinaus - Der Gesamtbetrag geht über die Bilanz hinaus - Nein, alles senden - Um %s XTZ reduziert - Damit Sie beim nächsten Aufladen Ihrer Brieftasche keine erhöhte Provision zahlen, soll der Betrag um %s XTZ reduziert werden - diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index b7a04e5add..aabccb9ff7 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -21,6 +21,8 @@ Token anlegen Token verwalten Sende nur %1$s ( %2$s ) vom %3$s -Netzwerk an diese Adresse. Die Verwendung anderer Token und Netzwerke kann zum Verlust von Geldern führen. + Standard + Altbestand So scannt man Hilfe anfordern Erneut versuchen @@ -83,6 +85,7 @@ Cardano-Transaktionsanforderungen Um eine %1$s Transaktion durchzuführen, musst du einen gewissen ADA-Betrag einzahlen, um die Netzwerkgebühr und den ADA-Mindestwert zu decken (5 ADA werden empfohlen). Nicht genügend ADA für die Tokenübertrag + Betrag absenden, die Änderung darf nicht unter 1 ADA liegen Du musst einige ADA verwalten, weil du einige Token auf der Cardano-Blockchain besitzt Nicht genug ADA Akzeptieren @@ -100,6 +103,7 @@ Saldo biometrische Authentifizierung biometrische Daten + Transaktion fehlgeschlagen Kaufen Gehe zu %1$s D hast keinen Zugang zur Kamera erteilt, bitte passe deine Datenschutzeinstellungen an @@ -110,6 +114,8 @@ Stakingbelohnungen beanspruchen Schließen Bestätigen + Kontakt zum Tangem-Support + Kontakt zum Visa-Support Weiter Kopieren Adresse kopieren @@ -135,6 +141,7 @@ Erkunden Transaktionsverlauf einsehen Explorer + Erhalt der Gebühr fehlgeschlagen Netzwerkgebühren sind Gebühren, die Nutzer für die Verarbeitung und Bestätigung von Transaktionen zahlen. Die Höhe der Gebühren kann von der Überlastung des Netzes, der Größe der Transaktion und der Ausführungspriorität abhängen. %s Schnell Markt @@ -156,6 +163,7 @@ Netzgebühr Der überwiesene Betrag wird um %1$s (%2$s) gekürzt, um die gewählte Gebührenhöhe zu decken. Weiter + NFT Nein Keine Adresse Jetzt @@ -178,10 +186,12 @@ Suchen Token suchen sek. + Alles einblenden Seed phrase Aktion auswählen Verkaufen Senden + Absenden der Transaktion fehlgeschlagen Der Server ist nicht verfügbar. Bitte versuche es später erneut. Teilen Link teilen @@ -205,6 +215,7 @@ Es ist ein Fehler aufgetreten. Bitte versuche es erneut. Nicht erreichbar Staking beenden + Aufgrund der Beschränkungen von %1$s können nur %2$d UTXOs in eine einzige Transaktion passen. Das bedeutet, dass du nur %3$s oder weniger senden kannst. Du musst den Betrag reduzieren. woche mit Ja @@ -261,6 +272,7 @@ Überprüfe deine Internetverbindung oder wechseln zu einem anderen Netzwerk Nutzungsbedingungen Du hast eine Karte oder Ring aus einer anderen Wallet verwendet. Tippe auf die Karte oder Ring, die dieser Wallet zugeordnet ist. + Nicht genug Geld für die Transaktion. Bitte lade dein Konto auf. Meine Token Du hast noch keine Token hinzugefügt. Füge Token über den Markt zum Tausch hinzu Kann nicht gegen %s ausgetauscht werden @@ -298,6 +310,7 @@ Einzahlung wird erwartet Warten auf Einzahlung... Rückerstattet + Rückerstattung An dich gesendet wird an dich versendet... Gesendet @@ -340,6 +353,9 @@ Feedback zu Tangem Eine Transaktion kann nicht gesendet werden Fehler in der Coinbeschreibung + Es ist ein Fehler aufgetreten + Es ist ein Fehler aufgetreten. Code: %s. + Memo erforderlich Nur diese Gib das Genehmigungslimit für das ausgewählte Token an Betrag %s @@ -364,7 +380,7 @@ Du hast deine biometrischen Daten aktualisiert, scanne deine Karte oder Ring, um einzutreten Dein Guthaben sollte höher sein als der Gebührenwert, um eine Überweisung zu tätigen Unzureichende Mittel - Du hast nicht genug Mana für diese Transaktion. Bitte warte, bis das Mana wieder aufgefüllt ist. Dein Mana-Guthaben beträgt %1$s/%2$s + Du hast nicht genug Mana für diese Transaktion. Bitte warte, bis das Mana wieder aufgefüllt ist. Dein Managuthaben beträgt %1$s/%2$s Nicht genug Mana Du kannst nur %s übertragen, da das Koinos-Netzwerk ein Mana-Limit vorgibt. Mana-Limit @@ -499,14 +515,49 @@ Rufe dies auf oder tippe auf die Suchleiste, um Token direkt vom Markt hinzuzufügen Token hinzufügen NFC ist auf deinem Gerät nicht verfügbar + Über NFT + NFT-Vermögenswert %d Stück %d Stücke + NFTs, die an Deine Wallet-Adresse gesendet werden, werden hier angezeigt. + Noch keine Kollektionen + NFT erhalten + NFT-Kollektionen + Einige Daten werden möglicherweise nicht geladen + Vorübergehende Ladeprobleme + Basisinformationen + Netzwerk + Vertragsadresse + Letzter Verkaufspreis + Raritätsetikett + Seltenheitsgrad + Token-Adresse + Token-ID + Token-Standard + Eigenschaften + Keine Ergebnisse. Bitte versuche eine andere Anfrage. + Keine Abholung + Verfügbar + Netzwerk auswählen + NFT erhalten + Du hast dieses Netzwerk noch nicht hinzugefügt. Um NFTs zu empfangen, füge es zum Hauptbildschirm hinzu! + Netzwerk nicht hinzugefügt + Nicht hinzugefügt + NFT senden + Eigenschaften %1$d NFTs in der %2$d Sammlung Tippe hier, um das erste NFT zu erhalten NFT-Sammlungen Die Daten konnten nicht geladen werden + Um das %1$s -Netzwerk nutzen zu können, must du die Kontoreserve ( %2$s %3$s ) bezahlen, die diesen Betrag auf unbestimmte Zeit sperrt und verbirgt + Das Zielkonto ist nicht aktiv. Sende %s oder mehr, um das Konto zu aktivieren. + Senden Sie Geld an diese Andresse um ein Konto zu erstellen + Das Zielkonto verfügt nicht über eine Vertrauensstellung für das gesendete Asset. + Jetzt beitreten + Teile Deinen Code – verdiene 5 USDT pro Verkauf. Deine Freunde erhalten 10 % Rabatt. + Erhalte BELOHNUNGEN für jeden Freund! Du musst einen einzigen Zugangscode einrichten, um alle deine Geräte zu schützen Schützen Du kannst später auf jeder Karte oder Ring einen individuellen Zugangscode einrichten @@ -522,7 +573,7 @@ Bitte wiederhole den Vorgang. Die Karte oder Ring wird auf Werkseinstellungen zurückgesetzt. Aktivierungsfehler Token hinzufügen - Du hast einee Backup-Karte oder einen Backup-Ring hinzugefügt. Wenn der Backup-Prozess abgeschlossen ist, kannst Du keine weiteren Backup-Geräte hinzufügen. Wenn Du noch eine Karte oder einen Ring hast, fügen diese(n) zum Backup hinzu. Möchtest Du den Backup-Prozess fortsetzen? + Du hast eine Backup-Karte oder einen Backup-Ring hinzugefügt. Nach Abschluss des Backup-Vorgangs kannst Du keine weiteren Backup-Geräte hinzufügen. Wenn Du eine weitere Karte oder einen weiteren Ring hast, fügen diesen dem Backup jetzt hinzu. Möchtest Du den Backup-Vorgang fortsetzen? Der Sicherungsvorgang ist teilweise abgeschlossen. Du kannst ihn jetzt nicht beenden. Die Passphrase ist eine fortschrittliche Sicherheitsfunktion, die von Krypto-Wallets verwendet wird. Sie fügt ein zusätzliches Wort oder eine Phrase deiner Wahl zu der bereits bestehenden Wiederherstellungsphrase hinzu, um einen brandneuen Satz von Adressen zu erzeugen. Hinzufügen einer Sicherungskarte oder Ring @@ -638,6 +689,7 @@ Kamerazugriff verweigert Kein Memo erforderlich %1$s ( %2$s ) im %3$s Netzwerk + %1$s im %2$s Netzwerk Das Senden einer anderen Währung führt zu deren irreversiblem Verlust. Sende nur %s an diese Adresse. Der Versand einer anderen Währung führt zu ihrem unwiderruflichen Verlust. Senden nur %1$s im Netzwerk %2$s @@ -716,6 +768,12 @@ Ziel-Tag Adresse eingeben Die Adresse stimmt mit der Adresse Ihrer Brieftasche überein + Minimaler Betrag ist %s + Minimaler Wechselgeld ist %s + Falsche Gebühr + Mindestguthaben ist %s + Das Zielkonto ist nicht erstellt. Der abzusendende Betrag soll %s + Gebühr oder mehr sein + Unbekannter Fehler Ungültiges Memo. Sie wird der Transaktion nicht hinzugefügt. Memo Überprüfe deine Netzwerkverbindung @@ -773,8 +831,12 @@ inklusive einer Netzgebühr von %1$s Die Transaktion wurde erfolgreich signiert und an den Blockchain-Knoten gesendet. Die Walletbilanz wird aktualisiert %1$s ist ein Vermögenswert im Tron-Netzwerk. Um die Gebühr zu berechnen und eine Transaktion durchzuführen, musst du etwas Tron (TRX) auf deinem Konto einzahlen. + Der Betrag geht über die Bilanz hinaus Um diese Transaktion für die angegebene Adresse abzuschließen, ist ein Ziel-Tag (Memo) erforderlich. Ziel-Tag erforderlich + Ungültiger Betrag + Die Gebühr geht über die Bilanz hinaus + Der Gesamtbetrag geht über die Bilanz hinaus Transaktion gesendet Bereite das Scannen der Karte oder Ring vor, die du einrichten möchtest. Entferne diese Wallet @@ -844,6 +906,11 @@ 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. Um mit dem Staking bei TON zu beginnen, führe zunächst eine ausgehende Transaktion in beliebiger Höhe durch – dadurch wird Deine Wallet aktiviert. + Zusätzlich zur Netzwerkgebühr werden bis zu 0,2 TON benötigt, um alle Schritte der Transaktion abzuschließen. Nicht genutzte Beträge werden nach Abschluss der Transaktion zurückerstattet. + Für diesen Vorgang sind zusätzlich zur Netzwerkgebühr 0,2 TON erforderlich. Bitte lade Dein Guthaben auf. + 0,2 Ton reserviert + Durch diese Aktion werden andere Positionen geschlossen oder gemäß den Netzwerkregeln in den Auszahlungsstatus versetzt. + Positionsstatus Entsperre dein Geld, um es aus dem Staking-Prozess abzuheben. Das Freischalten nimmt %s. Nach Ablauf der 21-tägigen Bindungsfrist kannst Du über Dein Guthaben verfügen. Die Prämie wird zusammen mit dem ungestaketen Guthaben abgehoben. Deine Assets stehen Dir nach Ablauf der Frist für die Aufhebung der Bindung %s zur Verfügung. @@ -905,7 +972,7 @@ Verwende es unterwegs, überall und jederzeit. Keine Kabel oder Batterien. Tippe einfach mit der Karte oder Ring auf dein Telefon, wenn du Kryptowährung benötigst. Die Wallet für jeden Lerne Tangem kennen - Tausche, kaufen Sie NFTs, vergebe Kredite und tätige Einlagen bei mehr als 100 verschiedenen dezentralen Diensten + Mehr als 100 Integrationen dezentraler Dienste sind verfügbar Web 3.0-kompatibel Zum Fortfahren ist eine eingehende Transaktion von mindestens %1$s erforderlich Unzureichende Mittel @@ -960,7 +1027,7 @@ Blende %s aus Token ausblenden Durch das Staking kannst du alle %2$s Tage %1$s verdienen und Belohnungen erhalten - Verdiene bis zu %s Stakingprämie pro Jahr + Staking-Dienst %1$s Token in %%image%% %2$s Netzwerk Token in %%image%% %1$s Netzwerk Der %1$s (%2$s) Token ist die Hauptwährung im %3$s Netzwerk und kann nicht versteckt werden, solange du andere Token dieses Netzwerks in der Liste aktiv hast. @@ -1022,6 +1089,7 @@ Das wird nicht lange dauern. Wir richten gerade Dein Konto ein. Das wird nicht lange dauern. Wir schließen die Aktivierung ab. Alles wird vorbereitet! + PIN wurde nicht akzeptiert. Versuche es erneut oder verwende einen anderen Code. Ungültige PIN: Sequenzen oder Wiederholungen vermeiden Schon kann es losgehen! Du kannst Deine Verbindung \n auf der Website des Drittanbieters \n herstellen und zurück zur Tangem-App gelangen @@ -1030,6 +1098,7 @@ Willkommen zurück! Folge den Schritten, um Dein Konto einzurichten. Willkommen! + Diese Transaktion anfechten Freischalten Scanne Deine Karte, um den Zugriff freizuschalten Benötigte Freischaltung @@ -1163,12 +1232,36 @@ Dies ist eine Testnet-Karte. Sie kann keine Transaktionen verarbeiten und sollte nur zu Test- und Entwicklungszwecken verwendet werden. Nur für Testzwecke Der Kontostand ist möglicherweise veraltet. Aktualisiere bittre die Seite. + Unbekannte Domäne + Trotzdem verbinden + Zeitüberschreitungsfehler. Bitte versuche es später erneut. + WalletConnect konnte nicht hergestellt werden + Diese Domäne kann nicht verifiziert werden. Überprüfe die Anfrage sorgfältig und bestätige diese dann. + WalletConnect-Sitzung wurde getrennt + Fehlercode: %s. Wenn das Problem weiterhin besteht, wende Dich bitte an unseren Support. + Wir haben einen unbekannten Fehler festgestellt. + Tangem unterstützt derzeit das erforderliches Netzwerk von %s nicht. + Nicht unterstützte Netzwerke + Tangem unterstützt ein erforderliches Netzwerk um %s. + Verifizierte Domain + Wir haben eine Art Problem + Netzwerk + Netzwerke + Wallet + Signiere die Transaktionen ohne eine Vorankündigung + Genehmigung für Transaktionen anfordern + Wird nicht in der Lage sein, Verbindungen Alle trennen + Text über die Trennung aller dApps Alle dApps trennen + Füge Deinem Profil für dieses Wallet das Netzwerk %s hinzu + Die Wallet verfügt über keine erforderlichen Netzwerke Neue Verbindung Verbinde Deine Wallet mit einer anderen dApp Keine Sitzungen + Diese Domain wird von mehreren Sicherheitsanbietern als unsicher eingestuft. Verlasse diese umgehend, um Dein Vermögen zu schützen. + Bekanntes Sicherheitsrisiko Verwerfen Du hast eine unterbrochene Sicherung. Möchtest du diese fortsetzen? Ja, fortsetzen @@ -1180,4 +1273,7 @@ Karte oder Ring scannen Verwenden %s oder scanne eine Karte oder Ring, um auf die App zuzugreifen Willkommen zurück! + Nein, alles senden + Um %s XTZ reduziert + Damit Sie beim nächsten Aufladen Ihrer Brieftasche keine erhöhte Provision zahlen, soll der Betrag um %s XTZ reduziert werden diff --git a/core/res/src/main/res/values-es/strings-blockchain.xml b/core/res/src/main/res/values-es/strings-blockchain.xml deleted file mode 100644 index 709f3ab9dd..0000000000 --- a/core/res/src/main/res/values-es/strings-blockchain.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - Por defecto - Legado - No se pudo obtener la tarifa - Debido a limitaciónes sobre %1$s, solos %2$d UTXO pueden caber en una sola transacción. Esto significa que solo puedes enviar %3$s o menos. Debe reducir la cantidad. - No hay fondos suficientes para la transacción. Por favor, recargue su cuenta. - Ocurrió un error. Código: %s - Para utilizar la red %1$s, debe pagar la reserva de cuenta (%2$s%3$s), que bloquea y oculta ese monto indefinidamente - La cuenta de destino no está activa. Envíe %s o más para activar la cuenta. - Para crear una cuenta, envíe fondos a esta dirección - El monto mínimo es %s - La cantidad es demasiado baja - Tarifa no válida - El saldo mínimo es %s - No se ha creado la cuenta de destino. El monto a enviar debe ser %s + comisiones o más - Error desconocido - El monto excede el saldo - Cantidad no válida - La tarifa excede el saldo - El monto total excede el saldo - No, enviar todo - Réduire de %s XTZ - Para evitar pagar una comisión mayor la próxima vez que recargue su billetera, reduzca el monto en %s - diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index abe6273ee4..0bd26c5acb 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -21,6 +21,8 @@ Agregue un token personalizado Gestionar tokens Envíe solo %1$s (%2$s) desde redes como %3$s a esta dirección. Usar otros tokens y redes puede resultar en la pérdida de fondos. + Por defecto + Legado Cómo escanear Solicitar soporte Inténtelo de nuevo @@ -83,6 +85,7 @@ Requisitos de transacción de Cardano Para realizar una %1$s transacción, deba depositar algo de ADA para cubrir la tarifa de red y el valor mínimo de ADA (se recomiendan 5 ADA) ADA insuficiente para la transferencia de tokens + El monto enviado y el cambio no pueden ser menores a 1 ADA Deba mantener algo de ADA porque tiene algunos tokens en la blockchain de Cardano ADA insuficiente Aceptar @@ -100,6 +103,7 @@ Saldo autenticación biométrica biometría + No se pudo crear la transacción Comprar Ir a %1$s No ha otorgado acceso a su cámara, cambie su configuración de privacidad @@ -135,6 +139,7 @@ Explore Explore historial de transacciones Explorador(a) + No se pudo obtener la tarifa Las tarifas de red son cargos que los usuarios pagan para procesar y confirmar transacciones. El importe de la tarifa puede verse afectado por la congestión de la red, el tamaño de la transacción y la prioridad de ejecución. %s Rápido Mercado @@ -182,6 +187,7 @@ Seleccione una acción Vender Enviar + Error al enviar la transacción El servidor no está disponible, por favor inténtelo de nuevo más tarde Compartir Compartir enlace @@ -205,6 +211,7 @@ Hubo un error. Por favor inténtelo de nuevo. Inaccesible Termine el staking + Debido a limitaciónes sobre %1$s, solos %2$d UTXO pueden caber en una sola transacción. Esto significa que solo puedes enviar %3$s o menos. Debe reducir la cantidad. semana con @@ -261,6 +268,7 @@ Compruebe su conexión a internet o cambia a una red diferente Condiciones de uso Ha usado una tarjeta de otra billetera. Toque la tarjeta asociada con esta billetera + No hay fondos suficientes para la transacción. Por favor, recargue su cuenta. Mis tokens Aún no ha añadido ningún token. Agregue tokens a través de Market para hacer swap No se puede intercambiar por %s @@ -340,6 +348,9 @@ Comentarios en Tangem No se puede completar una transacción Error de descripción de moneda + Ocurrió un error + Ocurrió un error. Código: %s + Requiere memo Esta transacción Especifique el límite aprobado para el token seleccionado. Montante %s @@ -364,7 +375,7 @@ Ha actualizado la biometría, escanee su tarjeta o anillo para entrar Su saldo debe ser mayor que el valor de la tarifa para hacer una transferencia Saldo insuficiente - No tiene suficiente Mana para esta transacción. Por favor, espere hasta que el Mana se recargue. Su saldo de Mana es %1$s/%2$s + No tiene suficiente Mana para esta transacción. Espere hasta que se reponga el maná. Su saldo de maná es %1$s/%2$s Mana insuficiente Solo puede transferir %s debido al límite de Mana impuesto por la red Koinos Límite de Mana @@ -499,6 +510,10 @@ Tire hacia arriba o toque la barra de búsqueda para agregar tokens directamente desde el mercado Agregar tokens NFC no está disponible en su dispositivo + Para utilizar la red %1$s, debe pagar la reserva de cuenta (%2$s%3$s), que bloquea y oculta ese monto indefinidamente + La cuenta de destino no está activa. Envíe %s o más para activar la cuenta. + Para crear una cuenta, envíe fondos a esta dirección + La cuenta de destino no tiene una Trustline para el activo que se envía. Deba configurar un único código de acceso para proteger todss sus dispositivos. Proteger Puede configurar un código de acceso individual en cada tarjeta más adelante @@ -708,6 +723,12 @@ ID de destino Introduce la dirección La dirección es la misma que su billetera. + El monto mínimo es %s + El cambio mínimo es %s + Tarifa no válida + El saldo mínimo es %s + No se ha creado la cuenta de destino. El monto a enviar debe ser %s + comisiones o más + Error desconocido Memo no válido. No se añadirá a la transacción. Memo Compruebe su conexión de red @@ -765,8 +786,12 @@ incluida una tarifa de red de %1$s La transacción se firmó con éxito y se envió al nodo blockchain. El saldo de la billetera se actualizará después de un tiempo. %1$s es un activo en la red Tron. Para calcular la tarifa y realizar una transacción, deba depositar algo de Tron (TRX) en su cuenta. + El monto excede el saldo Es necesario una etiqueta de destino (memo) para completar esta transacción para la dirección especificada. Etiqueta de destino obligatoria + Cantidad no válida + La tarifa excede el saldo + El monto total excede el saldo Transacción enviada Escanee la tarjeta/anillo que quiere configurar Olvidar la billetera @@ -897,7 +922,7 @@ Úselo en cualquier lugar, en cualquier momento. Sin cables ni baterías. Solo toque la tarjeta con su teléfono cuando necesites su cripto. La billetera para todos Descubra Tangem - Intercambie, compre NFT, haga préstamos y depósitos en más de 100 servicios descentralizados diferentes + Más de 100 integraciones de servicios descentralizados están disponibles Compatible con Web 3.0 Se requiere una transacción entrante de al menos %1$s para proceder Fondos insuficientes @@ -952,7 +977,7 @@ Ocultar %s Ocultar el token El staking le permite ganar %1$s y obtener recompensas cada %2$s días - Gane hasta %s recompensa del staking por año + Servicio de Staking Token de %1$s en la red %%image%% %2$s Token en la %%image%% red %1$s El token %1$s (%2$s) es la moneda principal en la red %3$s y no se puede ocultar mientras tengas otros tokens de esta red en la lista @@ -1144,4 +1169,7 @@ Escanee la tarjeta o el anillo Use %s o escanee una tarjeta/anillo para acceder a la app ¡Bienvenido de nuevo! + No, enviar todo + Réduire de %s XTZ + Para evitar pagar una comisión mayor la próxima vez que recargue su billetera, reduzca el monto en %s diff --git a/core/res/src/main/res/values-fr/strings-blockchain.xml b/core/res/src/main/res/values-fr/strings-blockchain.xml deleted file mode 100644 index 8269ca16c6..0000000000 --- a/core/res/src/main/res/values-fr/strings-blockchain.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - Défaut - Héritage - Échec de réception des frais de commissions - En raison d\'une limitations sur les %1$s, seuls les %2$d UTXO peuvent s\'intégrer dans une seule transaction. Ce qui signifie vous ne pouvez envoyer que %3$s ou moins. Réduisez le montant. - Pas assez de fonds pour la transaction. Veuillez recharger votre compte. - Une erreur s\'est produite. Code:%s - Pour utiliser le réseau %1$s, vous devez payer la réserve de compte (%2$s%3$s), qui bloque et cache ce montant indéfiniment - Le compte de destination est inactif. Envoyez %s ou plus pour activer le compte. - Pour créer un compte, envoyez des fonds à cette adresse - Le montant minimal est de %s - Le montant est trop faible - Frais de commissions non valides - Le solde minimal est de %s - Le compte cible n\'a pas été créé. Le montant à envoyer doit être de %s + frais de commissions ou plus - Erreur inconnue - Le montant dépasse le solde - Montant invalide - Les frais de commissions dépassent le solde - Le total dépasse le solde - Non, envoyer toute la somme - Réduire de %s XTZ - Pour ne pas payer un fraid de commissions élevé la prochaine fois que vous rechargez votre portefeuille, veuillez réduire le montant de %s XTZ - diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 01f05ff01c..3866456cd5 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -21,6 +21,8 @@ Ajouter un jeton personnalisé Gérer les jetons Envoyez uniquement %1$s (%2$s) depuis les réseaux %3$s à cette adresse. L\'utilisation d\'autres jetons et réseaux peut entraîner une perte de fonds. + Défaut + Héritage Comment scanner Demander de l\'aide Réessayez @@ -83,6 +85,7 @@ Exigences pour les transactions Cardano Pour effectuer une transaction %1$s, vous devez déposer de l\'ADA pour couvrir les frais de réseau et la valeur minimale en ADA (5 ADA recommandés) ADA insuffisant pour le transfert de jetons + Le montant envoyé et la change ne peuvent être inférieurs à 1 ADA Vous devez conserver un peu d\'ADA car vous avez des jetons sur la blockchain Cardano ADA insuffisant Accepter @@ -100,6 +103,7 @@ Solde authentification biométrique biométrie + Échec de création de la transaction Acheter Aller à %1$s Vous n\'avez pas octroyé l\'accès à votre caméra, veuillez modifier vos paramètres de confidentialité @@ -135,11 +139,13 @@ Explorez Explorez l\'historique des transactions Explorateur + Échec de réception des frais de commissions Les frais de réseau sont des charges que les utilisateurs paient pour traiter et confirmer les transactions. Le montant des frais peut être affecté par la congestion du réseau, la taille de la transaction et la priorité d\'exécution. %s Rapide Marché Lent Vitesse et frais + Terminer Synchroniser les adresses Aller au fournisseur Aller au jeton @@ -159,6 +165,7 @@ Aucune adresse Maintenant OK + Ouvrir dans le navigateur Carte principale Bague principale Passphrase @@ -180,8 +187,10 @@ Sélectionnez une action Vendre Envoyer + Échec d\'envoi de la transaction Le serveur n\'est pas disponible, veuillez réessayer plus tard Partager + Partager le lien Signez Signez et envoyez Stake @@ -202,6 +211,7 @@ Il y avait une erreur. Veuillez réessayer. Inaccessible Unstakez + En raison d\'une limitations sur les %1$s, seuls les %2$d UTXO peuvent s\'intégrer dans une seule transaction. Ce qui signifie vous ne pouvez envoyer que %3$s ou moins. Réduisez le montant. semaine avec Oui @@ -258,6 +268,7 @@ Vérifiez votre connexion Internet ou passez à un réseau différent Conditions d\'utilisation Vous avez utilisé une carte d\'un autre portefeuille. Appuyez sur la carte associée à ce portefeuille + Pas assez de fonds pour la transaction. Veuillez recharger votre compte. Mes jetons Vous n\'avez pas encore ajouté de jetons. Ajoutez des jetons via Market pour effectuer une échange Ne peut pas être échangé contre %s @@ -337,6 +348,9 @@ Commentaires sur Tangem Impossible d\'effectuer une transaction Erreur de description de la pièce + Une erreur s\'est produite + Une erreur s\'est produite. Code:%s + Un mémo est requis Cette transaction Spécifiez la limite approuvée pour le jeton sélectionné Montant %s @@ -361,7 +375,7 @@ Vous avez mis à jour vos données biométriques, scannez votre carte ou bague pour entrer Votre solde doit être supérieur à la valeur des frais pour effectuer un transfert Solde insuffisant - Vous n\'avez pas assez de Mana pour cette transaction. Veuillez attendre que le Mana soit reconstitué. Votre solde de Mana est de %1$s/%2$s + Vous n\'avez pas assez de mana pour cette transaction. Veuillez patienter jusqu\'à ce que le mana soit réapprovisionné. Votre solde de mana est %1$s/%2$s Mana insuffisant Vous ne pouvez transférer que %s en raison de la limite de Mana imposée par le réseau Koinos Limite de Mana @@ -496,6 +510,23 @@ Tirez vers le haut ou appuyez sur la barre de recherche pour ajouter des jetons directement depuis le marché Ajouter des jetons NFC n\'est pas disponible sur votre appareil + Les NFT envoyés à l\'adresse de votre portefeuille s\'afficheront ici. + Aucune collection pour le moment + Recevoir des NFT + Collections NFT + Certaines données peuvent ne pas se charger + Problèmes de chargement temporaires + %1$d NFT dans la collection %2$d + Appuyez ici pour recevoir le premier NFT + Collections NFT + Impossible de charger les données + Pour utiliser le réseau %1$s, vous devez payer la réserve de compte (%2$s%3$s), qui bloque et cache ce montant indéfiniment + Le compte de destination est inactif. Envoyez %s ou plus pour activer le compte. + Pour créer un compte, envoyez des fonds à cette adresse + Le compte destinataire n\'a pas de Trustline pour l\'actif envoyé qu\'il tente d\'envoyer. + Rejoignez maintenant + Partagez votre code et gagnez 5 USDT par vente. Votre ami bénéficie de 10 % de réduction. + Recevez des RÉCOMPENSES pour chaque ami ! Vous devez définir un seul code d\'accès pour protéger tous vos appareils. Protéger Vous pourrez définir un code d\'accès individuel sur chaque carte plus tard @@ -705,6 +736,12 @@ ID de destination Entrez l\'adresse L\'adresse est la même que celle de votre portefeuille + Le montant minimal est de %s + La monnaie minimale est de %s + Frais de commissions non valides + Le solde minimal est de %s + Le compte cible n\'a pas été créé. Le montant à envoyer doit être de %s + frais de commissions ou plus + Erreur inconnue Mémo invalide. Il ne sera pas ajouté à la transaction. Mémo Vérifiez votre connexion réseau @@ -762,6 +799,12 @@ y compris des frais de réseau de %1$s La transaction a été signée avec succès et envoyée au nœud de blockchain. Le solde du portefeuille sera mis à jour après un certain temps %1$s est un actif du réseau Tron. Pour calculer les frais et effectuer une transaction, déposez du Tron (TRX) sur votre compte. + Le montant dépasse le solde + Une balise de destination (mémo) est requise pour terminer cette transaction pour l\'adresse spécifiée. + Étiquette de destination requise + Montant invalide + Les frais de commissions dépassent le solde + Le total dépasse le solde Transaction envoyée Scannez la carte/ bague que vous souhaitez configurer. Oublier le portefeuille @@ -783,6 +826,7 @@ %s profit estimatif Cote du marché Métriques + Selon les règles du réseau %1$s, les réclamations sont possibles à partir de %2$s. Les montants ci-dessous seront crédités sur votre compte lors du déblocage. Minimum requis Aucune récompense à réclamer Réclamation de récompense @@ -820,11 +864,16 @@ Solde de staking faible Un minimum de %1$s %2$s est requis pour le re-staking. Veuillez recharger votre solde. Pas assez de %s + Solde insuffisant pour le staking + Un minimum de 3 ADA est requis pour le re-staking. Veuillez recharger votre solde. + ADA insuffisants + Le montant minimum requis pour le staking doit être supérieur à 5 ADA. Veuillez recharger votre solde pour commencer à staking. L\'option de staking n\'est actuellement pas disponible en raison des conditions du réseau. Veuillez réessayer plus tard. Le staking dans le réseau %1$s avec un nouveau validateur transférera automatiquement tous les fonds précédemment stakés vers ce validateur Réinvestissez vos récompenses gagnées dans le montant que vous avez staké, augmentant ainsi vos gains potentiels. L\'option de restaker vous permet de déplacer vos fonds d\'un validateur à un autre sans avoir besoin de les déstaker. Vous êtes sur le point de staker l\'intégralité de votre solde. Nous vous recommandons de laisser un petit montant pour couvrir les frais de réseau pour unstaking ou la réclamation des récompenses. + Pour commencer à staker TON, effectuez d\'abord une transaction sortante de n\'importe quel montant — cela activera votre portefeuille. Débloquez votre argent pour le retirer du processus de staking. Le déverrouillage prend %s. Vos fonds seront disponibles à l\'utilisation après la période de déblocage de 21 jours. La récompense sera retirée en même temps que vos fonds de déblocage. Vos fonds seront disponibles pour utilisation après la période de désengagement %s. @@ -853,6 +902,7 @@ Récompenses Stake verrouillé Staker plus + Lorsque vous stakez %1$s, la totalité de votre solde %2$s est stakeée. Tout dépôt supplémentaire de %2$s sur votre portefeuille Tangem sera également staké automatiquement. Montant staké Vous stakez %1$s et recevrez %2$s Appuyez pour déverrouiller @@ -885,8 +935,10 @@ Utilisez-la en déplacement, n\'importe où, n\'importe quand. Pas de fils ni de piles. Il suffit de taper la carte sur votre téléphone lorsque vous avez besoin de votre crypto. Le portefeuille pour tous Découvrez Tangem - Échangez, achetez des NFT, faites des prêts et des dépôts dans plus de 100 services décentralisés différents + Plus de 100 intégrations de services décentralisés sont disponibles Compatible avec Web 3.0 + Une transaction entrante d\'au moins de %1$s est requise pour continuer + Fonds insuffisants 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 ! @@ -926,6 +978,7 @@ Vous n\'avez pas de fonds à envoyer. Renflouez votre compte pour pouvoir envoyer des fonds à partir de celui-ci. Die Daten wurden noch nicht geladen. Dies kann einige Sekunden dauern. Bitte versuchen Sie es später noch einmal. Le service d\'échange %s n\'est pas pris en charge par les fournisseurs actuels mais nous travaillons à ajouter plus d\'options. + Le solde affiché peut être obsolète en raison de la mise en cache. La vente de fonds sera disponible une fois que la ou les transactions en attente dans le réseau %s seront terminées L\'envoi de fonds sera disponible une fois la ou les transactions en attente dans le réseau %s terminées. L\'achat de %s n\'est pas pris en charge par les fournisseurs actuels mais nous travaillons à ajouter plus d\'options. @@ -936,7 +989,7 @@ Masquer %s Masquer le jeton Le Staking vous permet d\'en gagner %1$s et d\'obtenir des récompenses tous les %2$s jours - Gagnez jusqu\'à %s récompense de mise par an + Service de Staking %1$s jeton dans %%image%% %2$s le réseau Jeton dans le %%image%% %1$s réseau Le jeton %1$s (%2$s) est la principale devise du réseau %3$s et ne peut pas être masqué tant que vous avez d\'autres jetons de ce réseau dans la liste @@ -972,6 +1025,7 @@ Tangem Twin Cette action est irréversible. Vous n\'aurez plus accès à l\'ancien portefeuille. Appuyez sur la carte jumelle avec le numéro %s et ne la retirez pas jusqu\'à la fin de l\'opération + Nous avons rencontré une erreur. Code d\'erreur : %s. Veuillez contacter notre équipe de support. Utilisez %s ou scannez une carte/bague pour avoir accès à votre portefeuille Échec de la connexion : Cette dApp utilise Wallet Connect version1.0, qui n\'est pas prise en charge. Veuillez vous assurer que la dApp prend en charge Wallet Connect version2.0 pour réussir la connexion. Restez à jour avec les dernières fonctionnalités et actualités @@ -986,6 +1040,24 @@ Renommer le portefeuille Tout déverrouiller Tout déverrouiller avec %s + + disponible pour %d jour + disponible pour %d jours + + Soldes et Limites + Êtes-vous sûr de vouloir quitter ? Vous pourrez reprendre plus tard là où vous vous étiez arrêté. + Cela ne prendra pas longtemps. Nous configurons votre compte. + Cela ne prendra pas longtemps. Nous terminons l\'activation. + Tout est en cours de préparation ! + Code PIN invalide : évitez les séquences ou les répétitions + Accéder le site Web + Continuons la configuration de votre compte. + Content de vous revoir ! + Suivez les étapes pour configurer votre compte. + Bienvenue ! + Déverrouiller + Scannez votre carte pour déverrouiller l\'accès + Déverrouillage nécessaire La blockchain n\'est pas accessible. Réessayez plus tard Scanner la carte ou la bague Ce portefeuille a déjà été activé auparavant.\nSi cela n\'a pas été fait par vous, veuillez contacter le support.\nTangem ne vend jamais de portefeuilles avec le code d\'accès pré-généré. @@ -1116,6 +1188,13 @@ Il s\'agit d\'une carte Testnet. Elle ne peut pas traiter les transactions et ne doit être utilisée qu\'à des fins de test et de développement. À des fins de test uniquement Le solde peut être obsolète. Rafraîchissez la page. + Connexions + Déconnecter tout + Texte sur la déconnexion de toutes les dApps + Déconnecter toutes les dApps + Nouvelle connexion + Connectez votre portefeuille à différentes dApps + Aucune séance Ignorer Vous avez une sauvegarde interrompue. Voulez-vous la reprendre ? Oui, reprendre @@ -1127,4 +1206,7 @@ Scanner la carte Utiliser %s ou scanner une carte pour accéder à l\'application Bon retour ! + Non, envoyer toute la somme + Réduire de %s XTZ + Pour ne pas payer un fraid de commissions élevé la prochaine fois que vous rechargez votre portefeuille, veuillez réduire le montant de %s XTZ diff --git a/core/res/src/main/res/values-it/strings-blockchain.xml b/core/res/src/main/res/values-it/strings-blockchain.xml deleted file mode 100644 index bedc136ed0..0000000000 --- a/core/res/src/main/res/values-it/strings-blockchain.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - Impossibile ottenere la commissione - Per creare un account, invia fondi a questo indirizzo - L\'importo minimo è di %s - L\'importo residuo è molto basso - Commissione non valida - Il conto totale non è stato creato L\'importo da inviare deve essere %s + commissione o maggiore - Errore sconosciuto - L\'importo supera il saldo - Importo non valido - La commissione supera il saldo - Il totale supera il saldo - No, invia l\'intero importo - Riduci di %s XTZ - Per evitare di pagare una commissione maggiore la prossima volta che ricarichi il tuo portafoglio, riduci l\'importo di %s XTZ - diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index 9b25886a73..7132029cfe 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -1,17 +1,23 @@ + Default + Legacy Questa carta non è progettata per funzionare con Tangem + L\'importo inviato e il cambio non può essere inferiore a 1 ADA Accetta Saldo: %s + Impossibile creare la transazione Non hai fornito l\'accesso alla tua videocamera, modifica le tue impostazioni sulla privacy Annulla Rimuovere Fatto Errore + Impossibile ottenere la commissione Costi della rete OK Mantieni le modifiche Invia + Impossibile inviare la transazione Con successo Codice di accesso Prima di scansionare la carta sarà necessario inserire il codice di accesso corretto @@ -27,22 +33,39 @@ Firmato Requisiti Termini del servizio + Not enough funds for the transaction. Please top up your account. + An error occurred + Notifica richiesta Scansiona carta Avvicina per modificare il codice di accesso Avvicina per modificare la password Avvicina per scansionare Avvicina per firmare Avvicina la carta + Per creare un account, invia fondi a questo indirizzo + The destination account does not have a trustline for the asset being sent. Crea portafoglio Importo L\'indirizzo corrisponde all\'indirizzo del tuo portafoglio + L\'importo minimo è di %s + Il resto minimo è di %s + Commissione non valida + Il conto totale non è stato creato L\'importo da inviare deve essere %s + commissione o maggiore + Errore sconosciuto Memo Importo totale La transazione è stata firmata con successo e inviata al nodo blockchain. Il saldo del portafoglio verrà aggiornato dopo un po\' di tempo + L\'importo supera il saldo + Importo non valido + La commissione supera il saldo + Il totale supera il saldo Tangem Twin WalletConnect L\'indirizzo è stato copiato con successo Nessuna connessione a Internet Tangem Ok, ho capito! + No, invia l\'intero importo + Riduci di %s XTZ + Per evitare di pagare una commissione maggiore la prossima volta che ricarichi il tuo portafoglio, riduci l\'importo di %s XTZ diff --git a/core/res/src/main/res/values-ja/strings-blockchain.xml b/core/res/src/main/res/values-ja/strings-blockchain.xml deleted file mode 100644 index 5c5a94491d..0000000000 --- a/core/res/src/main/res/values-ja/strings-blockchain.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - デフォルト - レガシー - 手数料を取得できませんでした - %1$sの制限により、1つのトランザクションに収まるUTXOは%2$d個のみです。つまり、 %3$s以下しか送信できません。量を減らす必要があります。 - 取引に必要な資金が不足しています。アカウントに入金してください。 - エラーが発生しました。コード: %s 。 - %1$sネットワークを使用するには、アカウント準備金 ( %2$s %3$s ) を支払う必要があります。これにより、その金額はロックされ、無期限に非表示になります。 - 送信先アカウントが有効ではありません。%s 以上を送信してアカウントを有効にしてください。 - アカウントを作成するには、このアドレスに資金を送金してください - 最低額は%sです - 値が小さすぎます - 無効な手数料 - 最低残高は%sです - 対象アカウントは作成されていません。送信金額は、%s + 手数料またはそれ以上である必要があります。 - 不明なエラー - 金額が残高を超えています - 無効な金額 - 手数料が残高を超えています - 合計金額が残高を超えています - いいえ、すべて送信します - %s XTZを減らす - 次回ウォレットにチャージするときに手数料の増加を避けるには、金額を%s XTZ減らしてください。 - diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 9b67c45675..9492011009 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -21,6 +21,8 @@ カスタムトークンの追加 トークンの管理 このアドレスには%3$s ネットワークから%1$s (%2$s) のみを送信してください。他のトークンやネットワークを使用すると、資金を失う可能性があります。 + デフォルト + レガシー スキャン方法 サポートをリクエストする もう一度やり直してください @@ -82,6 +84,7 @@ Cardanoの取引要件 %1$s 取引を行うには、いくらかのADAを入金し、ネットワーク手数料と最小ADA (5ADAを推奨) をカバーする必要があります。 トークンを送るために必要なADAが不足しています。 + 送金額とお釣りは1ADA未満にすることはできません カルダノブロックチェーン上にトークンを持っているため、いくらかのADA残高を維持する必要があります。 ADAが不足しています。 受け入れる @@ -99,6 +102,7 @@ 残高 生体認証 生体認証 + 取引の構築に失敗しました 買う %1$sへ移動 カメラへのアクセスを許可していません。プライバシー設定を調整してください。 @@ -109,6 +113,8 @@ 報酬を受け取る 閉じる 確認 + Tangemサポートへ問い合わせる + Visaサポートへ問い合わせる 続ける コピー アドレスをコピー @@ -132,6 +138,7 @@ 移動する 取引履歴を調べる エクスプローラー + 手数料を取得できませんでした ネットワーク手数料は、取引の処理と確認のためにユーザーが支払う料金です。手数料の額は、ネットワークの混雑さ、取引のサイズ、実行の優先度によって左右されます。 %s 速い マーケット @@ -153,6 +160,7 @@ ネットワーク手数料 送金額は、選択された手数料レベルをカバーするため、%1$s (%2$s) 減額されます。 + NFT いいえ アドレスがありません @@ -175,10 +183,12 @@ 検索 トークンを検索 + すべて見る シードフレーズ アクションを選択 売る 送る + 取引の送信に失敗しました サーバーが利用できません。しばらくしてからもう一度お試しください。 共有 リンクを共有 @@ -202,6 +212,7 @@ エラーが発生しました。もう一度お試しください。 アクセスできません ステーキング解除 + %1$sの制限により、1つのトランザクションに収まるUTXOは%2$d個のみです。つまり、 %3$s以下しか送信できません。量を減らす必要があります。 はい @@ -258,6 +269,7 @@ インターネット接続を確認するか、別のネットワークに切り替えてください。 利用規約 別のウォレットのカードまたはリングを使用しました。このウォレットにリンクしているカードまたはリングをタップしてください。 + 取引に必要な資金が不足しています。アカウントに入金してください。 マイトークン まだトークンを追加していません。マーケットからトークンを追加して交換してください。 %sとの交換はできません @@ -295,6 +307,7 @@ 入金待ち 入金待ち... 返金済み + 処理中 あなたへ送金しています 送金中... 送金済み @@ -337,6 +350,9 @@ Tangemへのフィードバック 取引を送信できません コインの説明エラー + エラーが発生しました + エラーが発生しました。コード: %s 。 + メモが必要 取引 選択したトークンの承認制限を指定します 金額%s @@ -361,7 +377,7 @@ 生体認証を更新しました。カードまたはリングをスキャンして入ってください。 送金するには、残高が手数料額より高くなければなりません。 残高不足 - この取引に必要なManaが不足しています。Manaが補充されるまでお待ちください。あなたのMana残高は%1$s/%2$sです。 + この取引に必要なManaが足りません。Manaが補充されるまでお待ちください。Manaの残高は%1$s / %2$sです。 Manaが不足しています KoinosネットワークによるMana制限のため、%s のみ送金できます。 Mana上限 @@ -493,6 +509,8 @@ これをドラッグするか、検索窓をタップして、マーケットから直接トークンを追加します トークンを追加 お使いのデバイスではNFCが使用できません + NFTについて + NFTアセット アイテム @@ -502,10 +520,37 @@ NFTコレクション 一部のデータが読み込まれない場合があります 一時的な読み込みの問題 + 基本情報 + チェーン + コントラクトアドレス + 最終販売価格 + レアリティ・ラベル + レアリティ・ランク + トークンアドレス + トークンID + トークン標準 + 特徴 + 結果がありません。別のリクエストをお試しください。 + コレクションなし + 利用可能 + ネットワークを選択 + NFTを受け取る + このネットワークはまだ追加されていません。NFTの受け取りを開始するには、メイン画面に追加してください。 + ネットワークが追加されていません + 未追加 + NFTを送信する + 特徴 %1$dコレクションの%2$dNFT ここをタップして最初のNFTを受け取ります NFTコレクション データを読み込めません + %1$sネットワークを使用するには、アカウント準備金 ( %2$s %3$s ) を支払う必要があります。これにより、その金額はロックされ、無期限に非表示になります。 + 送信先アカウントが有効ではありません。%s 以上を送信してアカウントを有効にしてください。 + アカウントを作成するには、このアドレスに資金を送金してください + 送信先アカウントには、送金されるアセットのトラストラインがありません。 + 今すぐ参加 + コードを共有すると、販売ごとに5 USDTを獲得できます。お友達は10%割引になります。 + 友達への紹介で報酬を獲得しよう! すべてのデバイスを保護するには、単一のアクセスコードを設定してください。 保護する 後で各カードおよびリングに個別のアクセスコードを設定できます。 @@ -635,6 +680,7 @@ カメラへのアクセスが拒否されました メモ不要 %3$sネットワーク上の%1$s ( %2$s ) + %2$sネットワーク上の%1$s 他の暗号資産を送信すると、取り返しのつかない損失が発生します。 このアドレスには%sのみを送金してください。他のトークンを送信すると、取り返しのつかない損失が発生します。 %2$sネットワークの%1$sのみを送信してください @@ -711,6 +757,12 @@ 宛先タグ アドレスを入力 アドレスはウォレットアドレスと同じです + 最低額は%sです + 最小の変更は%sです + 無効な手数料 + 最低残高は%sです + 対象アカウントは作成されていません。送信金額は、%s + 手数料またはそれ以上である必要があります。 + 不明なエラー 無効なメモです。取引には追加されません。 メモ ネットワーク接続を確認してください @@ -768,8 +820,12 @@ ネットワーク手数料%1$sを含む 取引は正常に署名され、ブロックチェーンノードに送信されました。ウォレットの残高はしばらくして更新されます。 %1$sはTronネットワークのアセットです。手数料を計算して取引を行うには、アカウントにTron(TRX)を入金する必要があります。 + 金額が残高を超えています 指定されたアドレスへの取引を完了するには、宛先タグ(メモ)が必要です。 宛先タグが必要です + 無効な金額 + 手数料が残高を超えています + 合計金額が残高を超えています 取引が送信されました 設定したいカードまたはリングをスキャンするために準備してください。 ウォレット削除 @@ -839,6 +895,11 @@ 再ステーキングを使うと、ステーキングを解除することなく、あるバリデータから別のバリデータに資金を移動できます。 残高のすべてをステーキングしようとしています。ステーキング解除や報酬請求にかかるネットワーク手数料をカバーするために、少額を残しておくことをお勧めします。 TONでステーキングを開始するには、まず任意の金額の送金を行ってください。これにより、ウォレットがアクティブになります。 + ネットワーク手数料に加え、取引の全ステップを完了するには最大0.2 TONが必要です。未使用分は取引完了後に返金されます。 + この操作を続行するには、ネットワーク手数料に加えて0.2 TONが必要です。残高を補充してください。 + 0.2 TON保留済み + このアクションは、ネットワークのルールに従って、他のポジションをクローズするか、引き出しステータスに切り替えます。 + ポジション状況 資金をステーキングから引き出すには、ロックを解除してください。ロック解除には%sかかります。 資金は、21日間のロック解除期間後に使用可能になります。報酬は、ロック解除後の資金とともに引き出されます。 %sのステーキング解除期間後、資金はすぐ利用可能となります。 @@ -955,7 +1016,7 @@ %sを非表示 トークンを非表示 ステーキングにより、 %1$sを獲得し、 %2$s日ごとに報酬を受け取ることができます。 - 年間最大%sのステーキング報酬を獲得 + ステーキングサービス %%image%% %2$s ネットワークの %1$s トークン %%image%% %1$sネットワーク上のトークン %1$s ( %2$s ) トークンは%3$sネットワークの主要通貨であり、このネットワーク上の他のトークンがリストにある限り、非表示にすることはできません。 @@ -1015,12 +1076,14 @@ 長くはかかりません。アカウントを設定しています。 長くはかかりません。アクティベーションを完了しています。 準備完了です! + PINの認証に失敗しました。もう一度お試しいただくか、別のコードを使用してください。 無効な暗証番号:連続や繰り返しを避けてください ウェブサイトに移動 アカウントの設定を続けましょう。 お帰りなさい! 手順に従ってアカウントを設定してください。 ようこそ! + この取引に異議を唱える ロック解除 カードをスキャンしてアクセスロックを解除する ロック解除が必要 @@ -1153,13 +1216,44 @@ これはテストネットカードです。取引処理はできませんので、テストおよび開発目的でのみご利用ください。 テスト目的のみ 残高が古い可能性があります。ページを更新してください。 + 不明なドメイン + とにかく接続する + タイムアウトエラーが発生しました。しばらくしてからもう一度お試しください。 + WalletConnectを確立できませんでした + このドメインは検証できません。承認前にリクエスト内容をよく確認してください。 + ブラウザに戻り、WalletConnect経由で再度接続してください。 + WalletConnectセッションが接続解除されました + エラーコード: %s 。問題が解決しない場合は、お気軽にサポートまでお問い合わせください。 + 不明なエラーが発生しました + Tangemは現在%sで必要なネットワークをサポートしていません。 + サポートされていないネットワーク + Tangemは%sで必要なネットワークをサポートします。 + 検証済みドメイン + Tangemアプリで誤ったカードまたはリングが選択されました + 問題が起きています + 接続する + ネットワーク + ネットワーク + ウォレット + 接続されたネットワーク + ウォレットの残高とアクティビティを表示する + 通知なしに取引に署名する + 取引の承認をリクエストする + できなくなります + したい + 接続リクエスト 接続 すべての接続を解除する すべてのdAppsの接続解除に関するテキスト すべてのdAppを接続解除する + このウォレットのプロフィールに%sネットワークを追加する + ウォレットに必要なネットワークはありません 新しい接続 ウォレットを別のdAppに接続する セッションなし + このドメインは複数のセキュリティプロバイダーから安全でないとの警告を受けています。あなたの資産を守るため、直ちにアクセスを中止してください。 + 既知のセキュリティリスク + ウォレットコネクト 破棄 バックアップが中断されました。再開しますか? はい、再開します @@ -1171,4 +1265,7 @@ カードまたはリングをスキャン アプリにアクセスするには、 %sを使用するか、カードまたはリングをスキャンします お帰りなさい! + いいえ、すべて送信します + %s XTZを減らす + 次回ウォレットにチャージするときに手数料の増加を避けるには、金額を%s XTZ減らしてください。 diff --git a/core/res/src/main/res/values-ru/strings-blockchain.xml b/core/res/src/main/res/values-ru/strings-blockchain.xml deleted file mode 100644 index f589ed1f9f..0000000000 --- a/core/res/src/main/res/values-ru/strings-blockchain.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - По умолчанию - Устаревший - Не удалось получить комиссию - Из-за ограничений %1$s в одну транзакцию может поместиться только %2$d UTXO. Это означает, что вы можете отправить только %3$s или меньше. Вам нужно уменьшить сумму. - Недостаточно средств для совершения транзакции. Пожалуйста, пополните свой аккаунт. - Произошла ошибка. Код: %s. - Чтобы использовать сеть %1$s, вы должны оплатить резерв аккаунта (%2$s %3$s), который блокируется и не используется в вашем балансе - Аккаунт получателя не активирован. Отправьте %s или более для активации аккаунта. - Для создания аккаунта отправьте средства на этот адрес - Минимальная сумма: %s - Сдача слишком мала - Неверная комиссия - Минимальный баланс: %s - Аккаунт получателя не создан. Сумма для отправки должна быть %s + комиссия или больше - Неизвестная ошибка - Сумма превышает остаток - Недопустимая сумма - Комиссия превышает остаток - Отправляемая сумма превышает остаток - Нет, отправить все - Уменьшить на %s XTZ - Чтобы не платить повышенную комиссию при следующем пополнении кошелька, уменьшите сумму на %s XTZ - diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index de090f81f6..a4e05ae190 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -21,6 +21,8 @@ Добавить токен Валюты Отправляйте только %1$s (%2$s) в сети %3$s на этот адрес. Использование другой сети может привести к утрате средств. + По умолчанию + Устаревший Как сканировать Обратиться в поддержку Попробовать снова @@ -85,6 +87,7 @@ Требования к транзакции Cardano Чтобы совершить транзакцию %1$s, внесите некоторую сумму ADA для покрытия сетевой комиссии и минимального значения ADA (рекомендуется 5 ADA) Недостаточно ADA для транзакции + Отправляемая сумма и сдача не могут быть меньше 1 ADA Вы должны поддерживать некоторое количество ADA, поскольку у вас на балансе есть токены в сети Cardano Недостаточно ADA Принять @@ -102,6 +105,7 @@ Баланс биометрическую аутентификацию биометрией + Не удалось создать транзакцию Купить Перейти на %1$s Вы не предоставили доступ к камере, пожалуйста, измените настройки конфиденциальности. @@ -141,6 +145,7 @@ Обозреватель Посмотреть историю транзакций Обозреватель + Не удалось получить комиссию Сетевые комиссии – это плата пользователя за обработку и подтверждение транзакций. Размер комиссии зависит от нагрузки на сеть, объема транзакции и приоритета исполнения. %s Быстро По рынку @@ -188,6 +193,7 @@ Выберите действие Продать Отправить + Не удалось отправить транзакцию Сервер недоступен, повторите попытку позднее Поделиться Поделиться ссылкой @@ -211,6 +217,7 @@ Произошла ошибка. Пожалуйста, попробуйте снова. Недоступно Завершить стейкинг + Из-за ограничений %1$s в одну транзакцию может поместиться только %2$d UTXO. Это означает, что вы можете отправить только %3$s или меньше. Вам нужно уменьшить сумму. неделю с Да @@ -267,6 +274,7 @@ Проверьте подключение с интернетом или переключитесь на другую сеть Условия использования Вы использовали карту или кольцо от другого кошелька. Приложите карту или кольцо, связанную с этим кошельком. + Недостаточно средств для совершения транзакции. Пожалуйста, пополните свой аккаунт. Мои токены У вас нет добавленных токенов. Добавьте токены для обмена Недоступен для обмена с %s @@ -345,6 +353,9 @@ Обращение в поддержку Tangem Не могу отправить транзакцию Ошибка в описании монеты + Произошла ошибка + Произошла ошибка. Код: %s. + Требуется memo Транзакция Укажите лимит доступа к выбранному токену Количество %s @@ -434,7 +445,7 @@ Все Опытные трейдеры - Рейтинг + Капитализация Сортировать по Лидеры роста Лидеры падения @@ -510,6 +521,13 @@ Потяните вверх или коснитесь поисковой строки, чтобы добавить токены напрямую из рынка Добавить токены Функция NFC недоступна на вашем устройстве + Чтобы использовать сеть %1$s, вы должны оплатить резерв аккаунта (%2$s %3$s), который блокируется и не используется в вашем балансе + Аккаунт получателя не активирован. Отправьте %s или более для активации аккаунта. + Для создания аккаунта отправьте средства на этот адрес + Аккаунт получателя не содержит трастлайна для отправляемого актива. + Присоединиться + Поделись промокодом — заработай 5 USDT с каждой покупки. Твои друзья получат скидку 10% на карту Tangem! + Получай бонусы за каждого друга! Установите единый код доступа для защиты всех ваших карт или колец Защита Установите индивидуальный код доступа для каждой карты или кольца позже. @@ -727,6 +745,12 @@ Код назначения Введите адрес Адрес совпадает с адресом кошелька + Минимальная сумма: %s + Минимальная сдача: %s + Неверная комиссия + Минимальный баланс: %s + Аккаунт получателя не создан. Сумма для отправки должна быть %s + комиссия или больше + Неизвестная ошибка Недопустимый Memo. Он не будет добавлен в транзакцию. Memo Проверьте своё интернет соединение @@ -784,7 +808,11 @@ включая комиссию сети в размере %1$s Транзакция успешно подписана и отправлена в блокчейн. Баланс будет обновлен через некоторое время %1$s — это монета в сети Tron. Чтобы рассчитать комиссию и совершить транзакцию, вам необходимо внести немного Tron (TRX) на свой адрес. + Сумма превышает остаток Для завершения транзакции на указанный адрес необходим тег назначения (мемо). + Недопустимая сумма + Комиссия превышает остаток + Отправляемая сумма превышает остаток Транзакция отправлена Подготовьтесь к сканированию кольца или карты, которую вы хотите настроить. Забыть кошелек @@ -853,6 +881,9 @@ Рестейк позволяет вам переместить средства из одного валидатора в другого без необходимости выхода из стейкинга. Вы собираетесь застейкать весь баланс, рекомендуем оставить небольшую сумму для оплаты комиссии сети при выходе из стейкинга или получении награды. Чтобы начать стейкинг в TON, сначала осуществите исходящую транзакцию на любую сумму — это активирует ваш кошелек. + В дополнение к сетевой комиссии может потребоваться до 0.2 TON для завершения всех этапов транзакции. Неиспользованная часть будет возвращена после выполнения. + Для выполнения операции требуется дополнительно 0.2 TON, помимо сетевой комиссии. Пожалуйста, пополните баланс. + Зарезервировано 0.2 TON Разблокируйте свои средства, чтобы вывести их из стейкинга. Разблокировка займёт %s. Ваши средства будут доступны для использования после 21-дневного периода отзыва. Награда будет выведена вместе с вашими выводими средствами. Ваши средства будут доступны после %s периода отзыва. @@ -914,7 +945,7 @@ Используйте его на ходу, в любом месте, в любое время. Без проводов и батареек. Как только понадобится крипта, просто приложите карту или кольцо к телефону. Кошелек для каждого Встречайте Tangem - Обменивайте, покупайте NFT, получайте займы и делайте вклады в более чем 100 различных децентрализованных сервисах + Более 100 децентрализованных сервисов уже доступны для интеграции Поддержка Web 3.0 Для отправки требуется входящая транзакция на сумму не менее %1$s Недостаточно средств @@ -969,7 +1000,7 @@ Скрыть %s Скрыть токен Стейкинг позволяет вам зарабатывать %1$s и получать вознаграждения каждые %2$s дней - Зарабатывайте до %s вознаграждений за стейкинг ежегодно + Сервис стейкинга %1$s токен в сети %%image%% %2$s Токен в сети %%image%% %1$s Токен %1$s (%2$s) является основной валютой в сети %3$s и не может быть скрыт до тех пор, пока у вас в списке есть другие токены этой сети @@ -1020,6 +1051,7 @@ Переименование кошелька Разблокировать все Разблокировать все с %s + ПИН не принят. Попробуйте ещё раз или введите другой код. Блокчейн недоступен. Попробуйте позже. Отсканируйте карту или кольцо Этот кошелек уже был активирован ранее.\nЕсли это сделали не вы, свяжитесь со службой поддержки.\nTangem никогда не продает кошелек вместе с предустановленным кодом доступа. @@ -1163,4 +1195,7 @@ Сканировать карту или кольцо Используйте %s или отсканируйте карту либо кольцо для входа в приложение C возвращением! + Нет, отправить все + Уменьшить на %s XTZ + Чтобы не платить повышенную комиссию при следующем пополнении кошелька, уменьшите сумму на %s XTZ diff --git a/core/res/src/main/res/values-uk-rUA/strings-blockchain.xml b/core/res/src/main/res/values-uk-rUA/strings-blockchain.xml deleted file mode 100644 index d2c3ed6cdf..0000000000 --- a/core/res/src/main/res/values-uk-rUA/strings-blockchain.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - За замовчуванням - Застарілий - Не вдалося отримати комісію - Через обмеження %1$s в одну транзакцію може поміститися тільки %2$d UTXO. Це означає, що ви можете відправити тільки %3$s або менше. Вам потрібно зменшити суму. - Недостатньо коштів для здійснення транзакції. Будь ласка, поповніть свій акаунт. - Виникла помилка. Код: %s. - Щоб користуватися мережею %1$s, ви маєте оплатити резерв акаунта (%2$s %3$s), який блокується і не використовується у вашому балансі - Обліковий запис одержувача не активовано. Надішліть %s або більше, щоб активувати обліковий запис. - Для створення акаунту надішліть кошти на цю адресу - Мінімальна сума: %s - Решта занадто мала - Невірна комісія - Мінімальний баланс: %s - Обліковий запис одержувача не створено. Сума для переказу повинна бути %s + комісія або більше - Невідома помилка - Сума перевищує залишок - Недопустима сума - Комісія перевищує залишок - Сума, що відправляється, перевищує залишок - Ні, відправити все - Зменшити на %s XTZ - Щоб не платити підвищену комісію при наступному поповненні гаманця, зменште суму на %s XTZ - 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 4b6a67ab8c..06a4c50786 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -21,6 +21,8 @@ Додати токен Токени Надсилайте тільки %1$s (%2$s) в мережі %3$s на цю адресу. Використання іншої мережі може призвести до втрати коштів. + За замовчуванням + Застарілий Як сканувати Звернутися в підтримку Спробуйте ще раз @@ -85,6 +87,7 @@ Вимоги до транзакції Cardano Щоб здійснити транзакцію %1$s, внесіть певну суму ADA для покриття мережевої комісії та мінімальне значення ADA (рекомендовано 5 ADA) Недостатньо ADA для транзакції + Сума і решта, що відправляються, не можуть бути меншими за 1 ADA Ви повинні утримувати деяку кількість ADA, оскільки у вас на балансі є токени в мережі Cardano Недостатньо ADA Прийняти @@ -102,6 +105,7 @@ Баланс біометричну автентифікацію біометрії + Не вдалося створити транзакцію Купити Перейдіть до %1$s Ви не надали доступ до камери, будь ласка, змініть налаштування конфіденційності @@ -141,6 +145,7 @@ Оглядач Переглянути історію транзакцій Оглядач + Не вдалося отримати комісію Мережеві комісії – це збори, які користувачі сплачують за обробку та підтвердження транзакцій. На розмір комісії може впливати перевантаження мережі, розмір транзакції та пріоритет виконання. %s Швидко За ринком @@ -188,6 +193,7 @@ Оберіть дію Продати Надіслати + Не вдалося надіслати транзакцію Сервер недоступний, спробуйте пізніше Поширити Поділитися посиланням @@ -211,6 +217,7 @@ Виникла помилка. Будь ласка, спробуйте ще раз. Недоступно Скасувати стейкінг + Через обмеження %1$s в одну транзакцію може поміститися тільки %2$d UTXO. Це означає, що ви можете відправити тільки %3$s або менше. Вам потрібно зменшити суму. тиждень з Так @@ -267,6 +274,7 @@ Перевірте підключення до інтернету або змініть мережу Умови використання Ви використали картку або кільце від іншого гаманця. Прикладіть картку або кільце, пов\'язану з цим гаманцем. + Недостатньо коштів для здійснення транзакції. Будь ласка, поповніть свій акаунт. Мої токени У вас немає доданих токенів. Додайте токени для обміну Недоступний для обміну з %s @@ -346,6 +354,9 @@ Звернення в підтримку Tangem Не вдається відправити транзакцію Помилка в описі монети + Виникла помилка + Виникла помилка. Код: %s. + Вимагається memo Транзакція Вкажіть ліміт доступу для обраного токена Кількість %s @@ -370,7 +381,7 @@ Ви оновили дані біометрії, відскануйте свою картку або кільце для входу Ваш баланс повинен перевищувати суму комісії для здійснення переказу Недостатньо балансу - У вас недостатньо Mana для цієї транзакції. Будь ласка, зачекайте, поки Mana буде поповнена. Ваш баланс Mana становить %1$s/%2$s + У вас недостатньо Мани для цієї транзакції. Будь ласка, зачекайте, поки Мана поповниться. Ваш баланс мани дорівнює %1$s/%2$s Недостатньо Mana Ви можете переказати тільки %s через обмеження Mana, встановлене мережею Koinos Ліміт Mana @@ -511,6 +522,10 @@ Потягніть вгору або торкніться панелі пошуку, щоб додати токени безпосередньо з маркету Додати токени Функція NFC недоступна на вашому пристрої + Щоб користуватися мережею %1$s, ви маєте оплатити резерв акаунта (%2$s %3$s), який блокується і не використовується у вашому балансі + Обліковий запис одержувача не активовано. Надішліть %s або більше, щоб активувати обліковий запис. + Для створення акаунту надішліть кошти на цю адресу + Акаунт одержувача не містить трастлайну для активу, що надсилається. Налаштуйте єдиний код доступу для захисту всіх ваших карток або кілець Захист Встановіть індивідуальний код доступу для кожної картки або кільця пізніше. @@ -728,6 +743,12 @@ Тег призначення Введіть адресу Адреса збігається з адресою гаманця + Мінімальна сума: %s + Мінімальна решта: %s + Невірна комісія + Мінімальний баланс: %s + Обліковий запис одержувача не створено. Сума для переказу повинна бути %s + комісія або більше + Невідома помилка Недопустимий Memo. Він не буде доданий до транзакції. Memo Перевірте підключення до мережі @@ -785,8 +806,12 @@ включно з комісією мережі %1$s Транзакція успішно підписана і відправлена до блокчейну. Баланс гаманця буде оновлено через деякий час %1$s — це монета у мережі Tron. Щоб розрахувати комісію та здійснити транзакцію, вам необхідно внести певну кількість Tron (TRX) на свій рахунок. + Сума перевищує залишок Тег призначення (memo) потрібен для завершення цієї транзакції для вказаної адреси. Тег призначення обов\'язковий + Недопустима сума + Комісія перевищує залишок + Сума, що відправляється, перевищує залишок Трансакцію надіслано Підготуйтеся до сканування кільця або картки, яку ви хочете налаштувати. Забути гаманець @@ -917,7 +942,7 @@ Використовуйте його в дорозі, будь-де і будь-коли. Ніяких дротів чи батарейок. Просто прикладіть картку або кільце до телефону, коли вам потрібна криптовалюта. Гаманець для кожного Зустрічайте Tangem - Обмінюйте, купуйте NFT, отримуйте позики та робіть депозити у понад 100 різних децентралізованих сервісах + Доступно понад 100 інтеграцій з децентралізованими сервісами Web 3.0 сумісність Для відправки потрібна вхідна транзакція на суму не менше %1$s Недостатньо коштів @@ -972,7 +997,7 @@ Приховати %s Приховати токен Стейкінг дозволяє заробляти %1$s і отримувати винагороду кожні %2$s днів - Заробляйте до %s винагород за стейкінг щороку + Сервіс стейкінгу %1$s токен в мережі %%image%% %2$s Токен у мережі %%image%% %1$s Токен %1$s (%2$s) є основною валютою в мережі %3$s і не може бути прихований до тих пір, поки у вас в списку є інші токени цієї мережі @@ -1166,4 +1191,7 @@ Сканувати картку або кільце Використовуйте %s або відскануйте картку або кільце для входу у додаток З поверненням! + Ні, відправити все + Зменшити на %s XTZ + Щоб не платити підвищену комісію при наступному поповненні гаманця, зменште суму на %s XTZ diff --git a/core/res/src/main/res/values-zh-rTW/strings-blockchain.xml b/core/res/src/main/res/values-zh-rTW/strings-blockchain.xml deleted file mode 100644 index 7545da58e5..0000000000 --- a/core/res/src/main/res/values-zh-rTW/strings-blockchain.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - 默認 - 遺留資產 - 獲取費用失敗 - 由於 %1$s 的限制,只有%2$d UTXO 可以放入單次交易中。這意味著您只能發送%3$s或更少數量。您需要減少數量。 - 沒有足夠的資金進行交易。請先入金 - - - 目標帳戶未激活。發送 %s 或更多以激活帳戶 - 要創建帳戶,請將資金發送到此地址 - 最小數量是 %s - 更動太小 - 無效費用 - 最低餘額為 %s - 未創建目標帳戶。發送金額應為 %s + 費用或更多 - 未知錯誤 - 金額超出餘額 - 無效金額 - 費用超出餘額 - 總金額超出餘額 - 不,全部發送 - 減少 %s XTZ - 為避免下次給錢包充值時支付增加的佣金,請將金額減少 %s XTZ - diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml index 814be67145..e1f37d9840 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -3,6 +3,8 @@ 添加自定義代幣 管理代幣 僅將 %1$s (%2$s) 從 %3$s 網絡發送到此地址。使用其他代幣和網絡可能會導致資金損失 + 默認 + 遺留資產 請求支持 再試一次 此功能不在展示模式中提供 @@ -36,6 +38,7 @@ 回復至原廠設置 安全模式 卡片設置 + 發送金額和找零不能少於1個ADA 接受 允許 注意 @@ -43,6 +46,7 @@ 餘額 生物識別 生物 + 建立交易失敗 購買 您尚未授予相機訪問權限,請更改您的隱私設置 删除 @@ -58,6 +62,7 @@ 允許 啟用 錯誤 + 獲取費用失敗 導入 進行中 網路費 @@ -73,6 +78,7 @@ 選擇 銷售 發送 + 發送交易失敗 伺服器不可用,請稍後在試 分享 簽署 @@ -85,6 +91,7 @@ 交易 我了解 無法觸達 + 由於 %1$s 的限制,只有%2$d UTXO 可以放入單次交易中。這意味著您只能發送%3$s或更少數量。您需要減少數量。 已複製代幣地址 支持的網路 @@ -121,6 +128,7 @@ 檢查您的網路連接或切換到其他網絡 服務條款 您使用了另一個錢包中的卡。點按與此錢包關聯的卡片 + 沒有足夠的資金進行交易。請先入金 以下信息是可選的。如果不想共享,可以將其刪除 告訴我們您缺少哪些功能,我們會盡力幫助您 請告訴我們你有什麼卡 @@ -131,6 +139,8 @@ 反饋 Tangem反饋 無法發送交易 + An error occurred + 需要memo 數量 %s 要繼續,您需要允許 %1s 智能合約使用您的 %2s 賦予權限 @@ -146,6 +156,9 @@ 要訪問所有的網路您需要掃描卡片 掃描卡片 代幣 + 目標帳戶未激活。發送 %s 或更多以激活帳戶 + 要創建帳戶,請將資金發送到此地址 + 目標帳戶沒有用於發送資產的 trustline 保護 您可以稍後在每張卡上設置單獨的訪問密碼 個人化 @@ -255,10 +268,20 @@ 準備好您的卡! 數量 地址與錢包地址相同 + 最小數量是 %s + 最小變化是 %s + 無效費用 + 最低餘額為 %s + 未創建目標帳戶。發送金額應為 %s + 費用或更多 + 未知錯誤 Memo無效。 它不會被添加到交易中 Memo 最大值 交易已成功簽署並發送至區塊鏈節點。錢包餘額稍後更新 + 金額超出餘額 + 無效金額 + 費用超出餘額 + 總金額超出餘額 安全地存儲您的加密貨幣,同時將私鑰保存在您的卡中 創新式的硬體錢包 最多 3張實體卡片 到一個錢包 @@ -358,4 +381,7 @@ 掃描卡片 使用 %s 或掃描卡片以訪問該應用程序 歡迎回來! + 不,全部發送 + 減少 %s XTZ + 為避免下次給錢包充值時支付增加的佣金,請將金額減少 %s XTZ diff --git a/core/res/src/main/res/values/strings-blockchain.xml b/core/res/src/main/res/values/strings-blockchain.xml deleted file mode 100644 index ef4e2b2edb..0000000000 --- a/core/res/src/main/res/values/strings-blockchain.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - Default - Legacy - Failed to get fee - Due to %1$s limitations only %2$d UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount. - Not enough funds for the transaction. Please top up your account. - An error occurred. Code: %s. - To use the %1$s network, you must pay the account reserve (%2$s %3$s), which locks up and hides that amount indefinitely - Destination account is not active. Send %s or more to activate the account. - To create account send funds to this address - Minimum amount is %s - Change is too small - Invalid Fee - Minimum balance is %s - Target account is not created. Amount to send should be %s + fee or more - Unknown error - Amount exceeds balance - Invalid amount - Fee exceeds balance - Total amount exceeds balance - No, send all - Reduce by %s XTZ - To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ - diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 48b2496729..0e73021a1e 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -21,6 +21,8 @@ Add custom token Manage tokens Send only %1$s (%2$s) from %3$s network to this address. Using other tokens and networks may result in loss of funds. + Default + Legacy How to scan Request support Try again @@ -83,6 +85,7 @@ Cardano transaction requirements To make a %1$s transaction, you must deposit some ADA to cover the network fee and minimum ADA value (5 ADA recommended) Insufficient ADA for token transfer + Sent amount and change cannot be less than 1 ADA You must maintain some ADA because you have some tokens on the Cardano blockchain Not enough ADA Accept @@ -100,6 +103,7 @@ Balance biometric authentication biometrics + Failed to build transaction Buy Go to %1$s You have not given access to your camera, please adjust your privacy settings @@ -110,13 +114,14 @@ Claim rewards Close Confirm + Contact Tangem Support + Contact Visa Support Continue Copy Copy address Create %1$s (%2$s) Custom - NFT %d day %d days @@ -136,6 +141,7 @@ Explore Explore transaction history Explorer + Failed to get fee Network fees are charges users pay to process and confirm transactions. The fee amount can be affected by network congestion, transaction size, and execution priority. %s Fast Market @@ -157,6 +163,7 @@ Network fee Amount sent will be reduced by %1$s (%2$s) to cover the selected fee level Next + NFT No No address Now @@ -184,6 +191,7 @@ Select action Sell Send + Failed to send transaction The server is not available, please try again later Share Share Link @@ -208,6 +216,7 @@ There was an error. Please try again. Unreachable Unstake + Due to %1$s limitations only %2$d UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount. week with Yes @@ -264,6 +273,7 @@ Check your internet connection or switch to a different network Terms of service You have used a card or ring from another wallet. Tap the card or ring associated with this wallet + Not enough funds for the transaction. Please top up your account. My tokens You haven\'t added any tokens yet. Add tokens via Market to swap Cannot be swapped for %s @@ -301,6 +311,7 @@ Awaiting deposit Awaiting deposit... Refunded + Refunding Sending to you Sending to you... Sent @@ -309,11 +320,11 @@ Verification required Awaiting transaction hash List of all tokens added to your wallet - Fetching best rates... + Fetching current rates... Floating rate By using swap functionality, you agree with provider’s %s By using swap functionality, you agree with provider’s %1$s and %2$s - More providers are coming soon.\nStay tuned! + More providers will be available soon Provider Best rate Available up to %s @@ -343,6 +354,9 @@ Tangem feedback Can\'t send a transaction Coin description error + An error occurred + An error occurred. Code: %s. + Requires memo Transaction Specify the approve limit for the selected token Amount %s @@ -406,6 +420,7 @@ This asset is currently not supported in the wallet This asset is not available for this wallet Add + APY %s Available networks My portfolio Market @@ -430,11 +445,13 @@ 7d All Experienced buyers - Rating + Capitalization Sort By Top Gainers Top Losers Trending + Staking is the easiest way to receive rewards on your crypto. + Earn up to %s APY About %s %d exchange @@ -479,9 +496,9 @@ Market cap The total market value of a cryptocurrency, calculated by multiplying the current price of the coin by the total number of coins in circulation Market cap - Market rating + Market position Position in crypto rating between all coins based on market capitalization - Market rating + Market position Max supply The maximum number of coins or tokens that can ever exist for a particular cryptocurrency Max supply @@ -502,6 +519,8 @@ Pull this up or tap the search bar to add tokens directly from the market Add tokens NFC is not available on your device + About NFT + NFT asset %d item %d items @@ -512,27 +531,37 @@ NFT collections Some data may not load Temporary loading problems + Base information + Chain + Contract Address + Last sale price + Rarity label + Rarity rank + Token Address + Token ID + Token Standard + Traits No results. Please try another request. + No collection + Available + Choose network Receive NFT - To My wallet + You haven\'t added this network yet. To start receiving NFTs, add it to the main screen! + Network not added + Not Added + Send NFT + Traits %1$d NFTs in %2$d collection Tap here to receive first NFT NFT collections Unable to load the data - Choose network + To use the %1$s network, you must pay the account reserve (%2$s %3$s), which locks up and hides that amount indefinitely + Destination account is not active. Send %s or more to activate the account. + To create account send funds to this address + The destination account does not have a trustline for the asset being sent. Join Now Share your code - earn 5 USDT per sale. Your friend gets 10% OFF. Get REWARDS for every friend! - Last sale price - Rarity label - Rarity rank - Traits - Base information - Token Standard - Contract Address - Token ID - Token Address - Chain Set up a single access code to protect all your devices. Protect Set an individual access code for each card or ring later. @@ -743,6 +772,12 @@ Destination Tag Enter address Address is the same as wallet address + Minimum amount is %s + Minimum change is %s + Invalid Fee + Minimum balance is %s + Target account is not created. Amount to send should be %s + fee or more + Unknown error Invalid Memo. It won\'t be added to the transaction. Memo Check your network connection @@ -800,8 +835,12 @@ including a network fee of %1$s Transaction has been successfully signed and sent to the blockchain node. Wallet balance will be updated in a while %1$s is an asset in the Tron network. To calculate the fee and make a transaction you need to deposit some Tron (TRX) in your account. + Amount exceeds balance A destination tag (memo) is required to complete this transaction for the specified address. Destination Tag Required + Invalid amount + Fee exceeds balance + Total amount exceeds balance Transaction sent Prepare to scan card or ring you want to set up. Forget wallet @@ -812,16 +851,16 @@ Unstaking amount will be rounded to %1$s TRX due to network rules. Claim unstaked Stake account fee - A staking account is a special account where staked SOL tokens are stored. It is created when you delegate your tokens to a validator to participate in transaction validation and earn rewards. A small fee is charged for creating the staking account, which is returned after the staking is completed. + A staking account is a special account where staked SOL tokens are stored. It is created when you delegate your tokens to a validator to participate in transaction validation and receive rewards. A small fee is charged for creating the staking account, which is returned after the staking is completed. Annual percentage rate The annual percentage return you can earn from participating in staking. APR Rewards automatically accumulate in your staking balance daily. Available Average Reward Rate - What is Staking? + How Staking Works? %s est. profit - Market rating + Market position Metrics According to %1$s network rules, claims are possible from %2$s. Amounts below will be credited to your account upon unstaking. Minimum Requirement @@ -847,15 +886,15 @@ When staking on the Cardano network, your entire balance is used. An additional 2 ADA will be reserved and returned after unstaking. Your ADA remains unlocked while staking. ADA Staking Details Earned rewards will be sent to your wallet and available for use immediately - Stake securely and start earning your rewards - Stake securely and start earning daily rewards - Stake securely and start earning hourly rewards - Stake securely and start earning monthly rewards - Staking allows you to earn %1$s. Your staking rewards arrive every day. - Staking allows you to earn %1$s. Your staking rewards arrive every hour. - Staking allows you to earn %1$s. Your staking rewards arrive every month. - Staking allows you to earn %1$s. Your staking rewards arrive every week. - Stake securely and start earning weekly rewards + Stake securely and start receiving your rewards + Stake securely and start receiving daily rewards + Stake securely and start receiving hourly rewards + Stake securely and start receiving monthly rewards + Staking allows you to receive %1$s. Your staking rewards arrive every day. + Staking allows you to receive %1$s. Your staking rewards arrive every hour. + Staking allows you to receive %1$s. Your staking rewards arrive every month. + Staking allows you to receive %1$s. Your staking rewards arrive every week. + Stake securely and start receiving weekly rewards Earn staking rewards Your remaining staked balance will be too low to unstake. You’ll need to stake more to meet the minimum unstake amount. Low staked balance @@ -871,6 +910,11 @@ Restake lets you move your funds from one validator to another without the need to unstake You’re about to stake your entire balance. We recommend leaving a small amount to cover network fees for unstaking or claiming rewards. To start staking in TON, first make an outgoing transaction of any amount — this will activate your wallet. + In addition to the network fee, up to 0.2 TON is needed to complete all steps of the transaction. Unused amount will be returned after it\'s finished. + 0.2 TON is required to proceed with this operation, in addition to the network fee. Please top up your balance. + 0.2 Ton Reserved + This action will close other positions or switch them to withdrawal status, according to network rules. + Positions status Unlock your money to withdraw it from staking process. Unlocking takes %s. Your funds will be available for use after the 21-day unbonding period. Reward will be withdrawn along with your unstaking funds. Your funds will be available for use after the %s unbonding period. @@ -932,7 +976,7 @@ Use it on the go, anywhere, anytime. No wires or batteries. Just tap the card or ring to your phone when you need your crypto. The Wallet for Everyone Meet Tangem - Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services + More than 100 decentralized service integrations are available Web 3.0 Compatible An incoming transaction of at least %1$s is required to proceed Insufficient funds @@ -986,8 +1030,8 @@ You are about to hide this token from the main screen. You can add it back anytime through the manage tokens page. Hide %s Hide token - Staking allows you to earn %1$s and get rewards every %2$s days - Earn up to %s staking rewards yearly + Staking allows you to receive %1$s and get rewards every %2$s days + Staking Service %1$s token in %%image%% %2$s network Token in %%image%% %1$s network The %1$s (%2$s) token is the main currency on the %3$s network and cannot be hidden as long as you have other tokens on this network in the list @@ -1070,6 +1114,7 @@ Set up a 4-digit code. 
It will be used for payments. PIN code Create PIN Code + PIN was not accepted. Try again or use a different code. Invalid PIN: avoid sequences or repeats You\'re good to go! Prepare the Tangem card and tap to approve @@ -1101,6 +1146,7 @@ Transaction request Transaction status Type + Dispute this transaction Unlock Scan your card to unlock access Needed unlock @@ -1234,13 +1280,44 @@ This is a Testnet card. It cannot process transactions and should only be used for testing and development purposes. For testing purposes only Balance may be outdated. Refresh the page. + Unknown domain + Connect anyway + Timeout error. Please, try again later. + Failed to establish WalletConnect + This domain cannot be verified. Check the request carefully approving. + Go back to your browser and connect via WalletConnect again. + WalletConnect session was disconnected + Error code: %s. If the problem persists — feel free to contact our support. + We\'ve encountered unknown error + Tangem does not currently support a required network by %s. + Unsuported networks + Tangem support a required network by %s. + Verified domain + Wrong card or ring selected in Tangem App + We\'ve got some kind of problem + Connect + Network + Networks + Wallet + Connected networks + View your wallet balance and activity + Sign transactions without your notice + Request approval for transactions + Will not be able to + Would like to + Connection request Connections Disconnect all Text about discnected all dApps Disconect All dApps + Add the %s network to your profile for this wallet + The wallet has no required networks New connection Connect your wallet to a different dApps No sessions + This domain is flagged as unsafe by multiple security providers. Leave immediately to protect your assets + Known security risk + Wallet connect Discard You have an interrupted backup. Do you want to resume? Yes, resume @@ -1252,4 +1329,7 @@ Scan card or ring Use %s or scan a card or ring to access the app Welcome back! + No, send all + Reduce by %s XTZ + To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ diff --git a/data/settings/src/main/java/com/tangem/data/settings/DefaultSettingsRepository.kt b/data/settings/src/main/java/com/tangem/data/settings/DefaultSettingsRepository.kt index 1fdbc68282..87ea3f6639 100644 --- a/data/settings/src/main/java/com/tangem/data/settings/DefaultSettingsRepository.kt +++ b/data/settings/src/main/java/com/tangem/data/settings/DefaultSettingsRepository.kt @@ -8,12 +8,11 @@ import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getSyncOrDefault import com.tangem.datasource.local.preferences.utils.store import com.tangem.domain.settings.repositories.SettingsRepository +import com.tangem.domain.settings.usercountry.models.GB_COUNTRY import com.tangem.domain.settings.usercountry.models.UserCountry import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import timber.log.Timber import java.util.Locale @@ -108,15 +107,11 @@ internal class DefaultSettingsRepository( appPreferencesStore.store(key = PreferencesKeys.SHOULD_SHOW_MARKETS_TOOLTIP_KEY, value = !value) } - override suspend fun getUserCountryCodeSync(): UserCountry? { + override fun getUserCountryCodeSync(): UserCountry? { // If user country code is already set, return it val countryCode = userCountryFlow.value if (countryCode != null) return countryCode - coroutineScope { - launch { fetchUserCountryCode() } - } - return null } @@ -125,6 +120,12 @@ internal class DefaultSettingsRepository( override suspend fun fetchUserCountryCode() { Timber.i("Start fetching user country code") + // for GB locale avoid request geo and use device default (FCA fixes) + if (Locale.getDefault().country == GB_COUNTRY.code) { + userCountryFlow.value = GB_COUNTRY + return + } + withContext(dispatchers.io) { val country = runCatching { tangemTechApi.getUserCountryCode() } .fold( diff --git a/domain/promo/build.gradle.kts b/domain/promo/build.gradle.kts index cefe592d97..61d5cb9d12 100644 --- a/domain/promo/build.gradle.kts +++ b/domain/promo/build.gradle.kts @@ -6,6 +6,7 @@ plugins { dependencies { implementation(projects.domain.promo.models) implementation(projects.domain.wallets.models) + implementation(projects.domain.settings) implementation(deps.kotlin.coroutines) implementation(deps.arrow.core) 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 786f1e9552..03a93bc23a 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 @@ -4,21 +4,49 @@ 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 +import com.tangem.domain.promo.models.StoryContentIds +import com.tangem.domain.settings.repositories.SettingsRepository +import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions +import kotlinx.coroutines.flow.* +import kotlin.time.Duration.Companion.seconds class GetStoryContentUseCase( private val promoRepository: PromoRepository, + private val settingsRepository: SettingsRepository, ) { - operator fun invoke(id: String): Flow> = promoRepository.getStoryById(id) - .map> { it.right() } - .catch { emit(it.left()) } - .onEmpty { emit(null.right()) } + operator fun invoke(id: String): Flow> { + return isFCAAllowed(id).transform { isAllowed -> + if (isAllowed) { + emitAll( + promoRepository.getStoryById(id) + .map> { it.right() } + .catch { emit(it.left()) } + .onEmpty { emit(null.right()) }, + ) + } else { + emit(null.right()) + } + } + } suspend fun invokeSync(id: String, refresh: Boolean = false): Either = Either.catch { - promoRepository.getStoryByIdSync(id, refresh) + val isFCAAllowed = isFCAAllowed(id).firstOrNull() ?: false + return@catch if (isFCAAllowed) { + promoRepository.getStoryByIdSync(id, refresh) + } else { + null + } + } + + private fun isFCAAllowed(id: String): Flow { + return if (id == StoryContentIds.STORY_FIRST_TIME_SWAP.id) { + settingsRepository.getUserCountryCode() + .filterNotNull() + .timeout(5.seconds) + .map { !it.needApplyFCARestrictions() } + } else { + flowOf(true) + } } } \ No newline at end of file diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SettingsRepository.kt b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SettingsRepository.kt index 047947701d..23b4a1756c 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SettingsRepository.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SettingsRepository.kt @@ -34,7 +34,7 @@ interface SettingsRepository { suspend fun setMarketsTooltipShown(value: Boolean) - suspend fun getUserCountryCodeSync(): UserCountry? + fun getUserCountryCodeSync(): UserCountry? fun getUserCountryCode(): StateFlow diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/usercountry/GetUserCountryUseCase.kt b/domain/settings/src/main/java/com/tangem/domain/settings/usercountry/GetUserCountryUseCase.kt index cabd6677a9..3e7f731735 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/usercountry/GetUserCountryUseCase.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/usercountry/GetUserCountryUseCase.kt @@ -31,7 +31,7 @@ class GetUserCountryUseCase( } } - suspend fun invokeSync(): Either { + fun invokeSync(): Either { return either { val userCountryCode = catch( block = { settingsRepository.getUserCountryCodeSync() }, diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/usercountry/models/UserCountry.kt b/domain/settings/src/main/java/com/tangem/domain/settings/usercountry/models/UserCountry.kt index e212b96917..c83164f088 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/usercountry/models/UserCountry.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/usercountry/models/UserCountry.kt @@ -1,5 +1,7 @@ package com.tangem.domain.settings.usercountry.models +import java.util.Locale + /** * User country * @@ -10,4 +12,12 @@ sealed class UserCountry(open val code: String) { data object Russia : UserCountry("ru") data class Other(override val code: String) : UserCountry(code) -} \ No newline at end of file +} + +fun UserCountry?.needApplyFCARestrictions(): Boolean { + val local = Locale.getDefault().country + if (local == GB_COUNTRY.code) return true + return this?.code.equals(GB_COUNTRY.code, ignoreCase = true) +} + +val GB_COUNTRY = UserCountry.Other(Locale.UK.country) \ No newline at end of file diff --git a/features/markets/impl/build.gradle.kts b/features/markets/impl/build.gradle.kts index 87db7e37d6..fded1c34bc 100644 --- a/features/markets/impl/build.gradle.kts +++ b/features/markets/impl/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { implementation(projects.domain.tokens.models) implementation(projects.domain.wallets) implementation(projects.domain.wallets.models) + implementation(projects.domain.settings) // FIXME [REDACTED_TASK_KEY] // Remove the "Buy" and "Sell" actions from the redux middleware. diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt index 3ba4dd807e..5e4e7a4d4d 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/MarketsTokenDetailsModel.kt @@ -26,6 +26,9 @@ import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.markets.* +import com.tangem.domain.settings.usercountry.GetUserCountryUseCase +import com.tangem.domain.settings.usercountry.models.UserCountry +import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions import com.tangem.features.markets.details.MarketsTokenDetailsComponent import com.tangem.features.markets.details.impl.analytics.MarketDetailsAnalyticsEvent import com.tangem.features.markets.details.impl.model.converters.DescriptionConverter @@ -49,6 +52,7 @@ import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import org.joda.time.DateTime import java.math.BigDecimal +import java.util.Locale import javax.inject.Inject @Suppress("LargeClass", "LongParameterList") @@ -66,9 +70,11 @@ internal class MarketsTokenDetailsModel @Inject constructor( private val urlOpener: UrlOpener, private val analyticsEventHandler: AnalyticsEventHandler, private val excludedBlockchains: ExcludedBlockchains, + private val getUserCountryUseCase: GetUserCountryUseCase, ) : Model() { private var quotesJob = JobHolder() + private var userCountry: UserCountry? = null private val params = paramsContainer.require() private val analyticsEventBuilder = MarketDetailsAnalyticsEvent.EventBuilder(token = params.token) @@ -121,6 +127,9 @@ internal class MarketsTokenDetailsModel @Inject constructor( ), ) }, + needApplyFCARestrictions = Provider { + userCountry.needApplyFCARestrictions() + }, // ================== ) @@ -130,6 +139,9 @@ internal class MarketsTokenDetailsModel @Inject constructor( // === Analytics === analyticsEventHandler.send(analyticsEventBuilder.readMoreClicked()) }, + needApplyFCARestrictions = Provider { + userCountry.needApplyFCARestrictions() + }, onGeneratedAINotificationClick = { modelScope.launch { sendFeedbackEmailUseCase( @@ -231,6 +243,8 @@ internal class MarketsTokenDetailsModel @Inject constructor( private val loadChartJobHolder = JobHolder() init { + userCountry = getUserCountryUseCase.invokeSync().getOrNull() + ?: UserCountry.Other(Locale.getDefault().country) // reload screen if currency changed modelScope.launch { currentAppCurrency diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/DescriptionConverter.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/DescriptionConverter.kt index e2e8e6f985..f1e55176d1 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/DescriptionConverter.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/DescriptionConverter.kt @@ -8,15 +8,18 @@ import com.tangem.domain.markets.TokenMarketInfo import com.tangem.features.markets.details.impl.ui.state.InfoBottomSheetContent import com.tangem.features.markets.details.impl.ui.state.MarketsTokenDetailsUM import com.tangem.features.markets.impl.R +import com.tangem.utils.Provider import com.tangem.utils.converter.Converter @Stable internal class DescriptionConverter( private val onReadModeClicked: (InfoBottomSheetContent) -> Unit, private val onGeneratedAINotificationClick: () -> Unit, + private val needApplyFCARestrictions: Provider, ) : Converter { override fun convert(value: TokenMarketInfo): MarketsTokenDetailsUM.Description? { + if (needApplyFCARestrictions()) return null return value.shortDescription?.let { desc -> MarketsTokenDetailsUM.Description( shortDescription = stringReference(desc), diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/TokenMarketInfoConverter.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/TokenMarketInfoConverter.kt index 85c354906a..8f67567773 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/TokenMarketInfoConverter.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/details/impl/model/converters/TokenMarketInfoConverter.kt @@ -16,6 +16,7 @@ import com.tangem.utils.converter.Converter @Suppress("LongParameterList") internal class TokenMarketInfoConverter( private val appCurrency: Provider, + private val needApplyFCARestrictions: Provider, private val onInfoClick: (TangemBottomSheetConfigContent) -> Unit, private val onListedOnClick: (Int) -> Unit, onSecurityScoreInfoClick: (SecurityScoreBottomSheetContent) -> Unit, @@ -49,9 +50,19 @@ internal class TokenMarketInfoConverter( ) val exchangesAmount = value.exchangesAmount + val insights = if (needApplyFCARestrictions()) { + null + } else { + value.insights?.let { insightsConverter.convert(it) } + } + val securityScore = if (needApplyFCARestrictions()) { + null + } else { + value.securityData?.let { securityScoreConverter.convert(it) } + } return MarketsTokenDetailsUM.InformationBlocks( - insights = value.insights?.let { insightsConverter.convert(it) }, - securityScore = value.securityData?.let { securityScoreConverter.convert(it) }, + insights = insights, + securityScore = securityScore, metrics = value.metrics?.let { metricsConverter.convert(it) }, pricePerformance = value.pricePerformance?.let { pricePerformanceConverter.convert( diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceive.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceive.kt index 69acaeef22..56ad2eeddb 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceive.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceive.kt @@ -33,7 +33,6 @@ internal fun NFTReceive(state: NFTReceiveUM, modifier: Modifier = Modifier) { onIconClicked = state.onBackClick, ), title = stringResourceSafe(id = R.string.nft_receive_title), - subtitle = stringResourceSafe(id = R.string.nft_receive_subtitle), ) }, content = { innerPadding -> diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt index ea142aa30f..6a367639cb 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt @@ -21,6 +21,9 @@ import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent import com.tangem.domain.onramp.model.OnrampPaymentMethod import com.tangem.domain.onramp.model.OnrampProviderWithQuote import com.tangem.domain.onramp.model.error.OnrampError +import com.tangem.domain.settings.usercountry.GetUserCountryUseCase +import com.tangem.domain.settings.usercountry.models.UserCountry +import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodUM import com.tangem.features.onramp.providers.SelectProviderComponent @@ -37,6 +40,7 @@ import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import timber.log.Timber import java.math.BigDecimal +import java.util.Locale import javax.inject.Inject @Suppress("LongParameterList") @@ -48,6 +52,7 @@ internal class SelectProviderModel @Inject constructor( private val getOnrampSelectedPaymentMethodUseCase: GetOnrampSelectedPaymentMethodUseCase, private val getOnrampProviderWithQuoteUseCase: GetOnrampProviderWithQuoteUseCase, private val saveSelectedPaymentMethod: OnrampSaveSelectedPaymentMethod, + private val getUserCountryUseCase: GetUserCountryUseCase, paramsContainer: ParamsContainer, ) : Model() { @@ -56,7 +61,12 @@ internal class SelectProviderModel @Inject constructor( private val params: SelectProviderComponent.Params = paramsContainer.require() private val _state = MutableStateFlow(getInitialState()) + private var userCountry: UserCountry? = null + init { + userCountry = getUserCountryUseCase.invokeSync().getOrNull() + ?: UserCountry.Other(Locale.getDefault().country) + analyticsEventHandler.send(OnrampAnalyticsEvent.ProvidersScreenOpened) getPaymentMethods() getProviders(params.selectedPaymentMethod) @@ -202,7 +212,8 @@ internal class SelectProviderModel @Inject constructor( val rateDiff = bestProvider?.toAmount?.value?.let { bestRate -> BigDecimal.ONE - quote.toAmount.value / bestRate } - val isBestProvider = quote == bestProvider && hasBestProvider + val isBestProvider = + quote == bestProvider && hasBestProvider && !userCountry.needApplyFCARestrictions() val providerResult = SelectProviderResult.ProviderWithQuote( paymentMethod = quote.paymentMethod, provider = quote.provider, @@ -253,7 +264,7 @@ internal class SelectProviderModel @Inject constructor( onClick = { onProviderSelected( result = providerResult, - isBestRate = bestProvider == quote, + isBestRate = bestProvider == quote && !userCountry.needApplyFCARestrictions(), ) params.onDismiss() }, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt index 45ee5db07e..c4c8f072a3 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt @@ -117,7 +117,7 @@ internal class SetInitialDataStateTransformer( startText = TextReference.Res(R.string.staking_details_annual_percentage_rate), endText = getAprRange(validators), iconClick = { clickIntents.onInfoClick(InfoType.ANNUAL_PERCENTAGE_RATE) }, - isEndTextHighlighted = true, + isEndTextHighlighted = false, ) } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt index 99b5c966bd..ca16207365 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingClaimRewardsValidatorContent.kt @@ -16,8 +16,9 @@ import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.percent import com.tangem.core.ui.res.TangemTheme import com.tangem.features.staking.impl.R -import com.tangem.features.staking.impl.presentation.state.StakingStates import com.tangem.features.staking.impl.presentation.model.StakingClickIntents +import com.tangem.features.staking.impl.presentation.state.BalanceState +import com.tangem.features.staking.impl.presentation.state.StakingStates import com.tangem.utils.extensions.orZero @Composable @@ -37,16 +38,7 @@ internal fun StakingClaimRewardsValidatorContent( key(item.title.resolveReference() + index) { InputRowImageInfo( subtitle = item.title, - caption = combinedReference( - resourceReference(R.string.staking_details_apr), - annotatedReference { - appendSpace() - appendColored( - text = item.validator?.apr.orZero().format { percent() }, - color = TangemTheme.colors.text.accent, - ) - }, - ), + caption = item.getAprTextNeutral(), infoTitle = item.formattedFiatAmount, infoSubtitle = item.formattedCryptoAmount, imageUrl = item.validator?.image.orEmpty(), @@ -64,4 +56,26 @@ internal fun StakingClaimRewardsValidatorContent( } } } -} \ No newline at end of file +} + +/** + * For FCA fixes remove coloring for now + */ +@Suppress("UnusedPrivateMember") +@Composable +private fun BalanceState.getAprTextColored() = combinedReference( + resourceReference(R.string.staking_details_apr), + annotatedReference { + appendSpace() + appendColored( + text = validator?.apr.orZero().format { percent() }, + color = TangemTheme.colors.text.accent, + ) + }, +) + +@Composable +private fun BalanceState.getAprTextNeutral() = combinedReference( + resourceReference(R.string.staking_details_apr), + stringReference(" " + validator?.apr.orZero().format { percent() }), +) \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt index 5e8683d6a9..e984f97d3d 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingInitialInfoContent.kt @@ -264,7 +264,7 @@ private fun ActiveStakingBlock( val (icon, iconTint) = balance.type.getIcon() InputRowImageInfo( subtitle = balance.title, - caption = balance.subtitle ?: balance.getAprText(), + caption = balance.subtitle ?: balance.getAprTextNeutral(), infoTitle = balance.formattedFiatAmount.orMaskWithStars(isBalanceHidden), infoSubtitle = balance.formattedCryptoAmount.orMaskWithStars(isBalanceHidden), imageUrl = balance.getImage(), @@ -301,8 +301,12 @@ private fun StakeButtonBlock(buttonState: NavigationButtonsState) { } } +/** + * For FCA fixes remove coloring for now + */ +@Suppress("UnusedPrivateMember") @Composable -private fun BalanceState.getAprText() = combinedReference( +private fun BalanceState.getAprTextColored() = combinedReference( resourceReference(R.string.staking_details_apr), annotatedReference { appendSpace() @@ -313,6 +317,12 @@ private fun BalanceState.getAprText() = combinedReference( }, ) +@Composable +private fun BalanceState.getAprTextNeutral() = combinedReference( + resourceReference(R.string.staking_details_apr), + stringReference(" " + validator?.apr.orZero().format { percent() }), +) + @Composable private fun BalanceType.getIcon() = when (this) { BalanceType.UNSTAKING -> R.drawable.ic_connection_18 to TangemTheme.colors.icon.accent diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt index a525deb6df..3c842275b6 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingValidatorListContent.kt @@ -27,11 +27,12 @@ import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.percent import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.domain.staking.model.stakekit.Yield import com.tangem.features.staking.impl.R +import com.tangem.features.staking.impl.presentation.model.StakingClickIntents import com.tangem.features.staking.impl.presentation.state.StakingStates import com.tangem.features.staking.impl.presentation.state.previewdata.ValidatorStatePreviewData import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub -import com.tangem.features.staking.impl.presentation.model.StakingClickIntents import com.tangem.utils.extensions.orZero /** @@ -62,16 +63,7 @@ internal fun StakingValidatorListContent( InputRowImageSelector( subtitle = stringReference(item.name), - caption = combinedReference( - resourceReference(R.string.staking_details_annual_percentage_rate), - annotatedReference { - appendSpace() - appendColored( - text = item.apr.orZero().format { percent() }, - color = TangemTheme.colors.text.accent, - ) - }, - ), + caption = item.getAprTextNeutral(), imageUrl = item.image.orEmpty(), isSelected = item == state.chosenValidator, onSelect = { clickIntents.onValidatorSelect(item) }, @@ -108,6 +100,28 @@ internal fun StakingValidatorListContent( } } +/** + * For FCA fixes remove coloring for now + */ +@Suppress("UnusedPrivateMember") +@Composable +private fun Yield.Validator.getAprTextColored() = combinedReference( + resourceReference(R.string.staking_details_annual_percentage_rate), + annotatedReference { + appendSpace() + appendColored( + text = apr.orZero().format { percent() }, + color = TangemTheme.colors.text.accent, + ) + }, +) + +@Composable +private fun Yield.Validator.getAprTextNeutral() = combinedReference( + resourceReference(R.string.staking_details_annual_percentage_rate), + stringReference(" " + apr.orZero().format { percent() }), +) + @Composable private fun RowScope.ValidatorLabel(isStrategicPartner: Boolean) { if (isStrategicPartner) { diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt index 3d5cc0310a..6e2d13e5e0 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/block/ValidatorBlock.kt @@ -40,16 +40,30 @@ internal fun ValidatorBlock(validatorState: StakingStates.ValidatorState, isClic InputRowImageInfo( title = resourceReference(R.string.staking_validator), subtitle = stringReference(state.chosenValidator.name), - infoTitle = annotatedReference { - append(resourceReference(R.string.staking_details_apr).resolveReference()) - appendSpace() - appendColored( - text = state.chosenValidator.apr.orZero().format { percent() }, - color = TangemTheme.colors.text.accent, - ) - }, + infoTitle = state.getInfoTitleNeutral(), imageUrl = state.chosenValidator.image.orEmpty(), onImageError = { ValidatorImagePlaceholder() }, ) } -} \ No newline at end of file +} + +/** + * For FCA fixes remove coloring for now + */ +@Suppress("UnusedPrivateMember") +@Composable +private fun StakingStates.ValidatorState.Data.getInfoTitleColored() = combinedReference( + annotatedReference { + append(resourceReference(R.string.staking_details_apr).resolveReference()) + appendSpace() + appendColored( + text = chosenValidator.apr.orZero().format { percent() }, + color = TangemTheme.colors.text.accent, + ) + }, +) + +private fun StakingStates.ValidatorState.Data.getInfoTitleNeutral() = combinedReference( + resourceReference(R.string.staking_details_apr), + stringReference(" " + chosenValidator.apr.orZero().format { percent() }), +) \ No newline at end of file diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt index ea78698ede..50b49d4df6 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt @@ -31,6 +31,9 @@ import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.promo.GetStoryContentUseCase import com.tangem.domain.promo.ShouldShowStoriesUseCase import com.tangem.domain.promo.models.StoryContentIds +import com.tangem.domain.settings.usercountry.GetUserCountryUseCase +import com.tangem.domain.settings.usercountry.models.UserCountry +import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions import com.tangem.domain.tokens.* import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus @@ -95,6 +98,7 @@ internal class SwapModel @Inject constructor( private val getMinimumTransactionAmountSyncUseCase: GetMinimumTransactionAmountSyncUseCase, private val shouldShowStoriesUseCase: ShouldShowStoriesUseCase, private val getStoryContentUseCase: GetStoryContentUseCase, + private val getUserCountryUseCase: GetUserCountryUseCase, getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, swapInteractorFactory: SwapInteractor.Factory, private val urlOpener: UrlOpener, @@ -145,6 +149,7 @@ internal class SwapModel @Inject constructor( private val lastAmount = mutableStateOf(INITIAL_AMOUNT) private val lastReducedBalanceBy = mutableStateOf(BigDecimal.ZERO) private var swapRouter: SwapRouter = SwapRouter(router = router) + private var userCountry: UserCountry? = null private val isUserResolvableError: (SwapState) -> Boolean = { it is SwapState.SwapError && @@ -163,10 +168,13 @@ internal class SwapModel @Inject constructor( get() = swapRouter.currentScreen init { + userCountry = getUserCountryUseCase.invokeSync().getOrNull() + ?: UserCountry.Other(Locale.getDefault().country) modelScope.launch { initStories() swapRouter.openScreen(SwapNavScreen.PromoStories) } + modelScope.launch(dispatchers.io) { val fromStatus = getCryptoCurrencyStatusUseCase(userWalletId, initialCurrencyFrom.id).getOrNull() val toStatus = initialCurrencyTo?.let { getCryptoCurrencyStatusUseCase(userWalletId, it.id).getOrNull() } @@ -441,6 +449,7 @@ internal class SwapModel @Inject constructor( isNeedBestRateBadge = dataState.lastLoadedSwapStates.consideredProvidersStates().size > 1, selectedFeeType = dataState.selectedFee?.feeType ?: FeeType.NORMAL, isReverseSwapPossible = isReverseSwapPossible(), + needApplyFCARestrictions = userCountry.needApplyFCARestrictions(), ) if (uiState.notifications.any { it is SwapNotificationUM.Error.UnableToCoverFeeWarning }) { analyticsEventHandler.send( diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index f177785284..4be56e4101 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -253,6 +253,7 @@ internal class StateBuilder( isNeedBestRateBadge: Boolean, selectedFeeType: FeeType, isReverseSwapPossible: Boolean, + needApplyFCARestrictions: Boolean, ): SwapStateHolder { if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder @@ -346,6 +347,7 @@ internal class StateBuilder( ChangeCardsButtonState.DISABLED }, providerState = swapProvider.convertToContentClickableProviderState( + needApplyFCARestrictions = needApplyFCARestrictions, isBestRate = bestRatedProviderId == swapProvider.providerId, fromTokenInfo = quoteModel.fromTokenInfo, toTokenInfo = quoteModel.toTokenInfo, @@ -1138,6 +1140,7 @@ internal class StateBuilder( @Suppress("LongParameterList") private fun SwapProvider.convertToContentClickableProviderState( + needApplyFCARestrictions: Boolean, isBestRate: Boolean, fromTokenInfo: TokenSwapInfo, toTokenInfo: TokenSwapInfo, @@ -1158,7 +1161,7 @@ internal class StateBuilder( // val rateString = "1 $fromCurrencySymbol ≈ $rate $toCurrencySymbol" val badge = if (isRecommended) { ProviderState.AdditionalBadge.Recommended - } else if (isNeedBestRateBadge && isBestRate) { + } else if (isNeedBestRateBadge && isBestRate && !needApplyFCARestrictions) { ProviderState.AdditionalBadge.BestTrade } else { ProviderState.AdditionalBadge.Empty diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt index 7ce2014bc1..375e60ec26 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt @@ -144,10 +144,7 @@ internal object TokenDetailsPreviewData { val stakingLoadingBlock = StakingBlockUM.Loading(iconState) val stakingAvailableBlock = StakingBlockUM.StakeAvailable( - titleText = resourceReference( - id = R.string.token_details_staking_block_title, - formatArgs = wrappedList("3.27%"), - ), + titleText = resourceReference(id = R.string.token_details_staking_block_title), subtitleText = resourceReference( id = R.string.staking_notification_earn_rewards_text_period_day, formatArgs = wrappedList("Solana"), diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStakingInfoConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStakingInfoConverter.kt index 0f402c7631..9b5b230751 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStakingInfoConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStakingInfoConverter.kt @@ -7,7 +7,6 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format -import com.tangem.core.ui.format.bigdecimal.percent import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.staking.model.StakingAvailability import com.tangem.domain.staking.model.StakingEntryInfo @@ -102,12 +101,8 @@ internal class TokenDetailsStakingInfoConverter( iconState: IconState, isEnabled: Boolean, ): StakingBlockUM.StakeAvailable { - val apr = stakingEntryInfo.apr.format { percent() } return StakingBlockUM.StakeAvailable( - titleText = resourceReference( - id = R.string.token_details_staking_block_title, - formatArgs = wrappedList(apr), - ), + titleText = resourceReference(id = R.string.token_details_staking_block_title), subtitleText = resourceReference( id = R.string.staking_notification_earn_rewards_text, formatArgs = wrappedList(stakingEntryInfo.tokenSymbol), From 88cc411385e79bfb4867e1571ec495e56764e765 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 Apr 2025 11:56:36 +0300 Subject: [PATCH 13/21] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 76affe35f0..8c55070de7 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,7 +5,7 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.23-1043" +tangemBlockchainSdk = "releases-5.23-1048" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.23-456" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From bc0b01ecc2a3eeecfab87c40051b47435633199c Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 Apr 2025 14:59:29 +0500 Subject: [PATCH 14/21] Updated on 2026-08-14 --- .../feature/referral/data/ReferralRepositoryImpl.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt index 714e0e29dc..463325b671 100644 --- a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt +++ b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt @@ -29,18 +29,26 @@ internal class ReferralRepositoryImpl @Inject constructor( private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains) + // todo this quick fix of multiple api requests, make proper cache store + private val referralStatus: MutableMap = mutableMapOf() + override suspend fun getReferralData(walletId: String): ReferralData { return withContext(coroutineDispatcher.io) { - referralConverter.convert( + val referralData = referralConverter.convert( referralApi.getReferralStatus( walletId = walletId, ), ) + + referralStatus[walletId] = referralData is ReferralData.ParticipantData + referralData } } override suspend fun isReferralParticipant(userWalletId: UserWalletId): Boolean { - return getReferralData(userWalletId.stringValue) is ReferralData.ParticipantData + val isReferralParticipant = referralStatus[userWalletId.stringValue] + + return isReferralParticipant ?: getReferralData(userWalletId.stringValue) is ReferralData.ParticipantData } override suspend fun startReferral( @@ -50,6 +58,7 @@ internal class ReferralRepositoryImpl @Inject constructor( address: String, ): ReferralData { return withContext(coroutineDispatcher.io) { + referralStatus[walletId] = true referralConverter.convert( referralApi.startReferral( startReferralBody = StartReferralBody( From ffbd445677721dd670433a44fd8420869829cacb Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 Apr 2025 14:59:48 +0500 Subject: [PATCH 15/21] Updated on 2026-08-14 --- .../child/wallet/model/intents/WalletWarningsClickIntents.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 316ee31a8a..9e5139cf1b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -295,10 +295,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( if (promoId == PromoId.Referral) { val userWallet = getSelectedUserWallet() ?: return analyticsEventHandler.send(MainScreen.ReferralPromoButtonParticipate) - modelScope.launch { - shouldShowPromoWalletUseCase.neverToShow(promoId) - appRouter.push(AppRoute.ReferralProgram(userWalletId = userWallet.walletId)) - } + appRouter.push(AppRoute.ReferralProgram(userWalletId = userWallet.walletId)) } } From 640dab9c7e2760701f21f3da3cdc777774e499b0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 Apr 2025 15:20:34 +0500 Subject: [PATCH 16/21] Updated on 2026-08-14 --- .../referral/data/ReferralRepositoryImpl.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt index 463325b671..279d0632bf 100644 --- a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt +++ b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt @@ -16,6 +16,7 @@ import com.tangem.feature.referral.domain.models.ReferralData import com.tangem.feature.referral.domain.models.TokenData import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.withContext +import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject @Suppress("LongParameterList") @@ -30,7 +31,7 @@ internal class ReferralRepositoryImpl @Inject constructor( private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains) // todo this quick fix of multiple api requests, make proper cache store - private val referralStatus: MutableMap = mutableMapOf() + private val referralStatus: ConcurrentHashMap = ConcurrentHashMap() override suspend fun getReferralData(walletId: String): ReferralData { return withContext(coroutineDispatcher.io) { @@ -40,15 +41,14 @@ internal class ReferralRepositoryImpl @Inject constructor( ), ) - referralStatus[walletId] = referralData is ReferralData.ParticipantData + referralStatus[walletId] = referralData referralData } } override suspend fun isReferralParticipant(userWalletId: UserWalletId): Boolean { - val isReferralParticipant = referralStatus[userWalletId.stringValue] - - return isReferralParticipant ?: getReferralData(userWalletId.stringValue) is ReferralData.ParticipantData + val storedReferralData = referralStatus[userWalletId.stringValue] ?: getReferralData(userWalletId.stringValue) + return storedReferralData is ReferralData.ParticipantData } override suspend fun startReferral( @@ -58,8 +58,7 @@ internal class ReferralRepositoryImpl @Inject constructor( address: String, ): ReferralData { return withContext(coroutineDispatcher.io) { - referralStatus[walletId] = true - referralConverter.convert( + val referralData = referralConverter.convert( referralApi.startReferral( startReferralBody = StartReferralBody( walletId = walletId, @@ -69,6 +68,8 @@ internal class ReferralRepositoryImpl @Inject constructor( ), ), ) + referralStatus[walletId] = referralData + referralData } } From 68349b5e06513ee005e3cc6f114de060206cb3a5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 Apr 2025 13:52:28 +0300 Subject: [PATCH 17/21] Updated on 2026-08-14 --- core/res/src/main/res/values-ja/strings.xml | 42 +++++++++++---------- core/res/src/main/res/values/strings.xml | 17 +++++---- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 9492011009..bbced57b11 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -275,7 +275,7 @@ %sとの交換はできません 提供元 ステータス - Tangemは、各プロバイダーの条件に従って、サードパーティプロバイダーを介してトークンスワップを提供します。 + プロバイダーが取引を促進します プロバイダー エラーが発生しました。コード: %s エラー%1$s 。選択したプロバイダーは指定された取引を処理できません。値を%2$sに切り上げるか、変更してください。 @@ -316,11 +316,11 @@ 確認が必要です 取引ハッシュを待機中 ウォレットに追加されたすべてのトークンのリスト - 最良のレートを取得しています... + 現在のレートを取得中... 変動レート スワップ機能を使用すると、プロバイダーの%sに同意したことになります。 スワップ機能を使用すると、プロバイダーの%1$sおよび%2$sに同意したことになります。 - さらに多くのプロバイダーを追加予定です。 \nお楽しみに。 + さらに多くのプロバイダーが利用可能になる予定です プロバイダー ベストレート 最大 %s まで使用可能 @@ -415,6 +415,7 @@ このアセットは現在ウォレットで利用できません このアセットはこのウォレットでは使用できません。 追加 + APY %s 利用可能なネットワーク 私のポートフォリオ マーケット @@ -439,11 +440,14 @@ 7d 全部 経験豊富な買い手 - 格付け + 時価総額 並べ替え 上昇率上位 下落率上位 トレンド + ステーキングは暗号資産で報酬を受け取る最も簡単な方法です。 %s + もっと見る + 最大%s APYを獲得 %sについて %d取引所 @@ -647,7 +651,7 @@ 同一のカード アクセスコード %sで利用可能 - Tangemでの暗号通貨の買付は、サードパーティプロバイダーの条件に基づいて行われます。 + プロバイダーが取引を促進します 国で検索 利用不可 その他の通貨 @@ -836,16 +840,16 @@ ネットワークルールにより、ステーキング解除の量は%1$s TRX に切り上げられます。 ステーキング解除分を請求する ステーキングアカウント手数料 - ステーキングアカウントは、ステーキングされたSOLトークンが保管される特別なアカウントです。取引の検証に参加して報酬を得るために、トークンをバリデーターに委任すると、このアカウントが作成されます。ステーキングアカウントの作成には少額の手数料がかかりますが、この手数料はステーキングが完了すると返金されます。 + ステーキングアカウントとは、ステーキングされたSOLが保管される特別なアカウントです。トークンをバリデーターに委任し、取引の検証に参加して報酬を受け取る際に作成されます。ステーキングアカウントの作成には少額の手数料がかかりますが、ステーキング完了後に返金されます。 年率 ステーキングに参加することで得られる年間収益率。 APR 報酬は毎日自動的にステーキング残高に蓄積されます。 利用可能 平均報酬率 - ステーキングとは? + ステーキングの仕組み %s 推定利益 - 市場評価 + 市場格付け 指標 %1$sネットワークルールによれば、 %2$sからの請求が可能です。以下の金額は、ステーキング解除時にアカウントに入金されます。 最低要件 @@ -871,15 +875,15 @@ Cardanoネットワークでステーキングする場合、残高全体が使用されます。追加の2ADAは確保され、ステーキング解除後に返却されます。ステーキング中、ADAはロック解除されたままです。 ADAステーキングの詳細 獲得した報酬はあなたのアドレスに直接送られ、すぐ使用可能です。 - 安全にステーキングして報酬を獲得しましょう - 安全にステーキングして、報酬を毎日獲得しましょう - 安全にステーキングして、報酬を毎時間獲得しましょう - 安全にステーキングして、報酬を毎月獲得しましょう - ステーキングにより%1$sを獲得できます。ステーキング報酬は毎日受け取れます。 - ステーキングにより%1$sを獲得できます。ステーキング報酬は毎時間受け取れます。 - ステーキングにより%1$sを獲得できます。ステーキング報酬は毎月受け取れます。 - ステーキングにより%1$sを獲得できます。ステーキング報酬は毎週受け取れます。 - 安全にステーキングして、報酬を毎週獲得しましょう + Tangemで暗号資産をステーキングしよう + Tangemで暗号資産をステーキングしよう + Tangemで暗号資産をステーキングしよう + Tangemで暗号資産をステーキングしよう + ステーキングを行うと%1$sを受け取ることができます。ステーキング報酬は毎日受け取れます。 + ステーキングを行うと%1$sを受け取ることができます。ステーキング報酬は1時間ごとに受け取れます。 + ステーキングを行うと%1$sを受け取ることができます。ステーキング報酬は毎月受け取れます。 + ステーキングを行うと%1$sを受け取ることができます。ステーキング報酬は毎週受け取れます。 + Tangemで暗号資産をステーキングしよう ステーキング報酬を獲得 残りのステーキング残高が少なすぎてステーキングを解除できません。最小のステーキング解除残高を満たすには、さらにステーキングする必要があります。 ステーキング残高が低いです @@ -961,7 +965,7 @@ 外出先でも、いつでもどこでも使用できます。コードや電池は不要です。暗号資産が必要なときに、カードまたはリングをスマートフォンにタップするだけです。 すべての人のためのウォレット Tangemのご紹介 - 100種類以上の分散型サービスで、NFTの交換・購入や、借入・預金を行うことができます。 + 100以上の分散型サービスが利用可能 Web3.0対応 続行するには少なくとも%1$sの受信取引が必要です 残高不足 @@ -1015,7 +1019,7 @@ このトークンをメイン画面から非表示にします。トークンの管理ページからいつでも再度追加できます。 %sを非表示 トークンを非表示 - ステーキングにより、 %1$sを獲得し、 %2$s日ごとに報酬を受け取ることができます。 + ステーキングすると%1$sを受け取り、 %2$s日ごとに報酬を獲得できます ステーキングサービス %%image%% %2$s ネットワークの %1$s トークン %%image%% %1$sネットワーク上のトークン diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 0e73021a1e..cf9f9bf914 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -279,7 +279,7 @@ Cannot be swapped for %s Provided by Status - Tangem offers token swaps via 3rd-party providers according to each provider\'s terms + Providers facilitate transactions Provider An error occurred. Code: %s Error %1$s. The selected provider cannot process the specified transaction. Please round the value up to %2$s or change it @@ -450,7 +450,8 @@ Top Gainers Top Losers Trending - Staking is the easiest way to receive rewards on your crypto. + Staking is the easiest way to receive rewards on your crypto. %s + Show more Earn up to %s APY About %s @@ -660,7 +661,7 @@ Identical cards Access code Available with %s - Buying crypto in Tangem is powered by third-party providers on their terms. + Providers facilitate transactions Search by country Unavailable Other currencies @@ -886,15 +887,15 @@ When staking on the Cardano network, your entire balance is used. An additional 2 ADA will be reserved and returned after unstaking. Your ADA remains unlocked while staking. ADA Staking Details Earned rewards will be sent to your wallet and available for use immediately - Stake securely and start receiving your rewards - Stake securely and start receiving daily rewards - Stake securely and start receiving hourly rewards - Stake securely and start receiving monthly rewards + Stake your crypto with Tangem + Stake your crypto with Tangem + Stake your crypto with Tangem + Stake your crypto with Tangem Staking allows you to receive %1$s. Your staking rewards arrive every day. Staking allows you to receive %1$s. Your staking rewards arrive every hour. Staking allows you to receive %1$s. Your staking rewards arrive every month. Staking allows you to receive %1$s. Your staking rewards arrive every week. - Stake securely and start receiving weekly rewards + Stake your crypto with Tangem Earn staking rewards Your remaining staked balance will be too low to unstake. You’ll need to stake more to meet the minimum unstake amount. Low staked balance From 3b1add36d1871196e8b64129e89b3e0797f3457e Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 Apr 2025 13:57:20 +0300 Subject: [PATCH 18/21] Updated on 2026-08-14 --- core/res/src/main/res/values/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index cf9f9bf914..08ec35811c 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -887,15 +887,15 @@ When staking on the Cardano network, your entire balance is used. An additional 2 ADA will be reserved and returned after unstaking. Your ADA remains unlocked while staking. ADA Staking Details Earned rewards will be sent to your wallet and available for use immediately - Stake your crypto with Tangem - Stake your crypto with Tangem - Stake your crypto with Tangem - Stake your crypto with Tangem + Tangem allows users to stake their crypto + Tangem allows users to stake their crypto + Tangem allows users to stake their crypto + Tangem allows users to stake their crypto Staking allows you to receive %1$s. Your staking rewards arrive every day. Staking allows you to receive %1$s. Your staking rewards arrive every hour. Staking allows you to receive %1$s. Your staking rewards arrive every month. Staking allows you to receive %1$s. Your staking rewards arrive every week. - Stake your crypto with Tangem + Tangem allows users to stake their crypto Earn staking rewards Your remaining staked balance will be too low to unstake. You’ll need to stake more to meet the minimum unstake amount. Low staked balance From 64790a5c84997e172c1cb080d95518114ecf46ec Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 Apr 2025 19:57:59 +0500 Subject: [PATCH 19/21] Updated on 2026-08-14 --- .../send/v2/send/DefaultSendComponent.kt | 102 +++++++++++------- .../confirm/model/SendConfirmAlertFactory.kt | 3 +- .../v2/send/confirm/model/SendConfirmModel.kt | 8 +- .../features/send/v2/send/model/SendModel.kt | 24 +++-- 4 files changed, 91 insertions(+), 46 deletions(-) diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt index e7ae73cb18..e3b53feb36 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt @@ -140,27 +140,41 @@ internal class DefaultSendComponent @AssistedInject constructor( ), ) - private fun getAmountComponent(factoryContext: AppComponentContext, route: SendRoute) = SendAmountComponent( - appComponentContext = factoryContext, - params = SendAmountComponentParams.AmountParams( - state = model.uiState.value.amountUM, - currentRoute = currentRoute.filterIsInstance(), - isBalanceHidingFlow = model.isBalanceHiddenFlow, - analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY, - userWallet = model.userWallet, - appCurrency = model.appCurrency, - cryptoCurrencyStatus = model.cryptoCurrencyStatus, - callback = model, - isEditMode = route.isEditMode, - predefinedAmountValue = model.predefinedAmountValue, - ), - ) + private fun getAmountComponent(factoryContext: AppComponentContext, route: SendRoute): ComposableContentComponent { + val cryptoCurrencyStatus = model.cryptoCurrencyStatus + return if (cryptoCurrencyStatus != null) { + SendAmountComponent( + appComponentContext = factoryContext, + params = SendAmountComponentParams.AmountParams( + state = model.uiState.value.amountUM, + currentRoute = currentRoute.filterIsInstance(), + isBalanceHidingFlow = model.isBalanceHiddenFlow, + analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY, + userWallet = model.userWallet, + appCurrency = model.appCurrency, + cryptoCurrencyStatus = cryptoCurrencyStatus, + callback = model, + isEditMode = route.isEditMode, + predefinedAmountValue = model.predefinedAmountValue, + ), + ) + } else { + model.showAlertError() + getStubComponent() + } + } + @Suppress("ComplexCondition") private fun getFeeComponent(factoryContext: AppComponentContext): ComposableContentComponent { val state = model.uiState.value val sendAmount = (state.amountUM as? AmountState.Data)?.amountTextField?.cryptoAmount?.value val destinationAddress = (state.destinationUM as? DestinationUM.Content)?.addressTextField?.value - return if (sendAmount != null && destinationAddress != null) { + val cryptoCurrencyStatus = model.cryptoCurrencyStatus + val feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus + + return if (sendAmount != null && destinationAddress != null && + feeCryptoCurrencyStatus != null && cryptoCurrencyStatus != null + ) { SendFeeComponent( appComponentContext = factoryContext, params = SendFeeComponentParams.FeeParams( @@ -168,8 +182,8 @@ internal class DefaultSendComponent @AssistedInject constructor( currentRoute = currentRoute.filterIsInstance(), analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY, userWallet = model.userWallet, - cryptoCurrencyStatus = model.cryptoCurrencyStatus, - feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus, + cryptoCurrencyStatus = cryptoCurrencyStatus, + feeCryptoCurrencyStatus = feeCryptoCurrencyStatus, appCurrency = model.appCurrency, sendAmount = sendAmount, destinationAddress = destinationAddress, @@ -177,11 +191,14 @@ internal class DefaultSendComponent @AssistedInject constructor( ), ) } else { + model.showAlertError() getStubComponent() } } - private fun getConfirmComponent(factoryContext: AppComponentContext): SendConfirmComponent { + private fun getConfirmComponent(factoryContext: AppComponentContext): ComposableContentComponent { + val cryptoCurrencyStatus = model.cryptoCurrencyStatus + val feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus val predefinedAmount = params.amount val predefinedTxId = params.transactionId val predefinedAddress = params.destinationAddress @@ -196,31 +213,44 @@ internal class DefaultSendComponent @AssistedInject constructor( } else { SendConfirmComponent.Params.PredefinedValues.Empty } - return SendConfirmComponent( - appComponentContext = factoryContext, - params = SendConfirmComponent.Params( - state = model.uiState.value, - userWallet = model.userWallet, - currentRoute = currentRoute, - isBalanceHidingFlow = model.isBalanceHiddenFlow, - analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY, - cryptoCurrencyStatus = model.cryptoCurrencyStatus, - feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus, - appCurrency = model.appCurrency, - callback = model, - predefinedValues = predefinedValues, - ), - ) + return if (cryptoCurrencyStatus != null && feeCryptoCurrencyStatus != null) { + SendConfirmComponent( + appComponentContext = factoryContext, + params = SendConfirmComponent.Params( + state = model.uiState.value, + userWallet = model.userWallet, + currentRoute = currentRoute, + isBalanceHidingFlow = model.isBalanceHiddenFlow, + analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY, + cryptoCurrencyStatus = cryptoCurrencyStatus, + feeCryptoCurrencyStatus = feeCryptoCurrencyStatus, + appCurrency = model.appCurrency, + callback = model, + predefinedValues = predefinedValues, + ), + ) + } else { + model.showAlertError() + getStubComponent() + } } - private fun getStubComponent() = ComposableContentComponent { } + private fun getStubComponent() = StubComponent() + + class StubComponent : ComposableContentComponent { + @Composable + override fun Content(modifier: Modifier) { + } + } private fun onChildBack() { val isEmptyRoute = childStack.value.active.configuration == SendRoute.Empty val isEmptyStack = childStack.value.backStack.isEmpty() val isSuccess = model.uiState.value.confirmUM is ConfirmUM.Success + val isStubComponent = childStack.value.active.instance is StubComponent - if (isEmptyRoute || isEmptyStack || isSuccess) { + val isPopSend = isEmptyRoute || isEmptyStack || isSuccess || isStubComponent + if (isPopSend) { router.pop() } else { stackNavigation.pop() diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmAlertFactory.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmAlertFactory.kt index 7eb09a280d..b0b8c7aa36 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmAlertFactory.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmAlertFactory.kt @@ -16,11 +16,12 @@ internal class SendConfirmAlertFactory @Inject constructor( private val messageSender: UiMessageSender, ) { - fun getGenericErrorState(onFailedTxEmailClick: () -> Unit) { + fun getGenericErrorState(onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) { messageSender.send( DialogMessage( title = resourceReference(id = R.string.send_alert_transaction_failed_title), message = resourceReference(id = R.string.common_unknown_error), + onDismissRequest = popBack, firstAction = EventMessageAction( title = resourceReference(R.string.common_support), onClick = onFailedTxEmailClick, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt index daf5df6be6..4fbf115678 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt @@ -337,9 +337,11 @@ internal class SendConfirmModel @Inject constructor( ifLeft = { error -> Timber.e(error) _uiState.update(SendConfirmSendingStateTransformer(isSending = false)) - alertFactory.getGenericErrorState { - onFailedTxEmailClick(error.localizedMessage.orEmpty()) - } + alertFactory.getGenericErrorState( + onFailedTxEmailClick = { + onFailedTxEmailClick(error.localizedMessage.orEmpty()) + }, + ) }, ifRight = { txData -> sendTransaction(txData) diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt index 2e22376c66..40e7043074 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt @@ -47,6 +47,7 @@ import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject import kotlin.properties.Delegates @@ -89,8 +90,8 @@ internal class SendModel @Inject constructor( val isBalanceHiddenFlow = _isBalanceHiddenFlow.asStateFlow() var userWallet: UserWallet by Delegates.notNull() - var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull() - var feeCryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull() + var cryptoCurrencyStatus: CryptoCurrencyStatus? = null + var feeCryptoCurrencyStatus: CryptoCurrencyStatus? = null var appCurrency: AppCurrency = AppCurrency.Default var predefinedAmountValue: String? = null @@ -125,6 +126,13 @@ internal class SendModel @Inject constructor( _uiState.update { sendUM } } + fun showAlertError() { + sendConfirmAlertFactory.getGenericErrorState( + onFailedTxEmailClick = ::onFailedTxEmailClick, + popBack = router::pop, + ) + } + private fun initAppCurrency() { modelScope.launch { appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default } @@ -145,7 +153,8 @@ internal class SendModel @Inject constructor( ) }, ifLeft = { - sendConfirmAlertFactory.getGenericErrorState(::onFailedTxEmailClick) + Timber.w(it.toString()) + showAlertError() return@launch }, ) @@ -176,9 +185,12 @@ internal class SendModel @Inject constructor( ) }, ifLeft = { - sendConfirmAlertFactory.getGenericErrorState { - onFailedTxEmailClick(it.toString()) - } + sendConfirmAlertFactory.getGenericErrorState( + onFailedTxEmailClick = { + onFailedTxEmailClick(it.toString()) + }, + popBack = router::pop, + ) }, ) }.launchIn(modelScope) From 0edde23db1ee42bf09b9ace94ea9631ab7a04c7b Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 29 Apr 2025 15:40:07 +0000 Subject: [PATCH 20/21] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 8c55070de7..0d1f7d70f6 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,9 +5,9 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.23-1048" +tangemBlockchainSdk = "develop-1051" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.23-456" +tangemCardSdk = "develop-455" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem12" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ @@ -21,4 +21,4 @@ card-core = { module = "com.tangem.tangem-sdk-kotlin:core", version.ref = "tange vico-compose = { group = "com.tangem.vico", name = "compose", version.ref = "tangemVico" } vico-compose-m3 = { group = "com.tangem.vico", name = "compose-m3", version.ref = "tangemVico" } -vico-core = { group = "com.tangem.vico", name = "core", version.ref = "tangemVico" } +vico-core = { group = "com.tangem.vico", name = "core", version.ref = "tangemVico" } \ No newline at end of file From bef13c837f0dedb0caee1b021e2b1a4fc8ccfab6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 30 Apr 2025 13:29:28 +0300 Subject: [PATCH 21/21] Updated on 2026-08-14 --- core/res/src/main/res/values-es/strings.xml | 3 +++ core/res/src/main/res/values-ja/strings.xml | 12 +++++++----- core/res/src/main/res/values-uk-rUA/strings.xml | 3 +++ core/res/src/main/res/values/strings.xml | 15 +++++++++++++++ .../features/send/v2/send/DefaultSendComponent.kt | 6 +++--- .../sendnft/confirm/model/NFTSendConfirmModel.kt | 6 +++--- .../send/v2/sendnft/model/NFTSendModel.kt | 7 ++++--- .../model/intents/WalletWarningsClickIntents.kt | 2 +- .../ui/common/WcTransactionRequestButtons.kt | 2 +- gradle/tangem_dependencies.toml | 4 ++-- 10 files changed, 42 insertions(+), 18 deletions(-) diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 0bd26c5acb..9bb0a97146 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -514,6 +514,9 @@ La cuenta de destino no está activa. Envíe %s o más para activar la cuenta. Para crear una cuenta, envíe fondos a esta dirección La cuenta de destino no tiene una Trustline para el activo que se envía. + Únete ahora + Comparte tu código y gana 5 USDT por venta. Tu amigo obtiene un 10% de descuento. + ¡Obtén RECOMPENSAS por cada amigo! Deba configurar un único código de acceso para proteger todss sus dispositivos. Proteger Puede configurar un código de acceso individual en cada tarjeta más adelante diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index bbced57b11..31ae60add2 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -875,15 +875,15 @@ Cardanoネットワークでステーキングする場合、残高全体が使用されます。追加の2ADAは確保され、ステーキング解除後に返却されます。ステーキング中、ADAはロック解除されたままです。 ADAステーキングの詳細 獲得した報酬はあなたのアドレスに直接送られ、すぐ使用可能です。 - Tangemで暗号資産をステーキングしよう - Tangemで暗号資産をステーキングしよう - Tangemで暗号資産をステーキングしよう - Tangemで暗号資産をステーキングしよう + Tangemでは暗号資産をステーキングできます + Tangemでは暗号資産をステーキングできます + Tangemでは暗号資産をステーキングできます + Tangemでは暗号資産をステーキングできます ステーキングを行うと%1$sを受け取ることができます。ステーキング報酬は毎日受け取れます。 ステーキングを行うと%1$sを受け取ることができます。ステーキング報酬は1時間ごとに受け取れます。 ステーキングを行うと%1$sを受け取ることができます。ステーキング報酬は毎月受け取れます。 ステーキングを行うと%1$sを受け取ることができます。ステーキング報酬は毎週受け取れます。 - Tangemで暗号資産をステーキングしよう + Tangemでは暗号資産をステーキングできます ステーキング報酬を獲得 残りのステーキング残高が少なすぎてステーキングを解除できません。最小のステーキング解除残高を満たすには、さらにステーキングする必要があります。 ステーキング残高が低いです @@ -1044,6 +1044,8 @@ バリデーター: %s 最小%s 最小取引金額は%1$sです。 + Tronネットワークの人気トークンの手数料は高めです。TRXをステーキングすると、より安く、あるいは無料で取引できます。 + Tronネットワーク手数料を節約 もう一度やり直してください 同じカードをスキャンしました。ツインウォレットを作成するには、番号%dのカードをスキャンする必要があります。 間違ったツインカードをスキャンしました。別のカードをお試しください。 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 06a4c50786..46d6b20fe8 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -526,6 +526,9 @@ Обліковий запис одержувача не активовано. Надішліть %s або більше, щоб активувати обліковий запис. Для створення акаунту надішліть кошти на цю адресу Акаунт одержувача не містить трастлайну для активу, що надсилається. + Приєднатися + Поділіться промокодом — заробіть 5 USDT з кожної покупки. Ваші друзі отримають знижку 10% на картку Tangem! + Отримуй бонуси за кожного друга! Налаштуйте єдиний код доступу для захисту всіх ваших карток або кілець Захист Встановіть індивідуальний код доступу для кожної картки або кільця пізніше. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 08ec35811c..b4b174998e 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -535,6 +535,13 @@ Base information Chain Contract Address + stub + stub + stub + stub + stub + stub + stub Last sale price Rarity label Rarity rank @@ -1056,6 +1063,8 @@ validator: %s Minimum %s The minimum transaction amount is %1$s. + Tron network fees for popular tokens are higher. Stake some TRX for cheaper or free transactions. + Save on Tron network fees Try again You\'ve scanned the same card. To create a twin wallet you need to scan the card with number %d You\'ve scanned wrong twin card. Please try another one @@ -1308,6 +1317,8 @@ Would like to Connection request Connections + Contents + Copy data Disconnect all Text about discnected all dApps Disconect All dApps @@ -1318,6 +1329,10 @@ No sessions This domain is flagged as unsafe by multiple security providers. Leave immediately to protect your assets Known security risk + Request from + Signature Type + Transaction request + Transaction request Wallet connect Discard You have an interrupted backup. Do you want to resume? diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt index e7115d568b..895ac9ac94 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt @@ -177,7 +177,7 @@ internal class DefaultSendComponent @AssistedInject constructor( analyticsCategoryName = analyticCategoryName, userWallet = model.userWallet, appCurrency = model.appCurrency, - cryptoCurrencyStatus = model.cryptoCurrencyStatus, + cryptoCurrencyStatus = cryptoCurrencyStatus, callback = model, predefinedValues = model.predefinedValues, onBackClick = { @@ -270,8 +270,8 @@ internal class DefaultSendComponent @AssistedInject constructor( currentRoute = currentRoute, isBalanceHidingFlow = model.isBalanceHiddenFlow, analyticsCategoryName = analyticCategoryName, - cryptoCurrencyStatus = model.cryptoCurrencyStatus, - feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus, + cryptoCurrencyStatus = cryptoCurrencyStatus, + feeCryptoCurrencyStatus = feeCryptoCurrencyStatus, appCurrency = model.appCurrency, callback = model, predefinedValues = predefinedValues, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/NFTSendConfirmModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/NFTSendConfirmModel.kt index 0e89448a8f..aafd0448ea 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/NFTSendConfirmModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/NFTSendConfirmModel.kt @@ -273,9 +273,9 @@ internal class NFTSendConfirmModel @Inject constructor( ifLeft = { error -> Timber.e(error) _uiState.update(NFTSendConfirmSendingStateTransformer(isSending = false)) - alertFactory.getGenericErrorState { - onFailedTxEmailClick(error.localizedMessage.orEmpty()) - } + alertFactory.getGenericErrorState( + onFailedTxEmailClick = { onFailedTxEmailClick(error.localizedMessage.orEmpty()) }, + ) }, ifRight = { txData -> sendTransaction(txData) diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt index 8146fab729..4e496e2810 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt @@ -201,9 +201,10 @@ internal class NFTSendModel @Inject constructor( } }, ifLeft = { - alertFactory.getGenericErrorState { - onFailedTxEmailClick(it.toString()) - } + alertFactory.getGenericErrorState( + onFailedTxEmailClick = { onFailedTxEmailClick(it.toString()) }, + popBack = { router.pop() }, + ) }, ) }.launchIn(modelScope) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 331ff1a56b..fbe13e7f90 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -15,7 +15,7 @@ import com.tangem.domain.feedback.GetCardInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher -import com.tangem.domain.promo.ShouldShowSwapPromoWalletUseCase +import com.tangem.domain.promo.ShouldShowPromoWalletUseCase import com.tangem.domain.promo.models.PromoId import com.tangem.domain.settings.NeverToSuggestRateAppUseCase import com.tangem.domain.settings.RemindToRateAppLaterUseCase diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/common/WcTransactionRequestButtons.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/common/WcTransactionRequestButtons.kt index 27eec41927..8451c004cb 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/common/WcTransactionRequestButtons.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/common/WcTransactionRequestButtons.kt @@ -30,7 +30,7 @@ internal fun WcTransactionRequestButtons( modifier = Modifier .fillMaxWidth() .weight(1f), - text = stringResourceSafe(R.string.wc_sign_message_button_text), + text = stringResourceSafe(R.string.common_sign), onClick = onSign, iconResId = R.drawable.ic_tangem_24, showProgress = isLoading, diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 0d1f7d70f6..8a6f485b07 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,9 +5,9 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "develop-1051" +tangemBlockchainSdk = "develop-1052" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-455" +tangemCardSdk = "develop-463" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem12" #tangemVico = "0.0.1" # Keep it! - used for local builds ^