From 6280be92689964ebd8036df8a0d751542d5b2149 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Dec 2025 11:32:11 +0300 Subject: [PATCH 01/36] Updated on 2026-08-14 --- .../CreateWalletSelectionModel.kt | 20 ------- .../entity/CreateWalletSelectionUM.kt | 6 -- .../ui/CreateWalletSelectionContent.kt | 60 ------------------- 3 files changed, 86 deletions(-) diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt index e3eab1b7e1..14265dcd96 100644 --- a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/CreateWalletSelectionModel.kt @@ -54,32 +54,12 @@ internal class CreateWalletSelectionModel @Inject constructor( style = LabelStyle.ACCENT, ), description = resourceReference(R.string.wallet_add_hardware_description), - features = persistentListOf( - CreateWalletSelectionUM.Feature( - iconResId = R.drawable.ic_add_wallet_16, - title = resourceReference(R.string.wallet_add_hardware_info_create), - ), - CreateWalletSelectionUM.Feature( - iconResId = R.drawable.ic_import_seed_16, - title = resourceReference(R.string.wallet_add_import_seed_phrase), - ), - ), onClick = ::onHardwareWalletClick, ), CreateWalletSelectionUM.Block( title = resourceReference(R.string.wallet_create_mobile_title), titleLabel = null, description = resourceReference(R.string.wallet_add_mobile_description), - features = persistentListOf( - CreateWalletSelectionUM.Feature( - iconResId = R.drawable.ic_mobile_wallet_16, - title = resourceReference(R.string.hw_create_title), - ), - CreateWalletSelectionUM.Feature( - iconResId = R.drawable.ic_import_seed_16, - title = resourceReference(R.string.wallet_add_import_seed_phrase), - ), - ), onClick = ::onMobileWalletClick, ), ), diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/entity/CreateWalletSelectionUM.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/entity/CreateWalletSelectionUM.kt index 2b1adb4ca1..685efc6da4 100644 --- a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/entity/CreateWalletSelectionUM.kt +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/entity/CreateWalletSelectionUM.kt @@ -16,12 +16,6 @@ internal data class CreateWalletSelectionUM( val title: TextReference, val titleLabel: LabelUM?, val description: TextReference, - val features: ImmutableList, val onClick: () -> Unit, ) - - data class Feature( - val iconResId: Int, - val title: TextReference, - ) } \ No newline at end of file diff --git a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/ui/CreateWalletSelectionContent.kt b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/ui/CreateWalletSelectionContent.kt index 37e1523bed..067a969771 100644 --- a/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/ui/CreateWalletSelectionContent.kt +++ b/features/create-wallet-selection/impl/src/main/kotlin/com/tangem/features/createwalletselection/ui/CreateWalletSelectionContent.kt @@ -33,7 +33,6 @@ import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.createwalletselection.entity.CreateWalletSelectionUM import com.tangem.features.createwalletselection.impl.R -import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @Suppress("LongMethod") @@ -103,7 +102,6 @@ internal fun CreateWalletSelectionContent(state: CreateWalletSelectionUM, modifi .padding(top = 8.dp), title = block.title.resolveReference(), description = block.description.resolveReference(), - features = block.features, badge = block.titleLabel?.let { { Label(it) } }, @@ -126,7 +124,6 @@ private fun WalletBlock( title: String, description: String, onClick: () -> Unit, - features: ImmutableList, modifier: Modifier = Modifier, badge: @Composable (() -> Unit)? = null, ) { @@ -163,43 +160,6 @@ private fun WalletBlock( style = TangemTheme.typography.body2, color = TangemTheme.colors.text.tertiary, ) - if (features.isNotEmpty()) { - HorizontalDivider( - modifier = Modifier.padding(top = 12.dp), - thickness = 0.5.dp, - color = TangemTheme.colors.stroke.primary, - ) - features.forEach { feature -> - Feature( - feature = feature, - modifier = Modifier - .padding(top = 12.dp), - ) - } - } - } -} - -@Composable -private fun Feature(feature: CreateWalletSelectionUM.Feature, modifier: Modifier = Modifier) { - Row( - modifier = modifier, - verticalAlignment = Alignment.CenterVertically, - ) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size16), - painter = painterResource(id = feature.iconResId), - contentDescription = null, - tint = TangemTheme.colors.icon.accent, - ) - Text( - modifier = Modifier - .weight(1f, fill = false) - .padding(start = 6.dp), - text = feature.title.resolveReference(), - style = TangemTheme.typography.caption2, - color = TangemTheme.colors.text.secondary, - ) } } @@ -259,32 +219,12 @@ private fun PreviewCreateWalletContent() { style = LabelStyle.ACCENT, ), description = resourceReference(R.string.wallet_add_hardware_description), - features = persistentListOf( - CreateWalletSelectionUM.Feature( - iconResId = R.drawable.ic_add_wallet_16, - title = resourceReference(R.string.wallet_add_hardware_info_create), - ), - CreateWalletSelectionUM.Feature( - iconResId = R.drawable.ic_import_seed_16, - title = resourceReference(R.string.wallet_add_import_seed_phrase), - ), - ), onClick = { }, ), CreateWalletSelectionUM.Block( title = resourceReference(R.string.wallet_create_mobile_title), titleLabel = null, description = resourceReference(R.string.wallet_add_mobile_description), - features = persistentListOf( - CreateWalletSelectionUM.Feature( - iconResId = R.drawable.ic_mobile_wallet_16, - title = resourceReference(R.string.hw_create_title), - ), - CreateWalletSelectionUM.Feature( - iconResId = R.drawable.ic_import_seed_16, - title = resourceReference(R.string.wallet_add_import_seed_phrase), - ), - ), onClick = { }, ), ), From 8ea66c6e33e05d22c1032a3aed4b64ccc19be4af Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Dec 2025 14:00:21 +0500 Subject: [PATCH 02/36] Updated on 2026-08-14 --- .../java/com/tangem/data/wallets/hot/TangemHotWalletSigner.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/hot/TangemHotWalletSigner.kt b/data/wallets/src/main/java/com/tangem/data/wallets/hot/TangemHotWalletSigner.kt index ccef106815..58df536d84 100644 --- a/data/wallets/src/main/java/com/tangem/data/wallets/hot/TangemHotWalletSigner.kt +++ b/data/wallets/src/main/java/com/tangem/data/wallets/hot/TangemHotWalletSigner.kt @@ -64,7 +64,7 @@ class TangemHotWalletSigner @AssistedInject constructor( hotWalletId = userWallet.hotWalletId, dataToSign = dataToSign.map { signData -> val wallet = - userWallet.wallets.orEmpty().firstOrNull { it.publicKey.contentEquals(signData.publicKey) } + userWallet.wallets.orEmpty().firstOrNull { it.publicKey.contentEquals(publicKey.seedKey) } ?: return CompletionResult.Failure( TangemSdkError.ExceptionError(IllegalStateException("wallet is locked")), ) From e904e548484560b93d634f5985ed8b25861816ff Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Dec 2025 14:00:49 +0500 Subject: [PATCH 03/36] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/MainActivity.kt | 4 ++++ features/hot-wallet/impl/build.gradle.kts | 1 - .../addexistingwallet/entry/AddExistingWalletModel.kt | 9 +++++---- .../walletactivation/entry/WalletActivationModel.kt | 9 +++++---- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 690ab43218..076a21b682 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -40,6 +40,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.settings.SetGooglePayAvailabilityUseCase import com.tangem.domain.settings.SetGoogleServicesAvailabilityUseCase +import com.tangem.domain.settings.ShouldInitiallyAskPermissionUseCase import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.staking.SendUnsubmittedHashesUseCase import com.tangem.domain.wallets.legacy.UserWalletsListManager @@ -129,6 +130,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { @Inject lateinit var cardRepository: CardRepository + @Inject + lateinit var shouldInitiallyAskPermissionUseCase: ShouldInitiallyAskPermissionUseCase + @Inject lateinit var backupServiceHolder: BackupServiceHolder diff --git a/features/hot-wallet/impl/build.gradle.kts b/features/hot-wallet/impl/build.gradle.kts index 36d956f24c..380b51678e 100644 --- a/features/hot-wallet/impl/build.gradle.kts +++ b/features/hot-wallet/impl/build.gradle.kts @@ -38,7 +38,6 @@ dependencies { implementation(projects.domain.feedback) implementation(projects.domain.feedback.models) implementation(projects.domain.hotWallet) - implementation(projects.domain.notifications) /** Common */ implementation(projects.common.ui) diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt index dc5afd1b9f..cd8a7936ba 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/entry/AddExistingWalletModel.kt @@ -15,8 +15,8 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.DialogMessage import com.tangem.core.ui.message.EventMessageAction import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.settings.ShouldAskPermissionUseCase import com.tangem.domain.hotwallet.SetAccessCodeSkippedUseCase -import com.tangem.domain.notifications.repository.NotificationsRepository import com.tangem.domain.wallets.analytics.WalletSettingsAnalyticEvents import com.tangem.features.hotwallet.addexistingwallet.entry.routing.AddExistingWalletRoute import com.tangem.features.hotwallet.addexistingwallet.im.port.AddExistingWalletImportComponent @@ -25,6 +25,7 @@ import com.tangem.features.hotwallet.accesscode.AccessCodeComponent import com.tangem.features.hotwallet.setupfinished.MobileWalletSetupFinishedComponent import com.tangem.features.hotwallet.stepper.api.HotWalletStepperComponent import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks +import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.MutableStateFlow @@ -36,7 +37,7 @@ import javax.inject.Inject internal class AddExistingWalletModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val router: Router, - private val notificationsRepository: NotificationsRepository, + private val shouldAskPermissionUseCase: ShouldAskPermissionUseCase, @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, private val trackingContextProxy: TrackingContextProxy, private val setAccessCodeSkippedUseCase: SetAccessCodeSkippedUseCase, @@ -78,8 +79,8 @@ internal class AddExistingWalletModel @Inject constructor( private fun navigateToPushNotificationsOrNext() { modelScope.launch { - val shouldAskNotificationPermissions = notificationsRepository.shouldAskNotificationPermissionsViaBs() - if (shouldAskNotificationPermissions) { + val shouldRequestPush = shouldAskPermissionUseCase(PUSH_PERMISSION) + if (shouldRequestPush) { stackNavigation.replaceAll(AddExistingWalletRoute.PushNotifications) } else { stackNavigation.replaceAll(AddExistingWalletRoute.SetupFinished) diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletactivation/entry/WalletActivationModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletactivation/entry/WalletActivationModel.kt index 2a1f014021..70cffd7a58 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletactivation/entry/WalletActivationModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/walletactivation/entry/WalletActivationModel.kt @@ -18,8 +18,8 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.DialogMessage import com.tangem.core.ui.message.EventMessageAction import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.settings.ShouldAskPermissionUseCase import com.tangem.domain.hotwallet.SetAccessCodeSkippedUseCase -import com.tangem.domain.notifications.repository.NotificationsRepository import com.tangem.domain.wallets.analytics.WalletSettingsAnalyticEvents import com.tangem.features.hotwallet.manualbackup.check.ManualBackupCheckComponent import com.tangem.features.hotwallet.manualbackup.completed.ManualBackupCompletedComponent @@ -28,6 +28,7 @@ import com.tangem.features.hotwallet.manualbackup.start.ManualBackupStartCompone import com.tangem.features.hotwallet.accesscode.AccessCodeComponent import com.tangem.features.hotwallet.setupfinished.MobileWalletSetupFinishedComponent import com.tangem.features.hotwallet.walletactivation.entry.routing.WalletActivationRoute +import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.features.hotwallet.WalletActivationComponent import com.tangem.features.hotwallet.stepper.api.HotWalletStepperComponent import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks @@ -43,7 +44,7 @@ internal class WalletActivationModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, private val router: Router, - private val notificationsRepository: NotificationsRepository, + private val shouldAskPermissionUseCase: ShouldAskPermissionUseCase, private val setAccessCodeSkippedUseCase: SetAccessCodeSkippedUseCase, @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, private val trackingContextProxy: TrackingContextProxy, @@ -117,8 +118,8 @@ internal class WalletActivationModel @Inject constructor( private fun navigateToPushNotificationsOrNext() { modelScope.launch { - val shouldAskNotificationPermissions = notificationsRepository.shouldAskNotificationPermissionsViaBs() - if (shouldAskNotificationPermissions) { + val shouldRequestPush = shouldAskPermissionUseCase(PUSH_PERMISSION) + if (shouldRequestPush) { stackNavigation.replaceAll(WalletActivationRoute.PushNotifications) } else { stackNavigation.replaceAll(WalletActivationRoute.SetupFinished) From b2fbe74220ec3fd0eb3ddc33e01d36da4d4740dd Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Dec 2025 14:01:21 +0300 Subject: [PATCH 04/36] Updated on 2026-08-14 --- .../java/com/tangem/tap/TangemApplication.kt | 2 + .../amplitude/AmplitudeAnalyticsHandler.kt | 6 +-- .../appsflyer/AppsFlyerAnalyticsClient.kt | 19 ++++++++- .../appsflyer/AppsFlyerAnalyticsHandler.kt | 39 +++++++++++++------ .../handlers/appsflyer/AppsFlyerLogClient.kt | 8 ++++ .../firebase/FirebaseAnalyticsHandler.kt | 6 +-- .../handlers/firebase/FirebaseClient.kt | 2 +- ...t => UnderscoreAnalyticsEventConverter.kt} | 2 +- .../analytics/models/AppsFlyerOnlyEvent.kt | 15 +++++++ .../models/event/OnboardingAnalyticsEvent.kt | 12 +++++- .../core/analytics/api/EventHandlerApi.kt | 6 +-- .../analytics/filter/AppsFlyerEventFilter.kt | 23 +++++++++++ .../CreateMobileWalletModel.kt | 5 +-- .../v2/common/analytics/OnboardingEvent.kt | 8 +++- 14 files changed, 121 insertions(+), 32 deletions(-) rename app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/{FirebaseAnalyticsEventConverter.kt => UnderscoreAnalyticsEventConverter.kt} (95%) create mode 100644 core/analytics/models/src/main/java/com/tangem/core/analytics/models/AppsFlyerOnlyEvent.kt create mode 100644 core/analytics/src/main/java/com/tangem/core/analytics/filter/AppsFlyerEventFilter.kt diff --git a/app/src/main/java/com/tangem/tap/TangemApplication.kt b/app/src/main/java/com/tangem/tap/TangemApplication.kt index 2815df1738..abbd2d80de 100644 --- a/app/src/main/java/com/tangem/tap/TangemApplication.kt +++ b/app/src/main/java/com/tangem/tap/TangemApplication.kt @@ -19,6 +19,7 @@ import com.tangem.common.routing.AppRouter import com.tangem.core.abtests.manager.ABTestsManager import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.api.ParamsInterceptor +import com.tangem.core.analytics.filter.AppsFlyerEventFilter import com.tangem.core.analytics.filter.OneTimeEventFilter import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam @@ -423,6 +424,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration. factory.addHandlerBuilder(AppsFlyerAnalyticsHandler.Builder()) factory.addFilter(oneTimeEventFilter) + factory.addFilter(AppsFlyerEventFilter()) val buildData = AnalyticsHandlerBuilder.Data( application = application, diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt index 1fdb08a185..a9a25c5acc 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt @@ -2,6 +2,7 @@ package com.tangem.tap.common.analytics.handlers.amplitude import com.tangem.core.analytics.api.AnalyticsHandler import com.tangem.core.analytics.api.AnalyticsUserIdHandler +import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder class AmplitudeAnalyticsHandler( @@ -9,7 +10,6 @@ class AmplitudeAnalyticsHandler( ) : AnalyticsHandler, AnalyticsUserIdHandler { override fun id(): String = ID - override fun setUserId(userId: String) { client.setUserId(userId) } @@ -18,8 +18,8 @@ class AmplitudeAnalyticsHandler( client.clearUserId() } - override fun send(eventId: String, params: Map) { - client.logEvent(eventId, params) + override fun send(event: AnalyticsEvent) { + client.logEvent(event.id, event.params) } companion object { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerAnalyticsClient.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerAnalyticsClient.kt index aa2b3b40db..755f393182 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerAnalyticsClient.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerAnalyticsClient.kt @@ -3,8 +3,10 @@ package com.tangem.tap.common.analytics.handlers.appsflyer import android.content.Context import com.appsflyer.AppsFlyerLib import com.tangem.core.analytics.api.EventLogger +import com.tangem.core.analytics.api.UserIdHolder +import com.tangem.tap.common.analytics.handlers.firebase.UnderscoreAnalyticsEventConverter -interface AppsFlyerAnalyticsClient : EventLogger +interface AppsFlyerAnalyticsClient : EventLogger, UserIdHolder internal class AppsFlyerClient( private val context: Context, @@ -13,6 +15,7 @@ internal class AppsFlyerClient( ) : AppsFlyerAnalyticsClient { private val appsFlyerLib: AppsFlyerLib = AppsFlyerLib.getInstance() + private val eventConverter = UnderscoreAnalyticsEventConverter() init { appsFlyerLib.init(key, null, context) @@ -20,7 +23,19 @@ internal class AppsFlyerClient( appsFlyerLib.start(context) } + override fun setUserId(userId: String) { + appsFlyerLib.setCustomerUserId(userId) + } + + override fun clearUserId() { + appsFlyerLib.setCustomerUserId(null) + } + override fun logEvent(event: String, params: Map) { - appsFlyerLib.logEvent(context, event, params) + appsFlyerLib.logEvent( + context, + event, + eventConverter.convertEventParams(params), + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerAnalyticsHandler.kt index bd7036b570..d9f80b3476 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerAnalyticsHandler.kt @@ -1,21 +1,38 @@ package com.tangem.tap.common.analytics.handlers.appsflyer import com.tangem.core.analytics.api.AnalyticsHandler +import com.tangem.core.analytics.api.AnalyticsUserIdHandler import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AppsFlyerIncludedEvent +import com.tangem.core.analytics.models.AppsFlyerOnlyEvent import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder class AppsFlyerAnalyticsHandler( private val client: AppsFlyerAnalyticsClient, -) : AnalyticsHandler { +) : AnalyticsHandler, AnalyticsUserIdHandler { override fun id(): String = ID - override fun send(eventId: String, params: Map) { - client.logEvent(eventId, params) + override fun send(event: AnalyticsEvent) { + when (event) { + is AppsFlyerOnlyEvent -> { + client.logEvent(event.id, event.params) + } + is AppsFlyerIncludedEvent -> { + client.logEvent( + event = AnalyticsEvent(category = event.category, event = event.appsFlyerReplacedEvent).id, + params = event.params, + ) + } + } } - override fun send(event: AnalyticsEvent) { - super.send(event) + override fun setUserId(userId: String) { + client.setUserId(userId) + } + + override fun clearUserId() { + client.clearUserId() } companion object { @@ -23,12 +40,10 @@ class AppsFlyerAnalyticsHandler( } class Builder : AnalyticsHandlerBuilder { - override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler? = null - // disabled for now until analytics strategy is defined - // when { - // !data.isDebug -> AppsFlyerClient(data.application, data.config.appsFlyerApiKey, data.config.appsAppId) - // data.isDebug && data.logConfig.appsflyer -> AppsFlyerLogClient(data.jsonConverter) - // else -> null - // }?.let { AppsFlyerAnalyticsHandler(it) } + override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler? = when { + !data.isDebug -> AppsFlyerClient(data.application, data.config.appsFlyerApiKey, data.config.appsAppId) + data.isDebug && data.logConfig.isAppsflyerLogEnabled -> AppsFlyerLogClient(data.jsonConverter) + else -> null + }?.let { AppsFlyerAnalyticsHandler(it) } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerLogClient.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerLogClient.kt index 36284bd8df..a953e00897 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerLogClient.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsflyer/AppsFlyerLogClient.kt @@ -12,4 +12,12 @@ internal class AppsFlyerLogClient( override fun logEvent(event: String, params: Map) { logger.logEvent(event, params) } + + override fun setUserId(userId: String) { + // No-op + } + + override fun clearUserId() { + // No-op + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt index 7e7106ebb4..4d662a7828 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt @@ -1,8 +1,8 @@ package com.tangem.tap.common.analytics.handlers.firebase import com.tangem.core.analytics.api.AnalyticsErrorHandler -import com.tangem.core.analytics.api.AnalyticsHandler import com.tangem.core.analytics.api.AnalyticsExceptionHandler +import com.tangem.core.analytics.api.AnalyticsHandler import com.tangem.core.analytics.api.AnalyticsUserIdHandler import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.ExceptionAnalyticsEvent @@ -25,8 +25,8 @@ class FirebaseAnalyticsHandler( client.clearUserId() } - override fun send(eventId: String, params: Map) { - client.logEvent(eventId, params) + override fun send(event: AnalyticsEvent) { + client.logEvent(event.id, event.params) } override fun sendException(event: ExceptionAnalyticsEvent) { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseClient.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseClient.kt index 6268ebf230..d982f6e7ae 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseClient.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseClient.kt @@ -20,7 +20,7 @@ internal class FirebaseClient : FirebaseAnalyticsClient { private val fbAnalytics = Firebase.analytics private val fbCrashlytics = Firebase.crashlytics - private val eventConverter = FirebaseAnalyticsEventConverter() + private val eventConverter = UnderscoreAnalyticsEventConverter() override fun setUserId(userId: String) { Firebase.analytics.setUserId(userId) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/UnderscoreAnalyticsEventConverter.kt similarity index 95% rename from app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsEventConverter.kt rename to app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/UnderscoreAnalyticsEventConverter.kt index 559fc3418b..8d4e3d1261 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsEventConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/UnderscoreAnalyticsEventConverter.kt @@ -1,6 +1,6 @@ package com.tangem.tap.common.analytics.handlers.firebase -internal class FirebaseAnalyticsEventConverter { +internal class UnderscoreAnalyticsEventConverter { fun convertEventName(event: String): String { return convertString(event, FIREBASE_EVENT_NAME_MAX_LENGTH) diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AppsFlyerOnlyEvent.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AppsFlyerOnlyEvent.kt new file mode 100644 index 0000000000..a265fcfd9f --- /dev/null +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AppsFlyerOnlyEvent.kt @@ -0,0 +1,15 @@ +package com.tangem.core.analytics.models + +/** + * Marker interface for AppsFlyer events + * Only events implementing this interface will be sent to AppsFlyer + */ +interface AppsFlyerOnlyEvent + +/** + * Marker interface for AppsFlyer included events + * Events implementing this interface will be sent to AppsFlyer along with other analytics handlers + */ +interface AppsFlyerIncludedEvent { + val appsFlyerReplacedEvent: String +} \ No newline at end of file diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/OnboardingAnalyticsEvent.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/OnboardingAnalyticsEvent.kt index f4bc6d2ca5..c1cad4c1a7 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/OnboardingAnalyticsEvent.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/OnboardingAnalyticsEvent.kt @@ -2,6 +2,8 @@ package com.tangem.core.analytics.models.event import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.AppsFlyerIncludedEvent +import com.tangem.core.analytics.models.AppsFlyerOnlyEvent sealed class OnboardingAnalyticsEvent( category: String, @@ -14,6 +16,8 @@ sealed class OnboardingAnalyticsEvent( params: Map = mapOf(), ) : OnboardingAnalyticsEvent(category = "Onboarding", event = event, params = params) { + class AppsFlyerOnlyEntryScreenView : Onboarding(event = "wallet_entry_screen_view"), AppsFlyerOnlyEvent + class Started( source: String, ) : Onboarding( @@ -64,7 +68,12 @@ sealed class OnboardingAnalyticsEvent( put("Seed Phrase Length", seedPhraseLength.toString()) } }, - ) + ), AppsFlyerIncludedEvent { + override val appsFlyerReplacedEvent = when (creationType) { + WalletCreationType.NewSeed -> "wallet_created_successfully" + WalletCreationType.SeedImport -> "wallet_imported" + } + } sealed class WalletCreationType(val value: String) { data object NewSeed : WalletCreationType(value = "New Seed") @@ -85,6 +94,7 @@ sealed class OnboardingAnalyticsEvent( AnalyticsParam.SOURCE to source, ), ) + class ButtonImportWallet : SeedPhrase("Button - Import Wallet") class ImportSeedPhraseScreenOpened : SeedPhrase("Import Seed Phrase Screen Opened") class ButtonImport : SeedPhrase("Button - Import") diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/api/EventHandlerApi.kt b/core/analytics/src/main/java/com/tangem/core/analytics/api/EventHandlerApi.kt index 08e59781a0..868a56d99c 100644 --- a/core/analytics/src/main/java/com/tangem/core/analytics/api/EventHandlerApi.kt +++ b/core/analytics/src/main/java/com/tangem/core/analytics/api/EventHandlerApi.kt @@ -27,11 +27,7 @@ interface AnalyticsHandler : AnalyticsEventHandler { fun id(): String - fun send(eventId: String, params: Map = emptyMap()) - - override fun send(event: AnalyticsEvent) { - send(event.id, event.params) - } + override fun send(event: AnalyticsEvent) } interface AnalyticsHandlerHolder { diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/filter/AppsFlyerEventFilter.kt b/core/analytics/src/main/java/com/tangem/core/analytics/filter/AppsFlyerEventFilter.kt new file mode 100644 index 0000000000..d316469bb1 --- /dev/null +++ b/core/analytics/src/main/java/com/tangem/core/analytics/filter/AppsFlyerEventFilter.kt @@ -0,0 +1,23 @@ +package com.tangem.core.analytics.filter + +import com.tangem.core.analytics.api.AnalyticsEventFilter +import com.tangem.core.analytics.api.AnalyticsHandler +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AppsFlyerIncludedEvent +import com.tangem.core.analytics.models.AppsFlyerOnlyEvent + +class AppsFlyerEventFilter : AnalyticsEventFilter { + + override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = + event is AppsFlyerOnlyEvent || event is AppsFlyerIncludedEvent + + override suspend fun canBeSent(event: AnalyticsEvent): Boolean = true + + override fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean { + return when (event) { + is AppsFlyerOnlyEvent -> handler.id() == "AppsFlyer" + is AppsFlyerIncludedEvent -> true + else -> false + } + } +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt index 0f188dfe43..1d9409b60b 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt @@ -60,9 +60,8 @@ internal class CreateMobileWalletModel @Inject constructor( init { trackingContextProxy.addHotWalletContext() - analyticsEventHandler.send( - event = OnboardingAnalyticsEvent.Onboarding.Started(source = params.source), - ) + analyticsEventHandler.send(event = OnboardingAnalyticsEvent.Onboarding.Started(source = params.source)) + analyticsEventHandler.send(event = OnboardingAnalyticsEvent.Onboarding.AppsFlyerOnlyEntryScreenView()) analyticsEventHandler.send( event = OnboardingAnalyticsEvent.SeedPhrase.CreateMobileScreenOpened(source = params.source), ) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/analytics/OnboardingEvent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/analytics/OnboardingEvent.kt index 1aa8695bab..101eb5ff04 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/analytics/OnboardingEvent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/analytics/OnboardingEvent.kt @@ -2,6 +2,7 @@ package com.tangem.features.onboarding.v2.common.analytics import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.AppsFlyerIncludedEvent sealed class OnboardingEvent( category: String, @@ -33,7 +34,12 @@ sealed class OnboardingEvent( put("Seed Phrase Length", seedPhraseLength.toString()) } }, - ) + ), AppsFlyerIncludedEvent { + override val appsFlyerReplacedEvent = when (creationType) { + WalletCreationType.NewSeed, WalletCreationType.PrivateKey -> "wallet_created_successfully" + WalletCreationType.SeedImport -> "wallet_imported" + } + } sealed class WalletCreationType(val value: String) { data object PrivateKey : WalletCreationType(value = "Private Key") From 98fa3b5ce5b437fd35120c62b43b782ca488a72c Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Dec 2025 17:06:07 +0500 Subject: [PATCH 05/36] Updated on 2026-08-14 --- .../markets/tokenlist/impl/model/MarketsListModel.kt | 4 ++-- .../features/markets/tokenlist/impl/ui/MarketsList.kt | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt index e214f30658..27fd01e1d5 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt @@ -116,7 +116,7 @@ internal class MarketsListModel @Inject constructor( flow4 = shouldShowYieldModeMarketPromoUseCase( appCurrency = currentAppCurrency.value, interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(), - ), + ).conflate(), flow5 = getUserCountryUseCase.invoke(), ) { uiItems, isInInitialLoadingErrorState, isSearchNotFoundState, isYieldModePromo, userCountry -> MarketsItemsData( @@ -134,7 +134,7 @@ internal class MarketsListModel @Inject constructor( flow3 = shouldShowYieldModeMarketPromoUseCase( appCurrency = currentAppCurrency.value, interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(), - ), + ).conflate(), flow4 = getUserCountryUseCase.invoke(), ) { uiItems, isInInitialLoadingErrorState, shouldShowYieldModePromo, userCountry -> MarketsItemsData( diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt index 0930d3c1e4..29c313fd89 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt @@ -176,14 +176,14 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif ) } - val marketsNotification = state.marketsNotificationUM AnimatedVisibility( - state.isInSearchMode.not() && - state.selectedSortBy != SortByTypeUM.YieldSupply, + state.list !is ListUM.LoadingError && + state.isInSearchMode.not() && state.selectedSortBy != SortByTypeUM.YieldSupply, ) { + val wrappedNotification = remember(this) { state.marketsNotificationUM } val showMore = stringResourceSafe(R.string.common_show_more) - when (marketsNotification) { + when (wrappedNotification) { is MarketsNotificationUM.YieldSupplyPromo -> { val description = stringResourceSafe( R.string.markets_yield_supply_banner_description, @@ -199,7 +199,7 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif } YieldSupplyInMarketsPromoNotification( - config = marketsNotification.config.copy( + config = wrappedNotification.config.copy( subtitle = clickableDescription, ), modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12), From 5bb97e290d094e940fd42743248eaac6bde90622 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Dec 2025 17:06:36 +0500 Subject: [PATCH 06/36] Updated on 2026-08-14 --- .../impl/model/TokenActionsHandler.kt | 44 +++++++++++++------ .../portfolio/impl/ui/state/QuickActionUM.kt | 2 +- .../impl/ui/state/TokenActionsBSContentUM.kt | 2 +- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt index 7561518e9f..854f6ccdcb 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/model/TokenActionsHandler.kt @@ -20,6 +20,8 @@ import com.tangem.domain.onramp.model.OnrampSource import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.domain.tokens.model.TokenActionsState +import com.tangem.domain.tokens.model.details.NavigationAction +import com.tangem.domain.yield.supply.usecase.YieldSupplyEnterStatusUseCase import com.tangem.features.markets.impl.R import com.tangem.features.markets.portfolio.impl.loader.PortfolioData import com.tangem.features.markets.portfolio.impl.ui.state.TokenActionsBSContentUM @@ -41,6 +43,7 @@ internal class TokenActionsHandler @AssistedInject constructor( private val isDemoCardUseCase: IsDemoCardUseCase, private val messageSender: UiMessageSender, private val shareManager: ShareManager, + private val yieldSupplyEnterStatusUseCase: YieldSupplyEnterStatusUseCase, ) { private val disabledActionsInDemoMode = buildSet { @@ -186,22 +189,37 @@ internal class TokenActionsHandler @AssistedInject constructor( val (userWalletId, cryptoCurrencyStatus) = cryptoCurrencyData.let { currencyData -> currencyData.userWallet.walletId to currencyData.status } - if (cryptoCurrencyStatus.value.yieldSupplyStatus?.isActive == true) { - router.push( - AppRoute.YieldSupplyActive( + val tokenEnterStatus = yieldSupplyEnterStatusUseCase(userWalletId, cryptoCurrencyStatus).getOrNull() + val isActiveYield = cryptoCurrencyStatus.value.yieldSupplyStatus?.isActive == true + + when { + tokenEnterStatus != null -> router.push( + AppRoute.CurrencyDetails( userWalletId = userWalletId, - cryptoCurrency = cryptoCurrencyStatus.currency, - apy = yieldSupplyApy, - ), - ) - } else { - router.push( - AppRoute.YieldSupplyPromo( - userWalletId = userWalletId, - cryptoCurrency = cryptoCurrencyStatus.currency, - apy = yieldSupplyApy, + currency = cryptoCurrencyStatus.currency, + navigationAction = NavigationAction.YieldSupply( + isActive = isActiveYield, + ), ), ) + isActiveYield -> { + router.push( + AppRoute.YieldSupplyActive( + userWalletId = userWalletId, + cryptoCurrency = cryptoCurrencyStatus.currency, + apy = yieldSupplyApy, + ), + ) + } + else -> { + router.push( + AppRoute.YieldSupplyPromo( + userWalletId = userWalletId, + cryptoCurrency = cryptoCurrencyStatus.currency, + apy = yieldSupplyApy, + ), + ) + } } } diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/state/QuickActionUM.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/state/QuickActionUM.kt index e0987c16e7..777dd019c1 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/state/QuickActionUM.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/state/QuickActionUM.kt @@ -44,7 +44,7 @@ internal sealed class QuickActionUM( data class YieldMode( private val apy: String, ) : QuickActionUM( - title = resourceReference(R.string.yield_module_start_earning), + title = resourceReference(R.string.common_yield_mode), description = resourceReference(R.string.yield_module_main_screen_promo_banner_message, wrappedList(apy)), icon = R.drawable.ic_analytics_up_mini_24, ) diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/state/TokenActionsBSContentUM.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/state/TokenActionsBSContentUM.kt index 078c25562f..20db6ec796 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/state/TokenActionsBSContentUM.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/impl/ui/state/TokenActionsBSContentUM.kt @@ -48,7 +48,7 @@ internal data class TokenActionsBSContentUM( iconRes = R.drawable.ic_staking_24, ), YieldMode( - text = resourceReference(R.string.yield_module_start_earning), + text = resourceReference(R.string.common_yield_mode), iconRes = R.drawable.ic_analytics_up_mini_24, ), ; From 737bb507d902f0faa0020357851b14f6f06a0ece Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 23 Dec 2025 18:54:08 +0500 Subject: [PATCH 07/36] Updated on 2026-08-14 --- .../tap/data/DefaultTangemPayStorage.kt | 11 ++++ .../tangem/datasource/api/pay/TangemPayApi.kt | 6 ++ .../request/SetTangemPayEnabledRequest.kt | 9 +++ .../response/CheckCustomerWalletResponse.kt | 1 + .../datasource/local/visa/TangemPayStorage.kt | 3 + core/res/src/main/res/values-de/strings.xml | 3 + core/res/src/main/res/values-es/strings.xml | 2 + core/res/src/main/res/values-ja/strings.xml | 2 +- core/res/src/main/res/values-ru/strings.xml | 2 +- core/res/src/main/res/values/strings.xml | 4 +- .../message/MessageBottomSheetUMV2.kt | 8 +++ .../message/MessageBottomSheetV2.kt | 57 +++++++++++++++++- .../repository/DefaultOnboardingRepository.kt | 21 ++++++- .../tokens/GetWalletTotalBalanceUseCase.kt | 4 +- .../pay/repository/OnboardingRepository.kt | 2 + .../model/intents/TangemPayClickIntents.kt | 60 +++++++++++++++++++ .../TangemPayUpdateInfoStateTransformer.kt | 51 +++++++++++----- .../state/util/TangemPayStateCreator.kt | 33 ---------- .../subscribers/TangemPayMainSubscriber.kt | 17 +----- 19 files changed, 221 insertions(+), 75 deletions(-) create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/pay/models/request/SetTangemPayEnabledRequest.kt delete mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/util/TangemPayStateCreator.kt diff --git a/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt b/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt index 80e06699c1..a6f6497a39 100644 --- a/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt +++ b/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt @@ -53,6 +53,12 @@ internal class DefaultTangemPayStorage @Inject constructor( } } + override suspend fun clearCustomerWalletAddress(userWalletId: UserWalletId) { + withContext(dispatcherProvider.io) { + appPreferencesStore.store(PreferencesKeys.getTangemPayCustomerWalletAddressKey(userWalletId), "") + } + } + override suspend fun storeAuthTokens(customerWalletAddress: String, tokens: TangemPayAuthTokens) = withContext(dispatcherProvider.io) { val json = tokensAdapter.toJson(tokens) @@ -70,6 +76,10 @@ internal class DefaultTangemPayStorage @Inject constructor( ?.let(tokensAdapter::fromJson) } + override suspend fun clearAuthTokens(customerWalletAddress: String) { + secureStorage.delete(createAuthTokensKey(customerWalletAddress)) + } + override suspend fun storeOrderId(customerWalletAddress: String, orderId: String) { withContext(dispatcherProvider.io) { appPreferencesStore.store(PreferencesKeys.getTangemPayOrderIdKey(customerWalletAddress), orderId) @@ -112,6 +122,7 @@ internal class DefaultTangemPayStorage @Inject constructor( override suspend fun clearAll(userWalletId: UserWalletId, customerWalletAddress: String) = withContext(dispatcherProvider.io) { secureStorage.delete(createAuthTokensKey(customerWalletAddress)) + appPreferencesStore.store(PreferencesKeys.getTangemPayCheckCustomerByWalletId(userWalletId), false) appPreferencesStore.store(PreferencesKeys.getTangemPayCustomerWalletAddressKey(userWalletId), "") appPreferencesStore.store(PreferencesKeys.getTangemPayOrderIdKey(customerWalletAddress), "") appPreferencesStore.store(PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress), false) diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt index 07719ff953..1054ffef58 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt @@ -29,6 +29,12 @@ interface TangemPayApi { @Path("customer_wallet_id") customerWalletId: String, ): ApiResponse + @PATCH("v1/customer/pay-enabled") + suspend fun setTangemPayEnabledStatus( + @Header("Authorization") authHeader: String, + @Body body: SetTangemPayEnabledRequest, + ): ApiResponse + @POST("v1/deeplink/validate") suspend fun validateDeeplink(@Body body: DeeplinkValidityRequest): ApiResponse diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/request/SetTangemPayEnabledRequest.kt b/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/request/SetTangemPayEnabledRequest.kt new file mode 100644 index 0000000000..c159a2418b --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/request/SetTangemPayEnabledRequest.kt @@ -0,0 +1,9 @@ +package com.tangem.datasource.api.pay.models.request + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class SetTangemPayEnabledRequest( + @Json(name = "is_tangem_pay_enabled") val isTangemPayEnabled: Boolean, +) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/response/CheckCustomerWalletResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/response/CheckCustomerWalletResponse.kt index 01ee25582c..0a522486f5 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/response/CheckCustomerWalletResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/response/CheckCustomerWalletResponse.kt @@ -9,5 +9,6 @@ data class CheckCustomerWalletResponse( ) { data class Result( @Json(name = "id") val id: String?, + @Json(name = "is_tangem_pay_enabled") val isTangemPayEnabled: Boolean?, ) } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt b/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt index a9279e9193..a048c54414 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt @@ -8,9 +8,12 @@ interface TangemPayStorage { suspend fun storeCustomerWalletAddress(userWalletId: UserWalletId, customerWalletAddress: String) suspend fun getCustomerWalletAddress(userWalletId: UserWalletId): String? + suspend fun clearCustomerWalletAddress(userWalletId: UserWalletId) + suspend fun storeAuthTokens(customerWalletAddress: String, tokens: TangemPayAuthTokens) suspend fun getAuthTokens(customerWalletAddress: String): TangemPayAuthTokens? + suspend fun clearAuthTokens(customerWalletAddress: String) suspend fun storeOrderId(customerWalletAddress: String, orderId: String) diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index af3e4fd8d7..be2b45ae50 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -1072,6 +1072,8 @@ Bitte setze das nächste Gerät zurück, um fortzufahren. Ringbesitzer erhalten bis zum 15.11. 3 provisionsfreie Swaps auf Changelly! Jetzt mit 0 % Gebühren tauschen! + Geräte mit Root-Zugriff gelten als weniger sicher. Deine Daten können zusätzlichen Risiken ausgesetzt sein. + Root-Zugriff erkannt Melde dich bei der App an und überprüfe dein Guthaben, ohne die Karte oder Ring zu scannen Zugriff auf die App Nutzung biometrischer Daten zulassen @@ -1990,6 +1992,7 @@ Gebührenpolitik Tangem erhebt außerdem eine Servicegebühr von 15% auf den erzielten Ertrag. Deine Gelder werden automatisch an Aave überwiesen, sobald die Netzwerkgebühren niedriger sind oder Dein Guthaben den erforderlichen Mindestbetrag erreicht. + Die Gebühren sind aufgrund der hohen Marktaktivität derzeit höher als üblich. Du kannst jetzt fortfahren oder später noch einmal vorbeischauen, wenn die Gebühren niedriger sind. Hohe Netzwerkgebühren Historische Renditen Aktiviere %1$s%% Jahreszins auf Dein Guthaben diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index e99920eeb5..92108a3ab5 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -916,6 +916,8 @@ El reseteo a valores de fábrica eliminará completamente la billetera de la tarjeta/anillo seleccionado y lo eliminará de la app. No podrá restaurar la billetera actual. Si tiene un Anillo Tangem, ¡3 swaps sin comisión en Changelly hasta el 15/11! ¡Intercambia con 0% de comisión! + Los dispositivos con jailbreak se consideran menos seguros. Sus datos podrían estar expuestos a riesgos adicionales. + Acceso root detectado Inicie sesión en la app y comprueba su saldo sin escanear la tarjeta o el anillo Acceder a la app Permitir el uso de biometría diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 70f1b95349..dbc266076b 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -1617,7 +1617,7 @@ ロック解除 カードをスキャンしてアクセスロックを解除する ロック解除が必要 - ウォレットの追加方法を選択してください + ウォレットの種類を選択します Tangemカードまたはリングをスキャンして復元するか、別のウォレットからインポートしてください。 ハードウェアウォレットを作成 Tangemウォレットを購入しますか? diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 036b504b45..537e6d8e15 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -1634,7 +1634,7 @@ ПИН не принят. Попробуйте ещё раз или введите другой код. Слабый ПИН: не используйте повторы или последовательности. Разблокировать - Выберите способ добавления кошелька + Выберите тип кошелька Отсканируйте вашу карту или кольцо Tangem, чтобы восстановить её или импортировать из другого кошелька. Создать аппаратный кошелёк Хотите приобрести кошелек Tangem? diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index eaddf5b46e..2598e6fe4b 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -1501,6 +1501,8 @@ Issuing your card We’re getting your card ready. This may take a little time. Tangem Pay + Confirm Cancellation + Are you sure you want to stop the KYC process? You can return to it anytime. We could not verify your profile. If you have any questions, please contact support. Unfortunately, we couldn\'t verify your identity KYC in progress @@ -1686,7 +1688,7 @@ Unlock Scan your card to unlock access Needed unlock - Choose how to add your wallet + Choose your wallet type Scan your Tangem card or ring to restore it or import from another wallet. Create Hardware Wallet Want to purchase a Tangem Wallet? diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/message/MessageBottomSheetUMV2.kt b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/message/MessageBottomSheetUMV2.kt index 0fc219bba4..a776ddd445 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/message/MessageBottomSheetUMV2.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/message/MessageBottomSheetUMV2.kt @@ -41,6 +41,9 @@ data class MessageBottomSheetUMV2( } } + @Immutable + data class IconImage(@DrawableRes internal var res: Int) : Element + @Immutable data class Chip( internal var text: TextReference, @@ -54,6 +57,7 @@ data class MessageBottomSheetUMV2( @Immutable data class InfoBlock( internal var icon: Icon? = null, + internal var iconImage: IconImage? = null, internal var chip: Chip? = null, var title: TextReference? = null, var body: TextReference? = null, @@ -106,6 +110,10 @@ fun MessageBottomSheetUMV2.InfoBlock.icon(@DrawableRes res: Int, init: MessageBo icon = MessageBottomSheetUMV2.Icon(res).apply(init) } +fun MessageBottomSheetUMV2.InfoBlock.iconImage(@DrawableRes res: Int) = apply { + iconImage = MessageBottomSheetUMV2.IconImage(res) +} + fun MessageBottomSheetUMV2.InfoBlock.chip(text: TextReference, init: MessageBottomSheetUMV2.Chip.() -> Unit = {}) = apply { chip = MessageBottomSheetUMV2.Chip(text).apply(init) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/message/MessageBottomSheetV2.kt b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/message/MessageBottomSheetV2.kt index cb3f2c538d..7b3ab2dd0b 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/message/MessageBottomSheetV2.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/message/MessageBottomSheetV2.kt @@ -1,14 +1,18 @@ package com.tangem.core.ui.components.bottomsheets.message +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -88,9 +92,7 @@ fun MessageBottomSheetV2Content(state: MessageBottomSheetUMV2, modifier: Modifie @Composable private fun ContentContainer(state: MessageBottomSheetUMV2.InfoBlock, modifier: Modifier = Modifier) { Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) { - state.icon?.let { - BottomSheetIcon(it) - } + BottomSheetIconContainer(state.icon, state.iconImage) state.title?.let { title -> Text( modifier = Modifier @@ -122,6 +124,26 @@ private fun ContentContainer(state: MessageBottomSheetUMV2.InfoBlock, modifier: } } +@Suppress("CanBeNonNullable") +@Composable +private fun BottomSheetIconContainer( + icon: MessageBottomSheetUMV2.Icon?, + iconImage: MessageBottomSheetUMV2.IconImage?, + modifier: Modifier = Modifier, +) { + if (icon != null) { + BottomSheetIcon(icon, modifier) + } else if (iconImage != null) { + Image( + modifier = modifier + .size(TangemTheme.dimens.size56) + .clip(CircleShape), + painter = painterResource(id = iconImage.res), + contentDescription = null, + ) + } +} + @Composable private fun BottomSheetIcon(icon: MessageBottomSheetUMV2.Icon, modifier: Modifier = Modifier) { val tint = when (icon.type) { @@ -236,4 +258,33 @@ private fun Preview() { onDismissRequest = {}, ) } +} + +@Preview +@Composable +private fun Preview2() { + TangemThemePreview { + MessageBottomSheetV2( + messageBottomSheetUM { + infoBlock { + iconImage = MessageBottomSheetUMV2.IconImage(R.drawable.img_visa_notification) + title = TextReference.Str("Title Title Title") + body = TextReference.Str("Body") + chip(text = TextReference.Str("Some chip information")) + } + primaryButton { + text = TextReference.Str("Test") + icon = R.drawable.ic_tangem_24 + } + secondaryButton { + icon = R.drawable.ic_tangem_24 + text = TextReference.Str("asdasd") + onClick { + closeBs() + } + } + }, + onDismissRequest = {}, + ) + } } \ No newline at end of file diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt index e11aa1c09b..79fed1dc36 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt @@ -4,6 +4,7 @@ import arrow.core.Either import com.tangem.datasource.api.pay.TangemPayApi import com.tangem.datasource.api.pay.models.request.DeeplinkValidityRequest import com.tangem.datasource.api.pay.models.request.OrderRequest +import com.tangem.datasource.api.pay.models.request.SetTangemPayEnabledRequest import com.tangem.datasource.api.pay.models.response.CustomerMeResponse import com.tangem.datasource.local.visa.TangemPayCardFrozenStateStore import com.tangem.datasource.local.visa.TangemPayStorage @@ -180,9 +181,10 @@ internal class DefaultOnboardingRepository @Inject constructor( ) }.map { response -> val id = response.result?.id - val isPaeraCustomer = !id.isNullOrEmpty() - tangemPayStorage.storeCheckCustomerWalletResult(userWalletId = userWalletId, isPaeraCustomer) - isPaeraCustomer + val isTangemPayEnabled = response.result?.isTangemPayEnabled == true + val shouldShowTangemPayBlock = !id.isNullOrEmpty() && isTangemPayEnabled + tangemPayStorage.storeCheckCustomerWalletResult(userWalletId = userWalletId, shouldShowTangemPayBlock) + shouldShowTangemPayBlock }.mapLeft { error -> if (error is VisaApiError.NotPaeraCustomer) { tangemPayStorage.storeCheckCustomerWalletResult(userWalletId = userWalletId, false) @@ -205,4 +207,17 @@ internal class DefaultOnboardingRepository @Inject constructor( override suspend fun setHideMainOnboardingBanner(userWalletId: UserWalletId) { tangemPayStorage.storeHideOnboardingBanner(userWalletId, hide = true) } + + override suspend fun disableTangemPay(userWalletId: UserWalletId): Either { + return requestHelper.performRequest(userWalletId) { authHeader -> + tangemPayApi.setTangemPayEnabledStatus( + authHeader = authHeader, + body = SetTangemPayEnabledRequest(isTangemPayEnabled = false), + ) + }.onRight { + val address = requestHelper.getCustomerWalletAddress(userWalletId) + tangemPayStorage.clearAll(userWalletId = userWalletId, customerWalletAddress = address) + setHideMainOnboardingBanner(userWalletId) + } + } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt index 18401f9621..11760b5e2f 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetWalletTotalBalanceUseCase.kt @@ -26,9 +26,9 @@ class GetWalletTotalBalanceUseCase( private val walletBalanceCache = ConcurrentHashMap() operator fun invoke( - userTallestIds: Collection, + userWalletsIds: Collection, ): LceFlow> { - val flows = userTallestIds.distinct() + val flows = userWalletsIds.distinct() .map { userWalletId -> invoke(userWalletId).map { maybeBalance -> userWalletId to maybeBalance diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt index e3fc78e653..6a304dbfbb 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt @@ -32,4 +32,6 @@ interface OnboardingRepository { suspend fun getHideMainOnboardingBanner(userWalletId: UserWalletId): Boolean suspend fun setHideMainOnboardingBanner(userWalletId: UserWalletId) + + suspend fun disableTangemPay(userWalletId: UserWalletId): Either } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt index b00b4b5886..7fc89a52ab 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt @@ -6,11 +6,14 @@ import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.res.R import com.tangem.core.ui.components.bottomsheets.message.* import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.message.DialogMessage +import com.tangem.core.ui.message.EventMessageAction import com.tangem.core.ui.message.bottomSheetMessage import com.tangem.domain.feedback.GetWalletMetaInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.pay.TangemPayDetailsConfig import com.tangem.domain.pay.repository.OnboardingRepository import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase @@ -26,6 +29,10 @@ internal interface TangemPayIntents { fun onRefreshPayToken(userWalletId: UserWalletId) + fun openDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig) + + fun onKycProgressClicked(userWalletId: UserWalletId) + fun onIssuingCardClicked() fun onIssuingFailedClicked() @@ -47,6 +54,7 @@ internal class TangemPayClickIntentsImplementor @Inject constructor( private val getWalletMetainfoUseCase: GetWalletMetaInfoUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase, + private val tangemPayOnboardingRepository: OnboardingRepository, private val uiMessageSender: UiMessageSender, ) : BaseWalletClickIntents(), TangemPayIntents { @@ -67,6 +75,51 @@ internal class TangemPayClickIntentsImplementor @Inject constructor( } } + override fun openDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig) { + router.openTangemPayDetails( + userWalletId = userWalletId, + config = config, + ) + } + + override fun onKycProgressClicked(userWalletId: UserWalletId) { + val cancelKycConfirmDialogMessage = DialogMessage( + title = resourceReference(R.string.tangempay_kyc_confirm_cancellation_alert_title), + message = resourceReference(R.string.tangempay_kyc_confirm_cancellation_description), + firstAction = EventMessageAction( + title = resourceReference(R.string.common_not_now), + onClick = { }, + ), + secondAction = EventMessageAction( + title = resourceReference(R.string.common_confirm), + onClick = { disableTangemPay(userWalletId) }, + ), + ) + val kycInfoBottomSheet = bottomSheetMessage { + infoBlock { + iconImage(res = com.tangem.core.ui.R.drawable.img_visa_notification) + title = resourceReference(R.string.tangempay_kyc_in_progress) + body = resourceReference(R.string.tangempay_kyc_in_progress_popup_description) + } + primaryButton { + text = resourceReference(R.string.tangempay_kyc_in_progress_notification_button) + onClick = { + router.openTangemPayOnboarding(AppRoute.TangemPayOnboarding.Mode.ContinueOnboarding(userWalletId)) + closeBs() + } + } + secondaryButton { + text = resourceReference(R.string.tangempay_cancel_kyc) + onClick = { + uiMessageSender.send(cancelKycConfirmDialogMessage) + closeBs() + } + } + } + + uiMessageSender.send(kycInfoBottomSheet) + } + override fun onIssuingCardClicked() { val issuingBottomSheet = bottomSheetMessage { infoBlock { @@ -132,4 +185,11 @@ internal class TangemPayClickIntentsImplementor @Inject constructor( onboardingRepository.setHideMainOnboardingBanner(userWalletId) } } + + private fun disableTangemPay(userWalletId: UserWalletId) { + modelScope.launch { + tangemPayOnboardingRepository.disableTangemPay(userWalletId) + .onRight { tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) } + } + } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayUpdateInfoStateTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayUpdateInfoStateTransformer.kt index a47a0aec3a..b6ad2482ff 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayUpdateInfoStateTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayUpdateInfoStateTransformer.kt @@ -1,5 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers +import com.tangem.common.ui.R import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.format.bigdecimal.fiat @@ -11,11 +12,10 @@ import com.tangem.domain.pay.model.CustomerInfo.ProductInstance import com.tangem.domain.pay.model.MainScreenCustomerInfo import com.tangem.domain.pay.model.OrderStatus import com.tangem.domain.visa.model.TangemPayCardFrozenState +import com.tangem.feature.wallet.child.wallet.model.intents.TangemPayIntents import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState +import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState.Progress import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState -import com.tangem.feature.wallet.presentation.wallet.state.util.TangemPayStateCreator.createCancelledState -import com.tangem.feature.wallet.presentation.wallet.state.util.TangemPayStateCreator.createIssueProgressState -import com.tangem.feature.wallet.presentation.wallet.state.util.TangemPayStateCreator.createKycInProgressState import java.util.Currency /** @@ -26,12 +26,9 @@ private const val POLYGON_CHAIN_ID = 137 internal class TangemPayUpdateInfoStateTransformer( userWalletId: UserWalletId, - private val value: MainScreenCustomerInfo? = null, + private val value: MainScreenCustomerInfo, private val cardFrozenState: TangemPayCardFrozenState, - private val onClickKyc: () -> Unit = {}, - private val onIssuingCard: () -> Unit = {}, - private val onIssuingFailed: () -> Unit = {}, - private val openDetails: (config: TangemPayDetailsConfig) -> Unit = {}, + private val tangemPayClickIntents: TangemPayIntents, ) : WalletStateTransformer(userWalletId = userWalletId) { override fun transform(prevState: WalletState): WalletState { @@ -44,16 +41,15 @@ internal class TangemPayUpdateInfoStateTransformer( } private fun createInitialState(): TangemPayState { - val cardInfo = value?.info?.cardInfo - val productInstance = value?.info?.productInstance + val cardInfo = value.info.cardInfo + val productInstance = value.info.productInstance // when statement copied to WalletTangemPayAnalyticsEventSender. Be careful when editing. return when { - value == null -> TangemPayState.Empty - value.orderStatus == OrderStatus.CANCELED -> createCancelledState(onIssuingFailed) - !value.info.isKycApproved -> createKycInProgressState(onClickKyc) + value.orderStatus == OrderStatus.CANCELED -> createCancelledState() + !value.info.isKycApproved -> createKycInProgressState() cardInfo != null && productInstance != null -> getCardInfoState(cardInfo, productInstance) - else -> createIssueProgressState(onIssuingCard) + else -> createIssueProgressState() } } @@ -63,7 +59,8 @@ internal class TangemPayUpdateInfoStateTransformer( balanceText = TextReference.Str(getBalanceText(cardInfo)), balanceSymbol = stringReference("USDC"), // TODO hardcode for now onClick = { - openDetails( + tangemPayClickIntents.openDetails( + userWalletId, TangemPayDetailsConfig( cardId = productInstance.cardId, isPinSet = cardInfo.isPinSet, @@ -82,4 +79,28 @@ internal class TangemPayUpdateInfoStateTransformer( fiat(fiatCurrencyCode = currency.currencyCode, fiatCurrencySymbol = currency.symbol) } } + + private fun createKycInProgressState(): TangemPayState = Progress( + title = TextReference.Res(R.string.tangempay_payment_account), + description = TextReference.Res(R.string.tangempay_kyc_in_progress), + buttonText = TextReference.Res(R.string.tangempay_kyc_in_progress_notification_button), + iconRes = R.drawable.ic_promo_kyc_36, + onButtonClick = { tangemPayClickIntents.onKycProgressClicked(userWalletId) }, + ) + + private fun createIssueProgressState(): TangemPayState = Progress( + title = TextReference.Res(R.string.tangempay_payment_account), + description = TextReference.Res(R.string.tangempay_issuing_your_card), + buttonText = TextReference.EMPTY, + iconRes = R.drawable.ic_tangem_pay_promo_card_36, + onButtonClick = tangemPayClickIntents::onIssuingCardClicked, + showProgress = true, + ) + + private fun createCancelledState(): TangemPayState = TangemPayState.FailedIssue( + title = TextReference.Res(R.string.tangempay_payment_account), + description = TextReference.Res(R.string.tangempay_failed_to_issue_card), + iconRes = R.drawable.ic_alert_24, + onButtonClick = tangemPayClickIntents::onIssuingFailedClicked, + ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/util/TangemPayStateCreator.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/util/TangemPayStateCreator.kt deleted file mode 100644 index 51b584d38f..0000000000 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/util/TangemPayStateCreator.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.tangem.feature.wallet.presentation.wallet.state.util - -import com.tangem.common.ui.R -import com.tangem.core.ui.extensions.TextReference -import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState -import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState.Progress - -internal object TangemPayStateCreator { - - fun createKycInProgressState(onClickKyc: () -> Unit): TangemPayState = Progress( - title = TextReference.Res(R.string.tangempay_payment_account), - description = TextReference.Res(R.string.tangempay_kyc_in_progress), - buttonText = TextReference.Res(R.string.tangempay_kyc_in_progress_notification_button), - iconRes = R.drawable.ic_promo_kyc_36, - onButtonClick = onClickKyc, - ) - - fun createIssueProgressState(onIssuingCardClick: () -> Unit): TangemPayState = Progress( - title = TextReference.Res(R.string.tangempay_payment_account), - description = TextReference.Res(R.string.tangempay_issuing_your_card), - buttonText = TextReference.EMPTY, - iconRes = R.drawable.ic_tangem_pay_promo_card_36, - onButtonClick = onIssuingCardClick, - showProgress = true, - ) - - fun createCancelledState(onIssueFailedClick: () -> Unit): TangemPayState = TangemPayState.FailedIssue( - title = TextReference.Res(R.string.tangempay_payment_account), - description = TextReference.Res(R.string.tangempay_failed_to_issue_card), - iconRes = R.drawable.ic_alert_24, - onButtonClick = onIssueFailedClick, - ) -} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt index 6a7cf0a950..8b890929a2 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt @@ -1,6 +1,5 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers -import com.tangem.common.routing.AppRoute import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.pay.model.MainCustomerInfoContentState @@ -10,7 +9,6 @@ import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase import com.tangem.domain.visa.model.TangemPayCardFrozenState import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents -import com.tangem.feature.wallet.presentation.router.InnerWalletRouter import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletTangemPayAnalyticsEventSender import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.* @@ -28,7 +26,6 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( @Assisted private val userWallet: UserWallet, private val stateController: WalletStateController, private val clickIntents: WalletClickIntents, - private val innerWalletRouter: InnerWalletRouter, private val cardDetailsRepository: TangemPayCardDetailsRepository, private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase, private val analytics: WalletTangemPayAnalyticsEventSender, @@ -102,19 +99,7 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( userWalletId = userWalletId, value = data, cardFrozenState = cardFrozenState, - onClickKyc = { - innerWalletRouter.openTangemPayOnboarding( - mode = AppRoute.TangemPayOnboarding.Mode.ContinueOnboarding(userWalletId), - ) - }, - onIssuingCard = clickIntents::onIssuingCardClicked, - onIssuingFailed = clickIntents::onIssuingFailedClicked, - openDetails = { config -> - innerWalletRouter.openTangemPayDetails( - userWalletId = userWalletId, - config = config, - ) - }, + tangemPayClickIntents = clickIntents, ), ) } From f9d1e222afc589f981b982b2cae6c329ca766dd2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 24 Dec 2025 15:14:53 +0500 Subject: [PATCH 08/36] Updated on 2026-08-14 --- .../data/yield/supply/DefaultYieldSupplyRepository.kt | 10 +++++----- .../features/markets/tokenlist/impl/ui/MarketsList.kt | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt index a40499ba87..d7faa6176a 100644 --- a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt +++ b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt @@ -27,6 +27,7 @@ import com.tangem.domain.yield.supply.models.YieldMarketToken import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus import com.tangem.domain.yield.supply.models.YieldSupplyMarketChartData import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.runSuspendCatching import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext @@ -155,7 +156,7 @@ internal class DefaultYieldSupplyRepository( override suspend fun getTokenPendingStatus( userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus, - ): YieldSupplyEnterStatus? = try { + ): YieldSupplyEnterStatus? = runSuspendCatching { val cryptoCurrency = cryptoCurrencyStatus.currency val walletManager = walletManagersFacade.getOrCreateWalletManager( userWalletId = userWalletId, @@ -174,10 +175,9 @@ internal class DefaultYieldSupplyRepository( hasRecentYieldExitTxs -> YieldSupplyEnterStatus.Exit else -> null } - } catch (e: Exception) { - Timber.e(e, "Failed to get pending yield supply status") - null - } + }.onFailure { exception -> + Timber.w(exception, "Failed to get pending yield supply status") + }.getOrNull() override fun getShouldShowYieldPromoBanner(): Flow { return appPreferencesStore.get(PreferencesKeys.YIELD_SUPPLY_SHOULD_SHOW_MAIN_PROMO_KEY, true) diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt index 29c313fd89..0a7e31ebfc 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/MarketsList.kt @@ -176,14 +176,14 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif ) } + val marketsNotificationUM = state.marketsNotificationUM AnimatedVisibility( state.list !is ListUM.LoadingError && state.isInSearchMode.not() && state.selectedSortBy != SortByTypeUM.YieldSupply, ) { - val wrappedNotification = remember(this) { state.marketsNotificationUM } val showMore = stringResourceSafe(R.string.common_show_more) - when (wrappedNotification) { + when (marketsNotificationUM) { is MarketsNotificationUM.YieldSupplyPromo -> { val description = stringResourceSafe( R.string.markets_yield_supply_banner_description, @@ -199,7 +199,7 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif } YieldSupplyInMarketsPromoNotification( - config = wrappedNotification.config.copy( + config = marketsNotificationUM.config.copy( subtitle = clickableDescription, ), modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12), From c9a7c85a896fb712c12218cef0bcd635049d42a8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 24 Dec 2025 11:57:55 +0500 Subject: [PATCH 09/36] Updated on 2026-08-14 --- core/res/src/main/res/values-ja/strings.xml | 1 - core/res/src/main/res/values/strings.xml | 1 - .../kotlin/com/tangem/features/details/utils/ItemsBuilder.kt | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index dbc266076b..5ba1fbe88a 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -422,7 +422,6 @@ トークンは誰でも作成できることに注意してください。 Tangemウォレットを購入 チャット - Tangem Visaを入手 アクセスコード カードをスキャンする前に、正しいアクセスコードを送信する必要があります。 長くタップ diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 2598e6fe4b..76cee235d8 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -430,7 +430,6 @@ Note that tokens can be created by anyone Buy Tangem Wallet Chat - Get Tangem Visa Access code You will have to submit the correct access code before scanning the card Long Tap diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt index 0cdd6b6a10..8de88bbb26 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt @@ -129,7 +129,7 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) { private fun getVisaItem(): DetailsItemUM.Basic.Item = DetailsItemUM.Basic.Item( id = "get_tangem_visa", block = BlockUM( - text = resourceReference(R.string.details_get_visa), + text = resourceReference(R.string.tangempay_get_tangem_pay), iconRes = R.drawable.ic_tangem_pay_24, onClick = { router.push(AppRoute.TangemPayOnboarding(AppRoute.TangemPayOnboarding.Mode.FromBannerInSettings)) From bbc732b01fd22eaf7f094bf130aa149072a5cc34 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 24 Dec 2025 12:29:33 +0500 Subject: [PATCH 10/36] Updated on 2026-08-14 --- .../tap/domain/tasks/visa/VisaCustomerWalletApproveTask.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/visa/VisaCustomerWalletApproveTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/visa/VisaCustomerWalletApproveTask.kt index d4c6dc4800..3f416e65e0 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/visa/VisaCustomerWalletApproveTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/visa/VisaCustomerWalletApproveTask.kt @@ -126,7 +126,8 @@ class VisaCustomerWalletApproveTask( extendedPublicKey = extendedPublicKey, ) - visaDataForApprove.sign(rsvSignature, visaDataForApprove.targetAddress) + val signedData = visaDataForApprove.sign(rsvSignature, visaDataForApprove.targetAddress) + callback(CompletionResult.Success(signedData)) } is CompletionResult.Failure -> { callback(CompletionResult.Failure(result.error)) From 1037d2ff103a1be2d85413284387bb7596e66c42 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 24 Dec 2025 12:01:22 +0500 Subject: [PATCH 11/36] Updated on 2026-08-14 --- .../tap/data/DefaultTangemPayStorage.kt | 34 +++++++++++++------ .../local/preferences/PreferencesKeys.kt | 1 + .../datasource/local/visa/TangemPayStorage.kt | 3 ++ .../pay/DefaultTangemPayEligibilityManager.kt | 10 +++++- .../repository/DefaultOnboardingRepository.kt | 10 +++++- .../domain/pay/TangemPayEligibilityManager.kt | 1 + .../pay/repository/OnboardingRepository.kt | 1 + .../features/details/model/DetailsModel.kt | 17 ++++++++-- .../features/details/utils/ItemsBuilder.kt | 24 +++++++++---- 9 files changed, 79 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt b/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt index a6f6497a39..fb02cff093 100644 --- a/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt +++ b/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt @@ -6,6 +6,7 @@ import com.tangem.datasource.di.NetworkMoshi import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObjectMapSync +import com.tangem.datasource.local.preferences.utils.getSyncOrDefault import com.tangem.datasource.local.preferences.utils.getSyncOrNull import com.tangem.datasource.local.preferences.utils.store import com.tangem.datasource.local.visa.TangemPayStorage @@ -21,6 +22,7 @@ import javax.inject.Singleton private const val AUTH_TOKENS_DEFAULT_KEY = "tangem_pay_default_key" private const val WITHDRAW_ORDER_ID_KEY = "tangem_pay_withdraw_order_id_key" +@Suppress("TooManyFunctions") @Singleton internal class DefaultTangemPayStorage @Inject constructor( @ApplicationContext applicationContext: Context, @@ -119,16 +121,6 @@ internal class DefaultTangemPayStorage @Inject constructor( return appPreferencesStore.getSyncOrNull(PreferencesKeys.getTangemPayCheckCustomerByWalletId(userWalletId)) } - override suspend fun clearAll(userWalletId: UserWalletId, customerWalletAddress: String) = - withContext(dispatcherProvider.io) { - secureStorage.delete(createAuthTokensKey(customerWalletAddress)) - appPreferencesStore.store(PreferencesKeys.getTangemPayCheckCustomerByWalletId(userWalletId), false) - appPreferencesStore.store(PreferencesKeys.getTangemPayCustomerWalletAddressKey(userWalletId), "") - appPreferencesStore.store(PreferencesKeys.getTangemPayOrderIdKey(customerWalletAddress), "") - appPreferencesStore.store(PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress), false) - appPreferencesStore.store(PreferencesKeys.getTangemPayHideOnboardingKey(userWalletId), false) - } - override suspend fun storeWithdrawOrder(userWalletId: UserWalletId, orderId: String) { appPreferencesStore.editData { mutablePreferences -> val orders = mutablePreferences.getObjectMap(PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY) @@ -170,6 +162,28 @@ internal class DefaultTangemPayStorage @Inject constructor( } } + override suspend fun storeTangemPayEligibility(eligibility: Boolean) { + withContext(dispatcherProvider.io) { + appPreferencesStore.store(key = PreferencesKeys.TANGEM_PAY_ELIGIBILITY_KEY, value = eligibility) + } + } + + override suspend fun getTangemPayEligibility(): Boolean { + return withContext(dispatcherProvider.io) { + appPreferencesStore.getSyncOrDefault(key = PreferencesKeys.TANGEM_PAY_ELIGIBILITY_KEY, default = false) + } + } + + override suspend fun clearAll(userWalletId: UserWalletId, customerWalletAddress: String) = + withContext(dispatcherProvider.io) { + secureStorage.delete(createAuthTokensKey(customerWalletAddress)) + appPreferencesStore.store(PreferencesKeys.getTangemPayCheckCustomerByWalletId(userWalletId), false) + appPreferencesStore.store(PreferencesKeys.getTangemPayCustomerWalletAddressKey(userWalletId), "") + appPreferencesStore.store(PreferencesKeys.getTangemPayOrderIdKey(customerWalletAddress), "") + appPreferencesStore.store(PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress), false) + appPreferencesStore.store(PreferencesKeys.getTangemPayHideOnboardingKey(userWalletId), false) + } + private fun createAuthTokensKey(address: String): String = "${AUTH_TOKENS_DEFAULT_KEY}_$address" private fun createWithdrawOrderIdKey(userWalletId: UserWalletId): String = "${WITHDRAW_ORDER_ID_KEY}_$userWalletId" 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 78e99e42bd..544a55357f 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 @@ -154,6 +154,7 @@ object PreferencesKeys { } val TANGEM_PAY_WITHDRAW_ORDERS_KEY by lazy { stringPreferencesKey(name = "tangemPayWithdrawOrders") } + val TANGEM_PAY_ELIGIBILITY_KEY by lazy { booleanPreferencesKey(name = "tangemPayEligibility") } fun getShouldShowNotificationKey(key: String) = booleanPreferencesKey("showShowNotificationUM_$key") // endregion diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt b/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt index a048c54414..591bc9f6be 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt @@ -3,6 +3,7 @@ package com.tangem.datasource.local.visa import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.visa.model.TangemPayAuthTokens +@Suppress("TooManyFunctions") interface TangemPayStorage { suspend fun storeCustomerWalletAddress(userWalletId: UserWalletId, customerWalletAddress: String) @@ -36,6 +37,8 @@ interface TangemPayStorage { suspend fun getHideMainOnboardingBanner(userWalletId: UserWalletId): Boolean suspend fun storeHideOnboardingBanner(userWalletId: UserWalletId, hide: Boolean) + suspend fun storeTangemPayEligibility(eligibility: Boolean) + suspend fun getTangemPayEligibility(): Boolean suspend fun clearAll(userWalletId: UserWalletId, customerWalletAddress: String) } \ No newline at end of file diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt index f2d850f463..4ab4d074f2 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt @@ -45,6 +45,10 @@ internal class DefaultTangemPayEligibilityManager @Inject constructor( } } + override suspend fun getTangemPayAvailability(): Boolean { + return onboardingRepository.checkCustomerEligibility() + } + private suspend fun getUserWalletsData(): List { cachedEligibleWallets?.let { return it } @@ -69,7 +73,7 @@ internal class DefaultTangemPayEligibilityManager @Inject constructor( } private suspend fun getPossibleWalletsForTangemPay(): List { - if (!onboardingRepository.checkCustomerEligibility()) { + if (!checkTangemPayEligibility()) { return emptyList() } @@ -125,6 +129,10 @@ internal class DefaultTangemPayEligibilityManager @Inject constructor( eligibleWalletsDeferred = null } + private suspend fun checkTangemPayEligibility(): Boolean { + return onboardingRepository.getCustomerEligibility() || onboardingRepository.checkCustomerEligibility() + } + private data class UserWalletData( val userWallet: UserWallet, val isPaeraCustomer: Boolean, diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt index 79fed1dc36..fe06e7b5e3 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt @@ -197,7 +197,15 @@ internal class DefaultOnboardingRepository @Inject constructor( val response = requestHelper.performWithoutToken { tangemPayApi.checkCustomerEligibility() }.getOrNull() - return response?.result?.isTangemPayAvailable == true + + val isAvailable = response?.result?.isTangemPayAvailable == true + tangemPayStorage.storeTangemPayEligibility(eligibility = isAvailable) + + return isAvailable + } + + override suspend fun getCustomerEligibility(): Boolean { + return tangemPayStorage.getTangemPayEligibility() } override suspend fun getHideMainOnboardingBanner(userWalletId: UserWalletId): Boolean { diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/TangemPayEligibilityManager.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/TangemPayEligibilityManager.kt index 5ad9a9d3d9..cc26e4832a 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/TangemPayEligibilityManager.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/TangemPayEligibilityManager.kt @@ -5,4 +5,5 @@ import com.tangem.domain.models.wallet.UserWallet interface TangemPayEligibilityManager { suspend fun getEligibleWallets(shouldExcludePaeraCustomers: Boolean): List + suspend fun getTangemPayAvailability(): Boolean } \ No newline at end of file diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt index 6a304dbfbb..1deca6b43a 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt @@ -26,6 +26,7 @@ interface OnboardingRepository { suspend fun checkCustomerWallet(userWalletId: UserWalletId): Either suspend fun checkCustomerEligibility(): Boolean + suspend fun getCustomerEligibility(): Boolean fun getSavedCustomerInfo(userWalletId: UserWalletId): CustomerInfo? diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt index b730125b22..992afae4ac 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt @@ -53,19 +53,19 @@ import javax.inject.Inject @Suppress("LongParameterList") internal class DetailsModel @Inject constructor( socialsBuilder: SocialsBuilder, + paramsContainer: ParamsContainer, + feedbackFeatureToggles: FeedbackFeatureToggles, private val itemsBuilder: ItemsBuilder, private val appVersionProvider: AppVersionProvider, private val checkIsWalletConnectAvailableUseCase: CheckIsWalletConnectAvailableUseCase, private val router: Router, private val urlOpener: UrlOpener, private val appInstanceIdProvider: AppInstanceIdProvider, - paramsContainer: ParamsContainer, private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, private val appStateHolder: ReduxStateHolder, private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val getWalletsUseCase: GetWalletsUseCase, - private val feedbackFeatureToggles: FeedbackFeatureToggles, override val dispatchers: CoroutineDispatcherProvider, private val generateBuyTangemCardLinkUseCase: GenerateBuyTangemCardLinkUseCase, private val hotWalletFeatureToggles: HotWalletFeatureToggles, @@ -254,7 +254,18 @@ internal class DetailsModel @Inject constructor( .getEligibleWallets(shouldExcludePaeraCustomers = true) .isNotEmpty() if (isEligible) { - items.update { itemsBuilder.addVisaItem(it) } + items.update { itemsBuilder.addTangemPayItem(items = it, onClick = ::onTangemPayItemClicked) } + } + } + } + + private fun onTangemPayItemClicked() { + modelScope.launch { + val isEligible = tangemPayEligibilityManager.getTangemPayAvailability() + if (isEligible) { + router.push(AppRoute.TangemPayOnboarding(AppRoute.TangemPayOnboarding.Mode.FromBannerInSettings)) + } else { + items.update { itemsBuilder.removeTangemPayItem(it) } } } } diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt index 8de88bbb26..c8627bf1ea 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt @@ -14,6 +14,8 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toPersistentList import javax.inject.Inject +private const val TANGEM_PAY_ITEM_ID = "get_tangem_pay" + @ModelScoped internal class ItemsBuilder @Inject constructor(private val router: Router) { @@ -37,10 +39,13 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) { ).let(::add) }.toImmutableList() - fun addVisaItem(items: ImmutableList): ImmutableList { + fun addTangemPayItem(items: ImmutableList, onClick: () -> Unit): ImmutableList { return items.toMutableList().map { block -> if (block.id == "shop" && block is DetailsItemUM.Basic) { - val newItems = block.items.toMutableList().apply { add(getVisaItem()) } + val newItems = block + .items + .toMutableList() + .apply { add(getTangemPayItem(onClick = onClick)) } block.copy(items = newItems.toImmutableList()) } else { block @@ -48,6 +53,13 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) { }.toImmutableList() } + fun removeTangemPayItem(items: ImmutableList): ImmutableList { + val tangemPayItem = items.find { it.id == TANGEM_PAY_ITEM_ID } ?: return items + return items.toMutableList() + .also { list -> list.remove(tangemPayItem) } + .toImmutableList() + } + private fun buildWalletConnectBlock(isWalletConnectAvailable: Boolean, userWalletId: UserWalletId): DetailsItemUM? { return if (isWalletConnectAvailable) { DetailsItemUM.WalletConnect( @@ -126,14 +138,12 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) { }.toPersistentList(), ) - private fun getVisaItem(): DetailsItemUM.Basic.Item = DetailsItemUM.Basic.Item( - id = "get_tangem_visa", + private fun getTangemPayItem(onClick: () -> Unit): DetailsItemUM.Basic.Item = DetailsItemUM.Basic.Item( + id = TANGEM_PAY_ITEM_ID, block = BlockUM( text = resourceReference(R.string.tangempay_get_tangem_pay), iconRes = R.drawable.ic_tangem_pay_24, - onClick = { - router.push(AppRoute.TangemPayOnboarding(AppRoute.TangemPayOnboarding.Mode.FromBannerInSettings)) - }, + onClick = onClick, ), ) } \ No newline at end of file From a0432c18bda42efedd497e5b46972ab25f6c48c8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 24 Dec 2025 18:22:17 +0500 Subject: [PATCH 12/36] 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 462e99b59c..55284d02b1 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.32-1329" +tangemBlockchainSdk = "releases-5.32-1331" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.32-574" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From 87fbd38dd717a3222ce0d8d1919e813fbca972ef Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 24 Dec 2025 17:04:17 +0300 Subject: [PATCH 13/36] Updated on 2026-08-14 --- .../java/com/tangem/data/wallets/DefaultWalletsRepository.kt | 1 + .../tangem/domain/wallets/repository/WalletsRepository.kt | 5 +++-- .../wallets/usecase/ShouldSaveUserWalletsSyncUseCase.kt | 1 + .../tangem/feature/wallet/child/wallet/model/WalletModel.kt | 4 +++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt index 797d06f372..45b444d02f 100644 --- a/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt +++ b/data/wallets/src/main/java/com/tangem/data/wallets/DefaultWalletsRepository.kt @@ -53,6 +53,7 @@ internal class DefaultWalletsRepository( private val upgradeWalletNotificationDisabled: MutableStateFlow> = MutableStateFlow(mutableSetOf()) + @Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method") override suspend fun shouldSaveUserWalletsSync(): Boolean { return appPreferencesStore.getSyncOrDefault(key = PreferencesKeys.SAVE_USER_WALLETS_KEY, default = false) } diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt index 96266b809d..430653e85c 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/repository/WalletsRepository.kt @@ -11,12 +11,13 @@ import kotlinx.coroutines.flow.Flow @Suppress("TooManyFunctions") interface WalletsRepository { + @Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method") suspend fun shouldSaveUserWalletsSync(): Boolean - @Deprecated("Hot wallet make always save user wallets. Do not use this method") + @Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method") fun shouldSaveUserWallets(): Flow - @Deprecated("Hot wallet make always save user wallets. Do not use this method") + @Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method") suspend fun saveShouldSaveUserWallets(item: Boolean) suspend fun useBiometricAuthentication(): Boolean diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsSyncUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsSyncUseCase.kt index 16efc0eadb..85e7b0265f 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsSyncUseCase.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/ShouldSaveUserWalletsSyncUseCase.kt @@ -2,6 +2,7 @@ package com.tangem.domain.wallets.usecase import com.tangem.domain.wallets.repository.WalletsRepository +@Deprecated("Hot wallet feature makes app always save user wallets. Do not use this method") class ShouldSaveUserWalletsSyncUseCase(private val walletsRepository: WalletsRepository) { suspend operator fun invoke(): Boolean = walletsRepository.shouldSaveUserWalletsSync() 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 c4b8aeb87c..8370377f18 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 @@ -304,7 +304,9 @@ internal class WalletModel @Inject constructor( notificationsRepository.setShouldAskNotificationPermissionsViaBs(true) return@launch } - if (!isBiometricsEnabled) return@launch + if (!hotWalletFeatureToggles.isHotWalletEnabled && !isBiometricsEnabled) { + return@launch + } if (!shouldShow) { return@launch } From 5540f76392b03682120f05f8532be9fc7534831c Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 25 Dec 2025 20:49:32 +0500 Subject: [PATCH 14/36] Updated on 2026-08-14 --- .../features/markets/tokenlist/impl/model/MarketsListModel.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt index 27fd01e1d5..d33935747e 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/model/MarketsListModel.kt @@ -18,6 +18,7 @@ import com.tangem.domain.promo.PromoRepository import com.tangem.domain.settings.usercountry.GetUserCountryUseCase import com.tangem.domain.settings.usercountry.models.UserCountry import com.tangem.domain.settings.usercountry.models.UserCountryError +import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions import com.tangem.features.markets.tokenlist.impl.analytics.MarketsListAnalyticsEvent import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListBatchFlowManager import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListUMStateManager @@ -147,7 +148,8 @@ internal class MarketsListModel @Inject constructor( } } }.collect { marketsItemsData -> - val shouldShowYieldModePromo = marketsItemsData.shouldShowYieldModePromo + val isApplyFCARestrictions = marketsItemsData.userCountry.getOrNull().needApplyFCARestrictions() + val shouldShowYieldModePromo = marketsItemsData.shouldShowYieldModePromo && !isApplyFCARestrictions if (marketsListUMStateManager.state.value.marketsNotificationUM == null && shouldShowYieldModePromo) { analyticsEventHandler.send(MarketsListAnalyticsEvent.YieldModePromoShown()) } From 2c2c994e72c1775db473f2814651ec5644eb6af2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 25 Dec 2025 19:34:39 +0300 Subject: [PATCH 15/36] Updated on 2026-08-14 --- core/res/src/main/res/values/strings.xml | 2 ++ .../model/warnings/CryptoCurrencyWarning.kt | 2 ++ .../tokens/GetCurrencyWarningsUseCase.kt | 18 ++++++++++++++---- ...TokenDetailsNotificationsAnalyticsSender.kt | 1 + .../components/TokenDetailsNotification.kt | 5 +++++ .../TokenDetailsNotificationConverter.kt | 1 + .../com/tangem/lib/crypto/BlockchainUtils.kt | 4 ++++ 7 files changed, 29 insertions(+), 4 deletions(-) diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index eaddf5b46e..f323d25978 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -1787,6 +1787,8 @@ Ok, Got it! Really cool! Refresh + According to Clore’s official documentation, all tokens received before December 21 will be migrated to Clore (ERC20); tokens received after will not. Transfer solution coming — stay tuned. + Clore Network Migration You are currently in the Demo mode Demo mode active The card you scanned is a developer card. Do not use it to create your wallet. 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 9edbf243da..1d69153c6e 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 @@ -57,6 +57,8 @@ sealed class CryptoCurrencyWarning { data object MigrationMaticToPol : CryptoCurrencyWarning() + data object MigrationClore : CryptoCurrencyWarning() + /** * Shows a warning about an available fee resource for a transaction in several blockchains (ex. Koinos) */ diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt index d4611e9d40..6ca1aa64ce 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt @@ -41,16 +41,16 @@ class GetCurrencyWarningsUseCase( // don't add here notifications that require async requests return combine( - getCoinRelatedWarnings( + flow = getCoinRelatedWarnings( userWalletId = userWalletId, networkId = currency.network.id, currencyId = currency.id, derivationPath = derivationPath, isSingleWalletWithTokens = isSingleWalletWithTokens, ), - flowOf(currencyChecksRepository.getRentInfoWarning(userWalletId, currencyStatus)), - flowOf(currencyChecksRepository.getExistentialDeposit(userWalletId, currency.network)), - flowOf(currencyChecksRepository.getFeeResourceAmount(userWalletId, currency.network)), + flow2 = flowOf(currencyChecksRepository.getRentInfoWarning(userWalletId, currencyStatus)), + flow3 = flowOf(currencyChecksRepository.getExistentialDeposit(userWalletId, currency.network)), + flow4 = flowOf(currencyChecksRepository.getFeeResourceAmount(userWalletId, currency.network)), ) { coinRelatedWarnings, maybeRentWarning, maybeEdWarning, maybeFeeResource -> setOfNotNull( maybeRentWarning, @@ -62,6 +62,7 @@ class GetCurrencyWarningsUseCase( getBeaconChainShutdownWarning(rawId = currency.network.id.rawId), getAssetRequirementsWarning(userWalletId = userWalletId, currency = currency), getMigrationFromMaticToPolWarning(currency), + getCloreMigrationWarning(currency), ) }.flowOn(dispatchers.io) } @@ -261,11 +262,20 @@ class GetCurrencyWarningsUseCase( } } + private fun getCloreMigrationWarning(currency: CryptoCurrency): CryptoCurrencyWarning? { + return if (currency.symbol == CLORE_SYMBOL && BlockchainUtils.isClore(currency.network.rawId)) { + CryptoCurrencyWarning.MigrationClore + } else { + null + } + } + private fun BigDecimal?.isZero(): Boolean { return this?.signum() == 0 } companion object { private const val MATIC_SYMBOL = "MATIC" + private const val CLORE_SYMBOL = "CLORE" } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt index 3bef7418c8..d65921fdb9 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt @@ -59,6 +59,7 @@ internal class TokenDetailsNotificationsAnalyticsSender( is TokenDetailsNotification.RequiredTrustlineWarning, is TokenDetailsNotification.KoinosMana, is TokenDetailsNotification.MigrationMaticToPol, + is TokenDetailsNotification.MigrationClore, is TokenDetailsNotification.UsedOutdatedData, -> null } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt index b1ae6761a1..5733db0e18 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt @@ -258,6 +258,11 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) { subtitle = resourceReference(id = R.string.warning_matic_migration_message), ) + data object MigrationClore : Warning( + title = resourceReference(id = R.string.warning_clore_migration_title), + subtitle = resourceReference(id = R.string.warning_clore_migration_message), + ) + data object UsedOutdatedData : TokenDetailsNotification( config = NotificationConfig( subtitle = resourceReference(R.string.warning_some_token_balances_not_updated), 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 0b4d3a4e71..eb54aca878 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 @@ -155,6 +155,7 @@ internal class TokenDetailsNotificationConverter( }, ) is CryptoCurrencyWarning.MigrationMaticToPol -> MigrationMaticToPol + is CryptoCurrencyWarning.MigrationClore -> MigrationClore is CryptoCurrencyWarning.UsedOutdatedDataWarning -> UsedOutdatedData } } diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt index b51011e498..91fb30dd4f 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt @@ -115,6 +115,10 @@ object BlockchainUtils { return blockchain == Blockchain.BSC || blockchain == Blockchain.BSCTestnet } + fun isClore(blockchainId: String): Boolean { + return Blockchain.fromId(blockchainId) == Blockchain.Clore + } + data class BlockchainInfo( val blockchainId: String, val name: String, From 9cd1741344fbaac99edddb712f003e328020ab42 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 25 Dec 2025 20:54:25 +0300 Subject: [PATCH 16/36] Updated on 2026-08-14 --- .../com/tangem/feature/swap/domain/SwapInteractorImpl.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 0531735446..88a95c06bd 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -694,6 +694,11 @@ internal class SwapInteractorImpl @AssistedInject constructor( userWalletId: UserWalletId, ): Throwable? { val currency = fromToken.currency + val blockchain = currency.network.toBlockchain() + // Stellar validation removed because swap uses destination = "0" and throws an error + if (blockchain == Blockchain.Stellar) { + return null + } val fee = Fee.Common( amount = Amount( value = when (feeState) { @@ -701,7 +706,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( is TxFeeState.MultipleFeeState -> feeState.normalFee.feeValue is TxFeeState.SingleFeeState -> feeState.fee.feeValue }, - blockchain = currency.network.toBlockchain(), + blockchain = blockchain, ), ) From 7b0e68fffe44dd62edb902528da57f83e57cc1ac Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 25 Dec 2025 21:09:13 +0300 Subject: [PATCH 17/36] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 5fc86d29bc..78be297b0f 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 5fc86d29bc2c0dc7c057ab0242b2cfa3e9f48daf +Subproject commit 78be297b0f09bc2be1e9b0fbab9384f17bf94c37 From 49863d5bb5b01982d9760925b3cded188e5ed415 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 26 Dec 2025 11:53:35 +0300 Subject: [PATCH 18/36] Updated on 2026-08-14 --- core/res/src/main/res/values-de/strings.xml | 36 ++++-- core/res/src/main/res/values-es/strings.xml | 95 ++++++++++++++-- core/res/src/main/res/values-fr/strings.xml | 104 ++++++++++++++++-- core/res/src/main/res/values-it/strings.xml | 12 +- core/res/src/main/res/values-ja/strings.xml | 33 ++++-- core/res/src/main/res/values-ru/strings.xml | 27 +++-- .../src/main/res/values-uk-rUA/strings.xml | 100 ++++++++++++++++- .../src/main/res/values-zh-rTW/strings.xml | 12 +- core/res/src/main/res/values/strings.xml | 79 +++++++------ 9 files changed, 405 insertions(+), 93 deletions(-) diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index af3e4fd8d7..3ada9d77f2 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -44,6 +44,7 @@ Speichern Kontoname Der Kontoname ist bereits vorhanden + Der Kontoname wird bereits verwendet. Konto Neues Konto Konto hinzufügen @@ -448,7 +449,7 @@ Überprüfe deine Internetverbindung oder wechseln zu einem anderen Netzwerk Nutzungsbedingungen Standardadresse - Legacy adresse + Legacy %s adresse Empfangen von Vermögenswerten %s Adresse Das Senden von Vermögenswerten in anderen Netzwerken führt zu dauerhaftem Verlust. @@ -541,6 +542,7 @@ Bitte sag uns, welche Karte oder Ring du hast Hallo Support-Team, Bitte erzähle uns mehr über dein Problem. Jedes kleine Detail kann helfen. + Problem mit der Sicherung Zuvor aktivierte Wallet Meine Vorschläge Kann eine Karte oder Ring nicht scannen @@ -593,10 +595,13 @@ Aktualisiere Deine aktuelle Wallet Gehe zum Backup Bitte sicher Deine Wallet, bevor Du einen Zugangscode erstellst. + Sicherung zuerst beenden Zuerst die Sicherung abschließen Unvollständig Andere Methoden + Speicher Deinen Wiederherstellungssatz an einem sicheren Ort und halte diesen stets geheim, um Dein Geld zu schützen. Wiederherstellungs-Phrase + Um Deine Wallet mit einem Zugangscode zu sichern, schließe den Sicherungsvorgang ab. Um Deine Wallet auf Hardware umzustellen, erstelle vorher ein Backup. Deine privaten Schlüssel sind sicher verschlüsselt und auf Deinem Telefon gespeichert. Schlüssel werden in der App gespeichert @@ -617,8 +622,9 @@ Für diese Wallet existiert ein Backup. Überprüfe dieses bitte, bevor Du sie entfernst, um sicherzustellen, dass Du sie später wiederherstellen kannst. Wenn Du diese Wallet ohne Backup entfernst, verlierst Du dauerhaft den Zugriff auf Deine Assets. Diese Wallet dauerhaft entfernen? - Mir ist bewusst, dass ich den Zugriff auf meine Wallet verliere kann, wenn ich sie vor der Entfernung nicht gesichert habe. + Mir ist bewusst, dass ich den Zugriff auf meine Wallet verlieren kann, wenn ich sie vor der Entfernung nicht gesichert habe. Mir ist bewusst, dass durch das Entfernen meiner Wallet diese nicht gelöscht, sondern lediglich von meinem Gerät entfernt wird. + Upgrade Es wird keine Seed-Phrase mehr benötigt – Deine Tangem-Karte oder Dein Tangem-Ring wird zu Deinem sicheren Backup. Backup mit Tangem Ein Upgrade ist nicht möglich. Auf diesem Gerät ist bereits eine Wallet vorhanden. @@ -793,6 +799,10 @@ Du musst auf die folgende Version aktualisieren: %1$s um eine mobile Wallet zu erstellen Mobile Wallet erfordert %1$s oder später Alle Neuigkeiten + Gefällt mir + Kurze Zusammenfassung + Verwandte Nachrichten + Quellen Auf dem Laufenden bleiben NFC ist auf deinem Gerät nicht verfügbar Über NFT @@ -1072,6 +1082,8 @@ Bitte setze das nächste Gerät zurück, um fortzufahren. Ringbesitzer erhalten bis zum 15.11. 3 provisionsfreie Swaps auf Changelly! Jetzt mit 0 % Gebühren tauschen! + Geräte mit Root-Zugriff gelten als weniger sicher. Deine Daten können zusätzlichen Risiken ausgesetzt sein. + Root-Zugriff erkannt Melde dich bei der App an und überprüfe dein Guthaben, ohne die Karte oder Ring zu scannen Zugriff auf die App Nutzung biometrischer Daten zulassen @@ -1417,6 +1429,7 @@ Entsperren der Karte fehlgeschlagen. Versuchen Sie es später erneut. Ihre Karte ist entsperrt. Abhebung + KYC abbrechen Guthaben hinzufügen Aufladeoptionen Kartennummer @@ -1444,6 +1457,7 @@ Alles erledigt! Deine Karte ist einsatzbereit. Karte zu Google Pay hinzufügen Karte zu Apple Pay hinzufügen + Pin Code Teile Deine Adresse mit oder zeig den QR-Code. Es wurden technische Probleme festgestellt. Bitte versuche es später erneut oder kontaktiere den Support. Empfangen ist jetzt nicht verfügbar @@ -1452,6 +1466,7 @@ Tausche beliebige Vermögenswerte in Deinem Portfolio gegen eine Karte. Kartendetails Karte entsperren + Dein PIN-Code Auszahlung Auszahlung derzeit nicht möglich Sie können keinen Tausch oder eine neue Auszahlung starten, bis die aktuelle abgeschlossen ist. @@ -1461,7 +1476,7 @@ Kartenausstellung fehlgeschlagen Ein technischer Fehler ist aufgetreten, bitte versuchen Sie es erneut, indem Sie auf die Schaltfläche unten klicken Ein technischer Fehler ist aufgetreten, bitte kontaktieren Sie den Support - Nutzen Sie Ihre Kryptowährungen für Einkäufe im Alltag. \nEine Zahlungskarte, die ihresgleichen sucht. + Holen Sie sich Ihre kostenlose virtuelle Tangem Visa-Karte Tangem Pay erhalten Zum Support Es dauert in der Regel bis zu 15 Minuten. @@ -1469,13 +1484,15 @@ Ausstellung Deiner Karte Wir bereiten Ihre Karte vor. Dies kann etwas dauern. Tangem Pay + Konvertierung bestätigen + Möchtest Du den KYC wirklich abbrechen? Du kannst später jederzeit weiter machen. Wir konnten Ihr Profil nicht verifizieren. Bei Fragen wenden Sie sich bitte an den Support. Leider konnten wir Ihre Identität nicht verifizieren KYC in Bearbeitung Status anzeigen KYC für Tangem Pay in Arbeit - Nutzen Sie Ihre Kryptowährungen für Einkäufe im echten Leben. \nEs ist eine Zahlungskarte, die ihresgleichen sucht. - Tangem Visa Card + Holen Sie sich Ihre kostenlose virtuelle Tangem Visa-Karte + Nutzen Sie USDC für alltägliche Zahlungen Karte erhalten Mit digitaler Karte, die mit Apple Pay und Google Pay funktioniert Geben Sie Ihre Vermögenswerte überall aus @@ -1485,15 +1502,15 @@ Unerreichte Privatsphäre Erhalten Sie Ihre kostenlose Tangem Pay Card in wenigen Minuten Zahlungskonto - Synchronisierung des Zahlungskontos erforderlich + Zahlungskonto ist nicht synchronisiert Wir beheben ein technisches Problem. Bitte versuchen Sie es später erneut. Service vorübergehend nicht verfügbar Daten können derzeit nicht angezeigt werden, Kartenzahlungen funktionieren jedoch weiterhin. Synchronisation erforderlich - Tangem Visa Card + Nutzen Sie USDC für alltägliche Zahlungen Tangem Pay ist vorübergehend nicht verfügbar Tangem Pay - Verwenden Sie Ihre Karte oder Ihren Ring, um den Zugriff auf Ihr Zahlungskonto wiederherzustellen + Klicken Sie auf die Schaltfläche unten, um den Zugriff wiederherzustellen Ihr PIN-Code Das ist meine Wallet Guthaben versteckt @@ -1754,6 +1771,8 @@ OK, habe ich verstanden! Echt toll! Aktualisieren + Laut der offiziellen Dokumentation von Clore werden alle Münzen, die vor dem 21. Dezember erhalten wurden, in Clore (ERC-20 Token) migriert; Münzen, die nach diesem Datum erhalten wurden, nicht. Eine Lösung für den Transfer ist in Arbeit — bleibt dran. + Migration des Clore-Netzwerks Du befindest sich derzeit im Demo-Modus Demo-Modus aktiv Die Karte, die du gescannt hast, ist eine Entwicklerkarte. Verwenden diese nicht zur Erstellung Ihrer Wallet. @@ -1990,6 +2009,7 @@ Gebührenpolitik Tangem erhebt außerdem eine Servicegebühr von 15% auf den erzielten Ertrag. Deine Gelder werden automatisch an Aave überwiesen, sobald die Netzwerkgebühren niedriger sind oder Dein Guthaben den erforderlichen Mindestbetrag erreicht. + Die Gebühren sind aufgrund der hohen Marktaktivität derzeit höher als üblich. Du kannst jetzt fortfahren oder später noch einmal vorbeischauen, wenn die Gebühren niedriger sind. Hohe Netzwerkgebühren Historische Renditen Aktiviere %1$s%% Jahreszins auf Dein Guthaben diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index e99920eeb5..05ae68f195 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -80,6 +80,7 @@ Seleccione una billetera para iniciar sesión ¡Bienvenido de nuevo! Realizó una copia de seguridad de su billetera correctamente. + Estas palabras son irrecuperables si se pierden. Guárdelas en un lugar seguro. Copia de seguridad completada Su frase secreta de recuperación es un conjunto fijo de %s palabras aleatorias que se utilizan para acceder a su billetera y recuperarla. Estas palabras no pueden recuperarse si se pierden. Asegúrese de guardarlas en un lugar seguro. @@ -87,6 +88,7 @@ Guarde estas %s palabras en un lugar seguro, como un administrador de contraseñas, y nunca las comparta con nadie. No se puede restaurar Frase de recuperación + Nunca comparta estas palabras con nadie. Tangem nunca se las pedirá. Las palabras %s que aparecen a continuación son la frase de recuperación de su billetera. Úselas para restaurar su billetera si pierde su dispositivo. Escriba estas %s palabras en orden y guárdelas en un lugar privado y seguro La responsabilidad total sobre la seguridad y copia de seguridad de la billetera y su frase de recuperación recae en el usuario, no en Tangem. Frase de recuperación @@ -399,7 +401,7 @@ Compruebe su conexión a internet o cambia a una red diferente Condiciones de uso Dirección por defecto - Dirección Legacy + Dirección %s Legacy Recibir activos %s dirección Enviar activos a otras redes resultará en una pérdida permanente. @@ -489,6 +491,7 @@ Por favor, díganos qué tarjeta o anillo tiene Hola equipo de soporte, Por favor, cuéntenos más sobre tu problema. Cada pequeño detalle puede ayudar. + Problema con la copia de seguridad Billetera previamente activada Mis recomendaciones No se puede escanear una tarjeta/anillo @@ -507,6 +510,13 @@ Para continuar, conceda a los contratos inteligentes de %1s permiso para utilizar su %2s Dar autorización Ilimitado + Su copia de seguridad se crea utilizando 2 o 3 tarjetas Tangem. Guárdalas en lugares seguros y separados para protegerlas de pérdidas o daños. + Copia de seguridad con varias tarjetas + Agregar billetera Tangem + Su clave privada se genera directamente dentro de la tarjeta Tangem y nunca sale de ella. + Generación de claves + Todas las operaciones criptográficas ocurren dentro del chip seguro, certificado contra la clonación y la manipulación física. + Seguridad a nivel de hardware Agregar Billetera Existente Crear Nueva Billetera Pedir Tangem @@ -515,7 +525,73 @@ a %s En la red %s ¿Está seguro de que desea salir del proceso de creación de código de acceso? + Hacer copia ahora + Para completar la configuración, haga una copia de seguridad de su billetera y proteja la aplicación con un código de acceso. + Finalizar ahora + Finalizar la configuración de la billetera + Complete la configuración protegiendo la aplicación con un código de acceso. + Si sale, tendrá que empezar de nuevo. + ¿Está seguro de que desea salir del proceso de configuración? + Mantiene sus criptomonedas seguras y sin conexión. Tan delgadas como una tarjeta de crédito, más seguras que una bóveda bancaria. Si lo hace, tendrá que empezar de nuevo. + Recuperar la billetera existente a través de una copia de seguridad de Google Drive + Copia de seguridad de Google Drive + Cree una billetera segura y transfiera sus fondos para mayor protección. + Crear nueva billetera + Mejore su seguridad con la billetera de hardware superior Tangem. + Billetera de hardware + Mueva su billetera actual a Tangem. + Actualizar la billetera actual + Ir a copia de seguridad + Por favor, haga una copia de seguridad de su billetera antes de crear un código de acceso. + Finalice la copia de seguridad primero + Finalizar la copia de seguridad primero + Incompleto + Otros métodos + Guarde su frase de recuperación en un lugar seguro y manténgala en privado para proteger sus fondos. + Frase de recuperación + Para proteger su billetera con un código de acceso, complete el proceso de copia de seguridad. + Para actualizar a una billetera de hardware, complete el proceso de copia de seguridad. + Sus claves privadas están encriptadas de forma segura y almacenadas en su teléfono + Las claves privadas permanecen en su dispositivo + Cree o restaure su billetera con una frase de recuperación. + Copia de seguridad de la frase semilla + Crear una billetera móvil + Importar billetera existente + Esta frase de recuperación ya ha sido importada + Billetera móvil + Olvidar billetera + Esta billetera se eliminará permanentemente de su dispositivo. + ¿Está seguro que desea hacer esto? + Olvidar billetera + Ir a copia de seguridad + Ver copia de seguridad + Olvidar la billetera + Olvidar de todos modos + Esta billetera tiene una copia de seguridad. Asegúrese de poder recuperarla antes de olvidarla. + Si olvida esta billetera sin una copia de seguridad, perderá permanentemente el acceso a sus fondos. + ¿Estás seguro de que desea olvidar esta billetera? + Entiendo que si no he hecho una copia de seguridad de mi billetera antes de eliminarla, perderé el acceso a ella. + Entiendo que quitar mi billetera no la borra, solo la elimina de mi dispositivo. + Actualizar + No se requiere frase semilla. Su tarjeta o anillo Tangem se convierte en su copia de seguridad. + Copia de seguridad con Tangem + No se puede actualizar. Ya existe una billetera en este dispositivo. + Elija otro dispositivo. Este no se puede usar para la actualización. + Se produjo un error durante la operación. + Sus fondos permanecen seguros y totalmente accesibles durante el proceso + Acceso a los fondos + Los datos de su billetera se borrarán de la aplicación y se almacenarán en su billetera de hardware. + Seguridad general + Las claves privadas se transferirán de la aplicación a su billetera de hardware Tangem + Migración de claves + Escanear dispositivo + Iniciar actualización + Estás a punto de actualizarte a nuestra billetera de hardware. Mantendrá sus activos seguros en almacenamiento en frío. + Tangem Wallet + Actualice a nuestra billetera de hardware + Mantenga sus criptomonedas seguras con la billetera de hardware de primer nivel de Tangem. + Actualice su billetera a la seguridad del hardware Esta información fue generada con IA.\nPulse aquí si encuentra algún error. Para cambiar el código de acceso coloque la tarjeta o el anillo como se muestra arriba y no lo retire hasta el fin de la operación Toque para cambiar la contraseña @@ -916,6 +992,8 @@ El reseteo a valores de fábrica eliminará completamente la billetera de la tarjeta/anillo seleccionado y lo eliminará de la app. No podrá restaurar la billetera actual. Si tiene un Anillo Tangem, ¡3 swaps sin comisión en Changelly hasta el 15/11! ¡Intercambia con 0% de comisión! + Los dispositivos con jailbreak se consideran menos seguros. Sus datos podrían estar expuestos a riesgos adicionales. + Acceso root detectado Inicie sesión en la app y comprueba su saldo sin escanear la tarjeta o el anillo Acceder a la app Permitir el uso de biometría @@ -1297,7 +1375,7 @@ Error al emitir la tarjeta Ha ocurrido un error técnico, por favor inténtalo de nuevo haciendo clic en el botón de abajo Ha ocurrido un error técnico, por favor contacta con el soporte - Usa tus criptomonedas para compras en el mundo real. \nEs una tarjeta de pago única en su tipo. + Obtén tu tarjeta virtual Tangem Visa gratuita Obtener Tangem Pay Ir a Soporte Suele tardar hasta 15 minutos @@ -1310,8 +1388,8 @@ KYC en curso Ver estado KYC en progreso para Tangem Pay - Usa tus criptomonedas para compras en el mundo real. \nEs una tarjeta de pago única en su tipo. - Tangem Visa Card + Obtén tu tarjeta virtual Tangem Visa gratuita + Usa USDC para pagos cotidianos Obtener tarjeta Con tarjeta digital que funciona con Apple Pay y Google Pay Gasta tus activos en cualquier lugar @@ -1321,15 +1399,15 @@ Privacidad inigualable Obtén tu tarjeta Tangem Pay gratuita en minutos Cuenta de pago - Sincronización de cuenta de pago necesaria + La cuenta de pago no está sincronizada Estamos solucionando un problema técnico. Por favor, inténtelo de nuevo más tarde. Servicio temporalmente no disponible No es posible mostrar los datos en este momento, pero los pagos con tarjeta siguen funcionando. Sincronización necesaria - Tangem Visa Card + Usa USDC para pagos cotidianos Tangem Pay temporalmente no disponible Tangem Pay - Usa tu tarjeta o anillo para restaurar el acceso a tu cuenta de pago + Haga clic en el botón de abajo para restaurar el acceso Tu código PIN Esta es mi billetera Saldos ocultos @@ -1410,6 +1488,7 @@ Active las notificaciones push y le avisaremos al instante cuando le lleguen fondos. No se pierda ninguna transacción Agregar una nueva billetera + Si olvida esta billetera sin una copia de seguridad, perderá permanentemente el acceso a sus fondos. ¿Estás seguro de que deseas olvidar esta billetera? Ha ocurrido un error, por favor escanee su tarjeta o anillo para iniciar sesión Esta billetera ya se ha guardado, puede agregar otro @@ -1504,6 +1583,8 @@ Entendido ¡Realmente genial! Actualizar + Según la documentación oficial de Clore, todas las monedas recibidas antes del 21 de diciembre serán migradas a Clore (token ERC-20); las monedas recibidas después de esa fecha no lo serán. Se está desarrollando una solución de transferencia — mantente atento. + Migración de la red Clore Actualmente estás en el modo Demo Modo demo activo La tarjeta que ha escaneado es una tarjeta de desarrollador. No la use para crear su billetera. diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index dea8c07645..484e6cf07b 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -72,7 +72,19 @@ Ajouter un wallet Sélectionnez un wallet pour vous connecter Heureux de te revoir! + Vous avez sauvegardé votre portefeuille avec succès. Ces mots ne peuvent pas être récupérés en cas de perte. Assurez-vous de les conserver en lieu sûr. + Sauvegarde terminée + Votre seed phrase est un ensemble fixe de %s mots aléatoires permettant d\'accéder à votre portefeuille et de le récupérer. + Ces mots ne peuvent être récupérés s\'ils sont perdus. Conservez-les précieusement. + Gardez-les en sécurité + Conservez ces %s mots dans un endroit sûr et ne les communiquez à personne. + Aucune récupération possible + Seed phrase + Ne communiquez jamais ces mots à qui que ce soit. Tangem ne vous les demandera jamais. Les %s mots ci-dessous constituent la seed phrase de votre portefeuille. Utilisez-les pour restaurer votre portefeuille si vous perdez votre appareil. + Notez ces %s mots dans l\'ordre numérique et conservez-les en lieu sûr et confidentiel. + Vous êtes entièrement responsable de la sécurité de votre portefeuille et de la sauvegarde de votre seed phrase. + Seed phrase Pour masquer ou afficher vos soldes, il suffit de retourner l\'écran de votre appareil vers le bas ou de le désactiver dans les paramètres Ne plus afficher Compris @@ -382,7 +394,7 @@ Vérifiez votre connexion Internet ou passez à un réseau différent Conditions d\'utilisation Adresse par défaut - Legacy adresse + Legacy %s adresse Recevoir des actifs %s adresse L’envoi d’actifs sur d’autres réseaux entraînera une perte définitive. @@ -470,6 +482,7 @@ Veuillez nous dire quelle carte vous avez Chère équipe de support, Veuillez nous en dire plus sur votre problème. Chaque petit détail peut nous aider. + Problème de sauvegarde Portefeuille précédemment activé Mes suggestions Impossible de scanner une carte @@ -488,6 +501,13 @@ Pour continuer, accordez aux smart contracts de %1s l\'autorisation d\'utiliser votre %2s Donner l\'autorisation Illimité + Votre sauvegarde est créée à l\'aide de 2 ou 3 cartes Tangem. Conservez-les dans des endroits sûrs distincts afin de les protéger contre toute perte ou tout dommage. Aucune seed phrase n\'est nécessaire. + Sauvegarde avec plusieurs cartes + Ajouter le wallet Tangem + Votre clé privée est générée directement dans la carte Tangem et ne la quitte jamais. + Génération de clés + Toutes les opérations cryptographiques s\'effectuent à l\'intérieur de la puce sécurisée, certifiée contre le clonage et la falsification physique. + Sécurité au niveau matériel Ajouter un Portefeuille existant Créer un nouveau Portefeuille Commandez @@ -496,6 +516,73 @@ à %s Via %s Êtes-vous sûr de vouloir annuler la configuration du code d\'accès ? + Sauvegarder maintenant + Pour terminer la configuration, sauvegardez votre portefeuille et sécurisez l\'application à l\'aide d\'un code d\'accès. + Finaliser maintenant + Finaliser la configuration du portefeuille + Terminez la configuration en sécurisant l\'application à l\'aide d\'un code d\'accès. + Si vous quittez, vous devrez recommencer depuis le début. + Êtes-vous sûr de vouloir quitter le processus d\'installation ? + Gardez vos cryptomonnaies en sécurité et hors ligne. Aussi fin qu\'une carte de crédit, plus sûr qu\'un coffre-fort bancaire. + Si vous le faites, vous devrez recommencer depuis le début. + Récupérer un portefeuille existant via la sauvegarde Google Drive + Sauvegarde Google Drive + Créez un portefeuille sécurisé et transférez vos fonds pour bénéficier d\'une protection supplémentaire. + Créer un nouveau portefeuille + Renforcez votre sécurité grâce au Hardware wallet haut de gamme Tangem. + Hardware wallet + Transférez votre portefeuille actuel vers Tangem. + Améliorer le wallet actuel + Aller à la sauvegarde + Veuillez sauvegarder votre portefeuille avant de créer un code d\'accès. + Terminez d\'abord la sauvegarde. + Finalisez d\'abord la sauvegarde. + Incomplet + Autres méthodes + Conservez votre seed phrase dans un endroit sûr et gardez-la confidentielle afin de protéger vos fonds. + Seed phrase + Pour sécuriser votre wallet avec un code d\'accès, effectuez la procédure de sauvegarde. + Pour passer à un portefeuille matériel, terminez le processus de sauvegarde. + Vos clés privées sont cryptées et stockées en toute sécurité sur votre téléphone. + Les clés privées restent sur votre appareil + Créez ou restaurez votre portefeuille à l\'aide d\'une seed phrase. + Sauvegarde de la seed phrase + Créer un wallet mobile + Importer un portefeuille existant + Cette seed phrase a déjà été importée. + Wallet mobile + Oubliez votre portefeuille + Ce portefeuille sera définitivement supprimé de votre appareil. + Êtes-vous sûr de vouloir faire cela ? + Oubliez votre portefeuille + Aller à la sauvegarde + Afficher la sauvegarde + Oubliez votre portefeuille + Oubliez quand même + Ce portefeuille dispose d\'une sauvegarde. Assurez-vous de pouvoir la récupérer avant d\'oublier le portefeuille. + Si vous oubliez ce portefeuille sans sauvegarde, vous perdrez définitivement l\'accès à vos fonds. + Êtes-vous sûr de vouloir oublier ce portefeuille ? + Je comprends que si je n\'ai pas sauvegardé mon portefeuille avant de le supprimer, je perdrai l\'accès à celui-ci. + Je comprends que le fait de supprimer mon portefeuille ne l\'efface pas, mais le supprime uniquement de mon appareil. + Améliorer + Aucune seed phrase n\'est requise. Votre carte ou bague Tangem devient votre sauvegarde sécurisée. + Sauvegarde avec Tangem + Impossible de mettre à niveau. Un portefeuille existe déjà sur cet appareil. + Choisissez un autre appareil. Celui-ci ne peut pas être utilisé pour la mise à niveau. + Une erreur s\'est produite pendant l\'opération. + Vos fonds restent en sécurité et entièrement accessibles pendant toute la durée du processus. + Accès aux fonds + Les données de votre wallet seront effacées de l\'application et stockées sur votre hardware wallet. + Sécurité générale + Les clés privées seront transférées de l\'application vers votre hardware wallet Tangem. + Migration des clés + Scannez l\'appareil + Lancer la mise à niveau + Vous êtes sur le point de passer à notre hardware wallet. Il assurera la sécurité de vos actifs grâce au stockage hors ligne. + Tangem Wallet + Passez à notre Hardware Wallet + Protégez vos cryptomonnaies grâce au hardware wallet haut de gamme de Tangem. + Améliorez la sécurité de votre wallet grâce à un dispositif matériel Ces informations ont été générées avec l\'IA.\nAppuyez ici si vous trouvez des erreurs. Touchez, pour modifier le code d\'accès Touchez, pour modifier le mot de passe @@ -1280,7 +1367,7 @@ Échec de l\'émission de la carte Une erreur technique s\'est produite, veuillez réessayer en cliquant sur le bouton ci-dessous Une erreur technique s\'est produite, veuillez contacter le support - Utilisez vos cryptomonnaies pour vos dépenses quotidiennes. \nC\'est une carte de paiement unique en son genre. + Obtenez votre carte virtuelle Tangem Visa gratuite Obtenir Tangem Pay Contacter le support Cela prend généralement jusqu\'à 15 minutes @@ -1293,8 +1380,8 @@ KYC en cours Voir le statut KYC en cours pour Tangem Pay - Utilisez vos cryptomonnaies pour vos dépenses du quotidien. \nC\'est une carte de paiement unique en son genre. - Tangem Visa Card + Obtenez votre carte virtuelle Tangem Visa gratuite + Utilisez USDC pour les paiements quotidiens Obtenir la carte Avec carte numérique compatible Apple Pay et Google Pay Dépensez vos actifs partout @@ -1304,15 +1391,15 @@ Confidentialité inégalée Obtenez votre carte Tangem Pay gratuite en quelques minutes Compte de paiement - Synchronisation du compte de paiement nécessaire + Le compte de paiement n\'est pas synchronisé Nous réparons un problème technique. Veuillez réessayer plus tard. Service temporairement indisponible Les données ne peuvent pas être affichées pour le moment, mais les paiements par carte fonctionnent toujours. Synchronisation requise - Tangem Visa Card + Utilisez USDC pour les paiements quotidiens Tangem Pay est temporairement indisponible Tangem Pay - Utilisez votre carte ou votre bague pour restaurer l\'accès à votre compte de paiement + Cliquez sur le bouton ci-dessous pour restaurer l\'accès Votre code PIN C\'est mon portefeuille Soldes masqués @@ -1392,6 +1479,7 @@ Activez les notifications pour recevoir des alertes lorsque des fonds arrivent dans votre portefeuille. Ne manquez aucune transaction Ajouter un nouveau portefeuille + Si vous supprimez ce portefeuille sans sauvegarde, vous perdrez définitivement l\'accès à vos fonds. Êtes-vous sûr de vouloir supprimer ce portefeuille ? Une erreur s\'est produite, veuillez scanner votre carte ou bague pour vous connecter Ce portefeuille a déjà été enregistré, vous pouvez en ajouter un autre @@ -1505,6 +1593,8 @@ Ok, compris! Vraiment cool ! Rafraîchir + Selon la documentation officielle de Clore, toutes les pièces reçues avant le 21 décembre seront migrées vers Clore (token ERC-20) ; les pièces reçues après cette date ne le seront pas. Une solution de transfert arrive — restez à l\'écoute. + Migration du réseau Clore Vous êtes actuellement en mode démo Mode démo actif La carte que vous avez scannée est une carte de développeur. Ne l\'utilisez pas pour créer votre portefeuille. diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index b7536b13ca..2e418c1d4c 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -139,7 +139,7 @@ Impossibile emettere la carta Si è verificato un errore tecnico, riprova cliccando il pulsante qui sotto Si è verificato un errore tecnico, contatta il supporto - Utilizza le tue attività per fare acquisti nel mondo reale. \nÈ una carta di pagamento diversa da qualsiasi altra. + Ottieni la tua carta virtuale Tangem Visa gratuita Ottieni Tangem Pay Vai al supporto Di solito richiede fino a 15 minuti @@ -152,8 +152,8 @@ KYC in corso Visualizza stato KYC in corso per Tangem Pay - Utilizza le tue attività per fare acquisti nel mondo reale. \nÈ una carta di pagamento diversa da qualsiasi altra. - Tangem Visa Card + Ottieni la tua carta virtuale Tangem Visa gratuita + Usa USDC per i pagamenti quotidiani Ottieni carta Con carta digitale che funziona con Apple Pay e Google Pay Spendi i tuoi asset ovunque @@ -163,15 +163,15 @@ Privacy senza rivali Ottieni la tua carta Tangem Pay gratuita in pochi minuti Conto di pagamento - Sincronizzazione del conto di pagamento necessaria + Il conto di pagamento non è sincronizzato Stiamo risolvendo un problema tecnico. Riprova più tardi. Servizio temporaneamente non disponibile Al momento non è possibile visualizzare i dati, ma i pagamenti con carta continuano a funzionare. Sincronizzazione necessaria - Tangem Visa Card + Usa USDC per i pagamenti quotidiani Tangem Pay è temporaneamente non disponibile Tangem Pay - Usa la tua carta o il tuo anello per ripristinare l\'accesso al tuo conto di pagamento + Fare clic sul pulsante in basso per ripristinare l\'accesso Il tuo codice PIN Tangem Twin Imposta un codice di 4 cifre.\nVerrà utilizzato per i pagamenti. diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 70f1b95349..f884797c15 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -23,7 +23,7 @@ 回復する 「 %1$s 」を回復しようとしています。 アカウントを回復する - すでにアクティブアカウントの上限(20件)に達しています。復元するには、1つをアーカイブしてください。 + 有効なアカウントは最大20件までです。1つのアカウントをアーカイブすると、このアカウントを復元できます。 アカウントを復元できません アーカイブ済み アカウントをアーカイブできませんでした。しばらくしてからもう一度お試しください。 @@ -43,12 +43,13 @@ アカウントを追加 保存 アカウント名 - アカウント名はすでに存在しています + この名前のアカウントはすでに存在します。別の名前を選択してください。 + このアカウント名はすでに使用されています アカウント 新しいアカウント アカウントを追加 アカウントを編集 - 少し時間をおいて再度お試しください。問題が続く場合はサポートへご連絡ください。こちらで解決をお手伝いします。 + しばらく時間をおいてから、もう一度お試しください。問題が解決しない場合は、サポートにお問い合わせください。こちらで解決をお手伝いします。 %1$s ( %2$s内) メインアカウント すでにアクティブアカウントの上限%1$s件を超えています。復元するには、1つをアーカイブしてください。 @@ -422,7 +423,6 @@ トークンは誰でも作成できることに注意してください。 Tangemウォレットを購入 チャット - Tangem Visaを入手 アクセスコード カードをスキャンする前に、正しいアクセスコードを送信する必要があります。 長くタップ @@ -593,11 +593,13 @@ アクセスコードを作成する前にウォレットをバックアップしてください。 先にバックアップを完了してください まずバックアップを完了する + 未完了 その他の方法 資金を保護するため、リカバリーフレーズは安全な場所に保管し、他人に知られないようにしてください。 リカバリーフレーズ アクセスコードでウォレットを保護するには、バックアップの手続きを完了してください。 ハードウェアウォレットにアップグレードするには、バックアップの手続きを完了してください。 + 秘密鍵は安全に暗号化され、スマートフォン上に保存されています 秘密鍵はデバイス上に保持されます リカバリーフレーズを使ってウォレットを作成または復元してください。 シードフレーズのバックアップ @@ -618,6 +620,7 @@ このウォレットを削除してもよろしいですか? ウォレットを削除する前にバックアップを行っていない場合、ウォレットへのアクセスを失うことを理解しています。 ウォレットを削除しても中身自体が消えるわけではなく、このデバイスから表示が消えるだけであることを理解しています。 + アップグレード シードフレーズは不要です。Tangemカードまたはリングが安全なバックアップとなります。 Tangemでバックアップ アップグレードできません。このデバイスにはすでにウォレットが存在します。 @@ -790,12 +793,16 @@ モバイルウォレットを作成するには、%1$sにアップデートする必要があります モバイルウォレットを使用するには、%1$s以降が必要です すべてのニュース + いいね %d時間前 %d分前 + クイックまとめ + 関連ニュース + 情報源 最新情報を入手 お使いのデバイスではNFCが使用できません NFTについて @@ -942,7 +949,7 @@ 通知 バックアップデバイスが1つ追加されました カードまたはリングを用意してください - バックアップデバイス2つが追加されました + バックアップデバイスが2つ追加されました 始めるには、ウォレットに任意の金額を入金するだけです 始めるには、ウォレットに%1$s %2$s以上入金するだけです 暗号資産を購入する @@ -1469,7 +1476,7 @@ カードの発行に失敗しました 技術的なエラーが発生しました。下のボタンをクリックして、もう一度お試しください。 技術的なエラーが発生しました。サポートへお問い合わせください。 - 暗号資産を日常の支払いに使おう。\n\nこれまでにないタイプの決済カード。 + 無料のTangem Visaバーチャルカードを入手 Tangem Payを入手 サポートへ移動 通常は最大で15分ほどかかります @@ -1477,14 +1484,16 @@ カードを発行しています カードを準備しています。少し時間がかかる場合があります。 Tangem Pay + 中止を確定する + KYC手続きを中止しますか?いつでも再開できます。 プロフィールを確認できませんでした。ご不明な点があればサポートまでお問い合わせください。 申し訳ございませんが、本人確認を行うことができませんでした KYC進行中 ステータスを表示 Tangem PayのKYC手続き進行中 以下のボタンから、現在のKYCステータスを確認するか、KYCをキャンセルできます。 - 暗号資産を、リアルな支払いに。\n他とはまったく違う、新しいタイプの決済カード。 - Tangem Visaカード + 無料のTangem Visaバーチャルカードを入手 + 日常の支払いにUSDCを利用 カードをGET Apple PayとGoogle Payに対応したデジタルカード付き どこでも暗号資産を使える @@ -1494,15 +1503,15 @@ 他に類を見ないプライバシー 無料のTangem Payカードを数分でゲットしましょう 支払いアカウント - 支払いアカウントの同期が必要です + 支払アカウントが同期されていません 技術的な問題を修正しています。後でもう一度お試しください。 サービスは一時的に利用できません 現在、データを表示できませんが、カードでのお支払いは引き続きご利用いただけます。 同期が必要です - Tangem Visaカード + 日常の支払いにUSDCを利用 Tangem Payは現在一時的に利用できません。 Tangem Pay - カードまたはリングを使用して、支払いアカウントへのアクセスを復元してください。 + 下のボタンをクリックしてアクセスを復元してください PINコード これは私のウォレットです 残高非表示 @@ -1617,7 +1626,7 @@ ロック解除 カードをスキャンしてアクセスロックを解除する ロック解除が必要 - ウォレットの追加方法を選択してください + ウォレットの種類を選択します Tangemカードまたはリングをスキャンして復元するか、別のウォレットからインポートしてください。 ハードウェアウォレットを作成 Tangemウォレットを購入しますか? diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 036b504b45..d34a9ed9b6 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -54,7 +54,7 @@ Нажмите и удерживайте аккаунт, чтобы изменить порядок аккаунтов. Продолжить Отменить - Вы уверены, что хотите создание нового аккаунта? + Вы уверены, что хотите отменить создание нового аккаунта? Вы уверены, что хотите отменить изменения? Несохраненные изменения Некоторые пользовательские токены были перемещены из «%1$s» в «%2$s», поскольку их путь деривации относится к этой учётной записи. @@ -460,7 +460,7 @@ Проверьте подключение с интернетом или переключитесь на другую сеть Условия использования Основной адрес - Legacy адрес + Legacy %s адрес Получить активы %s адрес Отправка средств в другой сети может повлечь потерю средств. @@ -551,6 +551,7 @@ Скажите, пожалуйста, какая у вас карта или кольцо? Привет, команда поддержки, Пожалуйста, расскажите нам больше о вашей проблеме. Каждая маленькая деталь может помочь. + Проблема резервного копирования Ранее активированный кошелек Мои предложения Не могу отсканировать карту/кольцо @@ -1457,6 +1458,7 @@ Не удалось разморозить карту, попробуйте еще раз Карта разморожена Вывести + Запрещено использовать на root-устройствах Пополнить Способы пополнения Номер @@ -1484,6 +1486,7 @@ Всё готово! Можно пользоваться картой Добавьте карту в Google Pay Добавить карту в Apple Pay + ПИН-код Скопируйте свой адрес или покажите QR Техническая ошибка. Попробуйте позже или обратитесь в поддержку. Пополнение недоступно @@ -1492,6 +1495,7 @@ Пополните карту любым активом через обмен Реквизиты Разморозить карту + Ваш ПИН Вывести Вывод сейчас недоступен Вы не можете начать обмен или новый вывод, пока не завершится текущий. @@ -1502,7 +1506,7 @@ Не удалось выпустить карту Техническая ошибка, попробуйте ещё раз, нажав кнопку ниже Техническая ошибка, свяжитесь с поддержкой - Используйте криптовалюту в реальной жизни. \nКарта, не похожая ни на одну другую. + Откройте бесплатную виртуальную карту Tangem Visa Получить Tangem Pay Написать в поддержку Обычно это занимает до 15 минут @@ -1515,8 +1519,9 @@ KYC в процессе Посмотреть статус KYC в процессе для Tangem Pay - Используйте криптовалюту в реальной жизни. \nКарта, не похожая ни на одну другую. - Tangem Visa Card + Вы можете посмотреть текущий статус KYC или отменить его + Откройте бесплатную виртуальную карту Tangem Visa + Оплачивайте ежедневные покупки в USDC Открыть карту Виртуальную карту можно добавить в Apple Pay и Google Pay Покупайте где угодно @@ -1526,15 +1531,15 @@ Абсолютная приватность Откройте виртуальную \nTangem Pay Card Платежный аккаунт - Требуется синхронизация платежного аккаунта + Платежный аккаунт не синхронизирован Мы устраняем техническую проблему. Пожалуйста, попробуйте позже. Сервис временно недоступен Не можем показать данные карты, но оплаты продолжают работать. - Требуется синхронизация - Tangem Visa Card + Не синхронизирован + Оплачивайте ежедневные покупки в USDC Tangem Pay временно недоступен Tangem Pay - Используйте вашу карту или кольцо для восстановления доступа к платежному аккаунту + Нажмите на кнопку ниже, чтобы восстановить доступ Ваш PIN-код Это мой кошелек Балансы скрыты @@ -1634,7 +1639,7 @@ ПИН не принят. Попробуйте ещё раз или введите другой код. Слабый ПИН: не используйте повторы или последовательности. Разблокировать - Выберите способ добавления кошелька + Выберите тип кошелька Отсканируйте вашу карту или кольцо Tangem, чтобы восстановить её или импортировать из другого кошелька. Создать аппаратный кошелёк Хотите приобрести кошелек Tangem? @@ -1735,6 +1740,8 @@ Понятно! Очень круто! Обновить + Согласно официальной документации Clore, все монеты, полученные до 21 декабря, будут мигрированы в токен Clore (ERC-20); монеты, полученные после этой даты, — нет. Решение для перевода находится в разработке — следите за обновлениями. + Миграция сети Clore Вы находитесь в режиме демо Демо режим включен Отсканированная вами карта является картой разработчика. Не используйте ее для создания своего кошелька. 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 92eff0a832..6df04c2899 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -49,6 +49,19 @@ Системна Тема Налаштування застосунку + Ви успішно створили резервну копію свого гаманця. + Ці слова неможливо відновити у разі втрати. Зберігайте їх надійно. + Бекап завершено + Ваша фраза відновлення — це набір випадкових слів %s для доступу та відновлення гаманця. + Ці слова неможливо відновити, якщо їх загубити. Зберігайте їх у безпеці. + Зберігайте в безпеці + Збережіть ці %s слова в безпечному місці та нікому не розповідайте про них. + Відновлення неможливе + Фраза відновлення + Наведені нижче слова %s - це фраза для відновлення вашого гаманця. Ніколи і нікому не повідомляйте ці слова. Tangem ніколи не запитає їх у вас. Використовуйте їх, щоб відновити свій гаманець, якщо ви втратите пристрій. + Запишіть ці %s слова в указаному порядку і зберігайте їх у безпеці та таємниці. + Ви несете повну відповідальність за безпеку свого гаманця і фрази відновлення. + Фраза відновлення Щоб приховати або показати свій баланс, просто переверніть екран пристрою вниз або вимкніть його в налаштуваннях Більше не показувати Зрозуміло @@ -310,7 +323,7 @@ Перевірте підключення до інтернету або змініть мережу Умови використання Основна адреса - Legacy адреса + Legacy %s адреса Отримати активи %s адреса Надсилання активів в інші мережі призведе до безповоротної втрати. @@ -395,6 +408,7 @@ Розкажіть, будь ласка, яку картку або кільце ви маєте? Привіт, команда підтримки, Будь ласка, розкажіть нам більше про вашу проблему. Кожна дрібниця може допомогти. + Проблема з резервним копіюванням Раніше активований гаманець Мої пропозиції Не вдається відсканувати картку/кільце @@ -413,11 +427,85 @@ Щоб продовжити, вам потрібно дозволити смарт-контракту %1s використовувати ваш %2s Надати дозвіл Необмежено + Резервна копія створюється на 2–3 картках Tangem. Зберігайте їх окремо для безпеки — seed-фраза не потрібна. + Бекап на декілька карток + Додати гаманець Tangem + Ваш приватний ключ генерується на картці Tangem і ніколи не покидає її. + Генерація ключа + Операції з криптографією відбуваються всередині захищеного чіпу, стійкого до клонування та фізичному взлому. + Безпека на апаратному рівні Створити новий гаманець Купити Сканувати в %s В мережі %s + Ви впевнені, що хочете скасувати процес створення коду доступу? + Створити бекап + Щоб завершити налаштування, створіть резервну копію свого гаманця та захистіть додаток за допомогою коду доступу. + Завершити зараз + Завершити налаштування гаманця + Завершіть налаштування, захистивши додаток кодом доступу. + Якщо ви вийдете, вам доведеться починати спочатку. + Ви впевнені, що хочете вийти з процесу активації? + Зберігає ваші криптовалюти в безпеці та в режимі офлайн. Тонкий, як кредитна картка, безпечніший за банківське сховище. + Якщо ви це зробите, доведеться почати спочатку. + Відновлення існуючого гаманця за допомогою резервної копії Google Диску + Google Диск бекап + Створіть новий захищений гаманець і переведіть свої кошти для додаткового захисту. + Створити новий гаманець + Підвищіть рівень своєї безпеки за допомогою просунутого апаратного гаманця Tangem. + Апаратний гаманець + Перенесіть свій поточний гаманець у Tangem. + Оновіть поточний гаманець + Перейти до бекапу + Будь ласка, створіть резервну копію свого гаманця, перш ніж створювати код доступу. + Спочатку завершіть резервне копіювання + Спочатку завершіть резервне копіювання + Не завершено + Інші методи + Збережіть фразу відновлення у безпечному місці і тримайте її у таємниці. + Фраза відновлення + Щоб захистити свій гаманець за допомогою коду доступу, завершіть процес резервного копіювання. + Щоб покращити гаманець до апаратного, спочатку створіть резервну копію. + Ваші приватні ключі надійно зашифровані та зберігаються на вашому телефоні + Ключі зберігаються у застосунку + Створіть або відновіть свій гаманець за допомогою вашої фрази відновлення. + Резервна копія + Створити мобільний гаманець + Імпортувати існуючий гаманець + Ця фраза відновлення вже була імпортована + Мобільний гаманець + Забути гаманець + Цей гаманець буде назавжди видалено з вашого пристрою + Ви впевнені, що хочете виконати цю операцію? + Забути гаманець + Перейти до резервної копії + Переглянути резервне копіювання + Забути гаманець + Все одно забути + Резервна копія цього гаманця існує. Перевірте її перед видаленням, щоб переконатися, що зможете відновити гаманець пізніше. + Якщо ви видалите цей гаманець без резервної копії, ви назавжди втратите доступ до своїх коштів. + Забути цей гаманець? + Я розумію, що якщо я не створив резервну копію гаманця перед його видаленням, я можу втратити досту до нього. + Я розумію, що видалення мого гаманця не видаляє його повністю, а просто видаляє його з мого пристрою. + Фраза відновлення більше не потрібна — ваша картка або кільце Tangem стає вашою безпечною резервною копією. + Резервне копіювання з Tangem + Цей пристрій не може бути використаний для оновлення, він вже містить інший гаманець. + Виберіть інший пристрій. Цей не можна використовувати для оновлення. + Під час операції виникла помилка. + Ваші кошти залишаються в безпеці та повністю доступними протягом усього процесу + Доступ до коштів + Данні вашого гаманця будуть видалені із застосунку і збережені на вашому пристрої Tangem. + Загальна безпека + Приватні ключі будуть переміщені з додатку у вашу Tangem картрку або кільце + Міграція ключів + Сканувати пристрій + Розпочати оновлення + Ви збираєтеся перейти на пристрій Tangem, де ваші активи будуть у безпеці в холодному сховищі. + Tangem Wallet + Оновіть до апаратного гаманця + Зберігайте свою криптовалюту в безпеці за допомогою першокласного апаратного гаманця Tangem. + Оновіть свій гаманець до апаратної версії. Ця інформація була створена за допомогою ШІ.\nНатисніть тут, якщо знайшли помилку. Щоб змінити код доступу, прикладіть картку або кільце, як показано вище, і не прибирайте її до закінчення операції Щоб змінити пароль, прикладіть картку, як показано вище, і не прибирайте її до закінчення операції @@ -1141,9 +1229,14 @@ Показати деталі Обміняйте будь-який актив у вашому портфелі на картку Розморозити картку - Tangem Visa Card + Отримайте безкоштовну віртуальну картку Tangem Visa + Отримайте безкоштовну віртуальну картку Tangem Visa + Використовуйте USDC для щоденних платежів + Платіжний рахунок не синхронізовано Ми усуваємо технічну проблему. Будь ласка, спробуйте пізніше. Сервіс тимчасово недоступний + Використовуйте USDC для щоденних платежів + Натисніть кнопку нижче, щоб відновити доступ Це мій гаманець Баланси приховано Баланси показано @@ -1220,6 +1313,7 @@ Нові функції та важливі новини Бажаєте використовувати Push-повідомлення? Додати новий гаманець + Якщо ви видалите цей гаманець без резервної копії, ви назавжди втратите доступ до своїх коштів. Ви впевнені, що хочете видалити цей гаманець? Сталася помилка, будь ласка, відскануйте свою картку або кільце, для входу Цей гаманець вже збережено, ви можете додати інший @@ -1290,6 +1384,8 @@ Зрозуміло! Дуже круто! Оновити + Згідно з офіційною документацією Clore, усі монети, отримані до 21 грудня, будуть мігровані в токен Clore (ERC-20); монети, отримані після цієї дати, — ні. Рішення для переказу перебуває в розробці — стежте за оновленнями. + Міграція мережі Clore Ви перебуваєте в демонстраційному режимі Демонстраційний режим активовано Відсканована вами картка є карткою розробника. Не використовуйте її для створення гаманця. 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 6fa2c8b69c..a79d66c1d7 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -382,7 +382,7 @@ 无法发行卡片 出现技术错误,请点击下方按钮重试 出现技术错误,请联系客服 - 使用您的加密货币进行真实世界消费。\n这是一张与众不同的支付卡。 + 獲取您的免費 Tangem Visa 虛擬卡 获取Tangem Pay 前往客服中心 通常需要最多15分钟 @@ -395,8 +395,8 @@ KYC进行中 查看状态 Tangem Pay 的 KYC 正在進行中 - 使用您的加密货币进行真实世界消费。这是一张与众不同的支付卡。 - Tangem Visa Card + 獲取您的免費 Tangem Visa 虛擬卡 + 使用 USDC 進行日常支付 获取卡片 使用支援 Apple Pay 和 Google Pay 的數位卡 在任何地方花费您的资产 @@ -406,15 +406,15 @@ 無與倫比的隱私 在幾分鐘內獲得免費的 Tangem Pay 卡 付款帳戶 - 需要同步支付账户 + 付款帳戶未同步 我们正在修复技术问题。请稍后再试。 服務暫時無法使用 目前無法顯示資料,但卡片支付仍可正常使用。 需要同步 - Tangem Visa Card + 使用 USDC 進行日常支付 Tangem Pay暂时不可用 Tangem Pay - 使用您的卡片或戒指恢复对支付账户的访问 + 點擊下方按鈕以恢復存取權限 您的PIN码 隱藏 您即將在主屏幕上隱藏此代幣。您可以隨時通過管理代幣頁面將其添加回來。 diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index f323d25978..3a61dcb024 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -23,12 +23,12 @@ Recover You’re about to recover “%1$s”. Recover account - You have already exceeded the limit of 20 active accounts. Archive one to recover. + You’ve reached the limit of 20 active accounts. Archive one account to recover this one. Can\'t recover account Archived We couldn’t archive account. Please try again later. - This account participates in the referral program. - This account cannot be archived. + This account is participating in the referral program. + This account can’t be archived We couldn’t create account. Please try again later. Account created Archive account @@ -43,12 +43,13 @@ Add account Save Account name - Account name already exists + An account with this name already exists. Please choose a different name. + Account name already in use Account New account Add account Edit account - Please try again later. If it keeps happening, get in touch with support and we’ll help you resolve it. + Please try again later. If the problem persists, contact support and we’ll help you resolve it. %1$s in %2$s Main account You have already exceeded the limit of %1$s active accounts. Archive one to recover @@ -127,15 +128,15 @@ Mobile Wallet You successfully backed up your wallet. - These words are unrecoverable if lost. Keep them somewhere safe. + These words cannot be recovered if lost. Store them securely. Backup completed - Your secret recovery phrase is a fixed set of %s random words for accessing and recovering your wallet. + Your secret recovery phrase is a set of %s random words for accessing and recovering your wallet. These words cannot be recovered if lost. Keep them safe. Keep it safe Save these %s words in a secure location and never share them with anyone. No recovery possible Recovery phrase - Never share these words with anyone. Tangem will never ask you for them. The %s words below are your wallet\'s recovery phrase. Use them to restore your wallet if you lose your device. + The %s words below are your wallet\'s recovery phrase. Never share these words with anyone. Tangem will never ask you for them. Use them to restore your wallet if you lose your device. Write down these %s words in numerical order and keep them safe and private You are fully responsible for securing your wallet and safely backing up your recovery phrase. Recovery phrase @@ -430,7 +431,6 @@ Note that tokens can be created by anyone Buy Tangem Wallet Chat - Get Tangem Visa Access code You will have to submit the correct access code before scanning the card Long Tap @@ -547,6 +547,7 @@ Please tell us what card or ring do you have Hi support team, Please tell us more about your issue. Every small detail can help. + Backup issue Previously activated wallet My suggestions Can\'t scan a card/ring @@ -565,8 +566,8 @@ To continue, grant %1s smart contracts permission to use your %2s Give Permission Unlimited - Your backup is created using 2 or 3 Tangem cards. Keep them in separate safe places to protect against loss or damage — no seed phrase needed. - Backup with Multiple Cards + A backup is created using 2–3 Tangem cards. Store them separately in secure locations to protect against loss or damage. No seed phrase needed. + Backup With Multiple Cards Add Tangem Wallet Your private key is generated directly inside the Tangem card and never leaves it. Key Generation @@ -586,7 +587,7 @@ Finalize wallet setup Complete setup by securing the app with an access code. If you exit, you\'ll need to start over. - Are you sure you want to quit the setup process? + Are you sure you want to quit activation? Keeps your crypto safe and offline. Slim as a credit card, safer than a bank vault. If you do, you\'ll need to start over. Recover existing wallet via Google Drive backup @@ -599,7 +600,7 @@ Upgrade current wallet Go to backup Please back up your wallet before creating an access code. - Finish backup first + Complete the backup first Finalize backup first Incomplete Other methods @@ -628,14 +629,15 @@ Are you sure you want to forget this wallet? I understand that if I haven\'t backed up my wallet before removing it, I will lose access to it. I understand that removing my wallet does not delete it, only removes it from my device. + Upgrade Seed phrase not required. Your Tangem card or ring becomes your secure backup. - Backup with Tangem + Backup With Tangem Can\'t upgrade. A wallet already exists on this device. - Pick another device. This one can’t be used for the upgrade. + Pick another device. This one can\'t be used for the upgrade. An error occurred during the operation. Your funds remain safe and fully accessible during the process Access to funds - Your wallet data will be erased from the app and stored on your hardware wallet + Your wallet information will be erased from the app and stored on your hardware wallet General security Private keys will be moved from the app to your Tangem hardware wallet Key migration @@ -803,6 +805,7 @@ You must update to %1$s before creating a mobile wallet Mobile Wallet requires %1$s or later All news + Like %dh ago %dh ago @@ -811,6 +814,9 @@ %d minute ago %d minutes ago + Quick recap + Related News + Sources Stay in the loop NFC is not available on your device About NFT @@ -894,8 +900,8 @@ Please repeat the operation. The card will be reset to factory settings. Activation error Add tokens - You\'ve added one backup card or ring. When backup process is finished you can\'t add more backup devices. If you have one more card or ring, add it to the backup. Would you like to continue the backup process? - The backup process is partly complete. You can\'t exit it now. + You\'ve added one backup card or ring. Once backup is finalized, you can\'t add more devices. If you have one more card or ring, add it now. Do you want to continue? + The backup is partially complete and can\'t be quit now. A passphrase is an optional security feature that adds a word or phrase to your recovery phrase, creating a new set of wallet addresses for extra protection. Add a card or ring Scan card @@ -945,7 +951,7 @@ Legacy To check whether you’ve written down your seed phrase correctly, please enter the 2nd, 7th and 11th words So, let’s check - To start the backup process add up to two backup cards or rings. + To start the backup process, add up to two backup cards or rings. You can add one more card or ring or finalize the backup process Prepare the backup card with number %s Scan the primary card or ring to start the backup process. @@ -1084,8 +1090,8 @@ I understand that after performing this action, I will no longer have access to the current wallet I realize that I can\'t use this card to recover my access code on the other cards of the current wallet I understand that I will completely lose access to my Tangem Pay Card and all funds on it without the possibility of recovery - Factory Reset will completely delete the wallet from the selected card or ring. You will not be able to restore the current wallet or use the card or ring to recover the access code. - Factory Reset will completely delete the wallet from the selected card or ring and remove it from the app. You will not be able to restore the current wallet. + A factory reset completely erases the wallet from the selected card or ring. You will not be able to restore the current wallet or use this card or ring to recover the access code. + A factory reset completely erases the wallet from the selected card or ring and removes it from the app. You will not be able to restore the current wallet. All Tangem devices have been reset. Something went wrong with the activation process. Please reset the cards one by one. Card verification failed @@ -1370,7 +1376,7 @@ Your stakes Store your crypto assets secure while keeping private keys contained in your card or ring Revolutionary Hardware Wallet - Up to 3 physical cards or rings to one wallet + Add up to 3 cards or rings to one wallet Ultra Secure Backup A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously — all in one card or ring Thousands of Currencies @@ -1493,7 +1499,7 @@ Failed to issue card A technical error has occurred, please try again by clicking the button below. A technical error has occurred, please contact support. - Use your crypto for real world spending. \nIt\'s a payment card unlike any other. + Get your free Tangem Visa virtual card Get Tangem Pay Go to Support It usually takes up to 15 minutes @@ -1501,14 +1507,16 @@ Issuing your card We’re getting your card ready. This may take a little time. Tangem Pay + Confirm Cancellation + Are you sure you want to stop the KYC process? You can return to it anytime. We could not verify your profile. If you have any questions, please contact support. Unfortunately, we couldn\'t verify your identity KYC in progress View Status KYC in progress for Tangem Pay Use the buttons below to view your current KYC status or cancel it. - Use your crypto for real world spending. \nIt’s a payment card unlike any other. - Tangem Visa Card + Get your free Tangem Visa virtual card + Use USDC for everyday payments Get card With digital card that works with Apple Pay and Google Pay Spend your assets anywhere @@ -1518,15 +1526,16 @@ Unrivaled privacy Get your free Tangem Pay Card in minutes Payment account - Payment account sync needed + Payment account is not synced We’re fixing a technical issue. Please try again later. Service temporarily unavailable Unable to display details. However, card payments are still working. - Sync needed - Tangem Visa Card + Not synced + Restore access + Use USDC for everyday payments Tangem Pay is temporarily unreachable Tangem Pay - Use your card or ring to restore access to your payment account + Click the button below to restore access Your PIN code This is my wallet Balances hidden @@ -1686,7 +1695,7 @@ Unlock Scan your card to unlock access Needed unlock - Choose how to add your wallet + Choose your wallet type Scan your Tangem card or ring to restore it or import from another wallet. Create Hardware Wallet Want to purchase a Tangem Wallet? @@ -1776,7 +1785,7 @@ Use %s or scan a card/ring to unlock access to your wallet The permission-granting process is currently underway and will be completed shortly Approval in Progress - It seems that the card or ring activation was not completed correctly. This could be due to an issue with your device\'s NFC module or incorrect tapping of the card or ring to your device. Please contact our Support team for assistance. + Activation was not completed successfully. This may be due to an NFC issue or incorrect tapping. Please contact our Support team for assistance. Activation error On December 3, 2024, the BEP-2 network was disabled by decision of the network developers and is no longer supported BNB Beacon Chain shut down @@ -1787,7 +1796,7 @@ Ok, Got it! Really cool! Refresh - According to Clore’s official documentation, all tokens received before December 21 will be migrated to Clore (ERC20); tokens received after will not. Transfer solution coming — stay tuned. + According to Clore’s official documentation, all coins received before December 21 will be migrated to Clore (ERC-20 token); coins received after that date will not. A transfer solution is coming — stay tuned. Clore Network Migration You are currently in the Demo mode Demo mode active @@ -1837,7 +1846,7 @@ The network is currently unreachable. Please try again later. Network is unreachable Top up your wallet - Your wallet hasn\'t been backed up. Carry out this procedure to protect your assets now. + Your wallet isn\'t backed up yet. Back it up now to protect your assets. Missing backup This card has been previously used for transactions. If received from an untrusted source, consider withdrawing all funds. If it\'s your card, no action is required. Card has already signed transactions @@ -1977,10 +1986,10 @@ Use a Tangem hardware wallet Learn more & buy Discard - You have an interrupted backup. Do you want to resume? + Your backup was interrupted. Do you want to resume? Yes, resume Discard - If you discard the backup now, then you will have to reset the devices to factory settings to start over again + If you discard the backup now, you will have to reset the devices to factory settings to start over again Resume backup This is an irreversible action Log in with %s From 774f25bf4a381bee3672aa880a62e0a0411759d5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 25 Dec 2025 17:45:06 +0500 Subject: [PATCH 19/36] Updated on 2026-08-14 --- core/res/src/main/res/values-de/strings.xml | 28 ++++-- core/res/src/main/res/values-es/strings.xml | 88 +++++++++++++++-- core/res/src/main/res/values-fr/strings.xml | 99 +++++++++++++++++-- core/res/src/main/res/values-it/strings.xml | 12 +-- core/res/src/main/res/values-ja/strings.xml | 30 ++++-- core/res/src/main/res/values-ru/strings.xml | 20 ++-- .../src/main/res/values-uk-rUA/strings.xml | 95 +++++++++++++++++- .../src/main/res/values-zh-rTW/strings.xml | 12 +-- core/res/src/main/res/values/strings.xml | 74 ++++++++------ .../wallet/state/model/WalletNotification.kt | 7 +- .../TangemPayRefreshNeededStateTransformer.kt | 7 ++ .../subscribers/TangemPayMainSubscriber.kt | 1 + .../components/visa/TangemPayRefreshBlock.kt | 1 + 13 files changed, 389 insertions(+), 85 deletions(-) diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index be2b45ae50..cefd04ae41 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -44,6 +44,7 @@ Speichern Kontoname Der Kontoname ist bereits vorhanden + Der Kontoname wird bereits verwendet. Konto Neues Konto Konto hinzufügen @@ -593,10 +594,13 @@ Aktualisiere Deine aktuelle Wallet Gehe zum Backup Bitte sicher Deine Wallet, bevor Du einen Zugangscode erstellst. + Sicherung zuerst beenden Zuerst die Sicherung abschließen Unvollständig Andere Methoden + Speicher Deinen Wiederherstellungssatz an einem sicheren Ort und halte diesen stets geheim, um Dein Geld zu schützen. Wiederherstellungs-Phrase + Um Deine Wallet mit einem Zugangscode zu sichern, schließe den Sicherungsvorgang ab. Um Deine Wallet auf Hardware umzustellen, erstelle vorher ein Backup. Deine privaten Schlüssel sind sicher verschlüsselt und auf Deinem Telefon gespeichert. Schlüssel werden in der App gespeichert @@ -617,8 +621,9 @@ Für diese Wallet existiert ein Backup. Überprüfe dieses bitte, bevor Du sie entfernst, um sicherzustellen, dass Du sie später wiederherstellen kannst. Wenn Du diese Wallet ohne Backup entfernst, verlierst Du dauerhaft den Zugriff auf Deine Assets. Diese Wallet dauerhaft entfernen? - Mir ist bewusst, dass ich den Zugriff auf meine Wallet verliere kann, wenn ich sie vor der Entfernung nicht gesichert habe. + Mir ist bewusst, dass ich den Zugriff auf meine Wallet verlieren kann, wenn ich sie vor der Entfernung nicht gesichert habe. Mir ist bewusst, dass durch das Entfernen meiner Wallet diese nicht gelöscht, sondern lediglich von meinem Gerät entfernt wird. + Upgrade Es wird keine Seed-Phrase mehr benötigt – Deine Tangem-Karte oder Dein Tangem-Ring wird zu Deinem sicheren Backup. Backup mit Tangem Ein Upgrade ist nicht möglich. Auf diesem Gerät ist bereits eine Wallet vorhanden. @@ -793,6 +798,10 @@ Du musst auf die folgende Version aktualisieren: %1$s um eine mobile Wallet zu erstellen Mobile Wallet erfordert %1$s oder später Alle Neuigkeiten + Gefällt mir + Kurze Zusammenfassung + Verwandte Nachrichten + Quellen Auf dem Laufenden bleiben NFC ist auf deinem Gerät nicht verfügbar Über NFT @@ -1419,6 +1428,7 @@ Entsperren der Karte fehlgeschlagen. Versuchen Sie es später erneut. Ihre Karte ist entsperrt. Abhebung + KYC abbrechen Guthaben hinzufügen Aufladeoptionen Kartennummer @@ -1446,6 +1456,7 @@ Alles erledigt! Deine Karte ist einsatzbereit. Karte zu Google Pay hinzufügen Karte zu Apple Pay hinzufügen + Pin Code Teile Deine Adresse mit oder zeig den QR-Code. Es wurden technische Probleme festgestellt. Bitte versuche es später erneut oder kontaktiere den Support. Empfangen ist jetzt nicht verfügbar @@ -1454,6 +1465,7 @@ Tausche beliebige Vermögenswerte in Deinem Portfolio gegen eine Karte. Kartendetails Karte entsperren + Dein PIN-Code Auszahlung Auszahlung derzeit nicht möglich Sie können keinen Tausch oder eine neue Auszahlung starten, bis die aktuelle abgeschlossen ist. @@ -1463,7 +1475,7 @@ Kartenausstellung fehlgeschlagen Ein technischer Fehler ist aufgetreten, bitte versuchen Sie es erneut, indem Sie auf die Schaltfläche unten klicken Ein technischer Fehler ist aufgetreten, bitte kontaktieren Sie den Support - Nutzen Sie Ihre Kryptowährungen für Einkäufe im Alltag. \nEine Zahlungskarte, die ihresgleichen sucht. + Holen Sie sich Ihre kostenlose virtuelle Tangem Visa-Karte Tangem Pay erhalten Zum Support Es dauert in der Regel bis zu 15 Minuten. @@ -1471,13 +1483,15 @@ Ausstellung Deiner Karte Wir bereiten Ihre Karte vor. Dies kann etwas dauern. Tangem Pay + Konvertierung bestätigen + Möchtest Du den KYC wirklich abbrechen? Du kannst später jederzeit weiter machen. Wir konnten Ihr Profil nicht verifizieren. Bei Fragen wenden Sie sich bitte an den Support. Leider konnten wir Ihre Identität nicht verifizieren KYC in Bearbeitung Status anzeigen KYC für Tangem Pay in Arbeit - Nutzen Sie Ihre Kryptowährungen für Einkäufe im echten Leben. \nEs ist eine Zahlungskarte, die ihresgleichen sucht. - Tangem Visa Card + Holen Sie sich Ihre kostenlose virtuelle Tangem Visa-Karte + Nutzen Sie USDC für alltägliche Zahlungen Karte erhalten Mit digitaler Karte, die mit Apple Pay und Google Pay funktioniert Geben Sie Ihre Vermögenswerte überall aus @@ -1487,15 +1501,15 @@ Unerreichte Privatsphäre Erhalten Sie Ihre kostenlose Tangem Pay Card in wenigen Minuten Zahlungskonto - Synchronisierung des Zahlungskontos erforderlich + Zahlungskonto ist nicht synchronisiert Wir beheben ein technisches Problem. Bitte versuchen Sie es später erneut. Service vorübergehend nicht verfügbar Daten können derzeit nicht angezeigt werden, Kartenzahlungen funktionieren jedoch weiterhin. Synchronisation erforderlich - Tangem Visa Card + Nutzen Sie USDC für alltägliche Zahlungen Tangem Pay ist vorübergehend nicht verfügbar Tangem Pay - Verwenden Sie Ihre Karte oder Ihren Ring, um den Zugriff auf Ihr Zahlungskonto wiederherzustellen + Klicken Sie auf die Schaltfläche unten, um den Zugriff wiederherzustellen Ihr PIN-Code Das ist meine Wallet Guthaben versteckt diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 92108a3ab5..c1cf00a410 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -80,6 +80,7 @@ Seleccione una billetera para iniciar sesión ¡Bienvenido de nuevo! Realizó una copia de seguridad de su billetera correctamente. + Estas palabras son irrecuperables si se pierden. Guárdelas en un lugar seguro. Copia de seguridad completada Su frase secreta de recuperación es un conjunto fijo de %s palabras aleatorias que se utilizan para acceder a su billetera y recuperarla. Estas palabras no pueden recuperarse si se pierden. Asegúrese de guardarlas en un lugar seguro. @@ -87,6 +88,7 @@ Guarde estas %s palabras en un lugar seguro, como un administrador de contraseñas, y nunca las comparta con nadie. No se puede restaurar Frase de recuperación + Nunca comparta estas palabras con nadie. Tangem nunca se las pedirá. Las palabras %s que aparecen a continuación son la frase de recuperación de su billetera. Úselas para restaurar su billetera si pierde su dispositivo. Escriba estas %s palabras en orden y guárdelas en un lugar privado y seguro La responsabilidad total sobre la seguridad y copia de seguridad de la billetera y su frase de recuperación recae en el usuario, no en Tangem. Frase de recuperación @@ -507,6 +509,13 @@ Para continuar, conceda a los contratos inteligentes de %1s permiso para utilizar su %2s Dar autorización Ilimitado + Su copia de seguridad se crea utilizando 2 o 3 tarjetas Tangem. Guárdalas en lugares seguros y separados para protegerlas de pérdidas o daños. + Copia de seguridad con varias tarjetas + Agregar billetera Tangem + Su clave privada se genera directamente dentro de la tarjeta Tangem y nunca sale de ella. + Generación de claves + Todas las operaciones criptográficas ocurren dentro del chip seguro, certificado contra la clonación y la manipulación física. + Seguridad a nivel de hardware Agregar Billetera Existente Crear Nueva Billetera Pedir Tangem @@ -515,7 +524,73 @@ a %s En la red %s ¿Está seguro de que desea salir del proceso de creación de código de acceso? + Hacer copia ahora + Para completar la configuración, haga una copia de seguridad de su billetera y proteja la aplicación con un código de acceso. + Finalizar ahora + Finalizar la configuración de la billetera + Complete la configuración protegiendo la aplicación con un código de acceso. + Si sale, tendrá que empezar de nuevo. + ¿Está seguro de que desea salir del proceso de configuración? + Mantiene sus criptomonedas seguras y sin conexión. Tan delgadas como una tarjeta de crédito, más seguras que una bóveda bancaria. Si lo hace, tendrá que empezar de nuevo. + Recuperar la billetera existente a través de una copia de seguridad de Google Drive + Copia de seguridad de Google Drive + Cree una billetera segura y transfiera sus fondos para mayor protección. + Crear nueva billetera + Mejore su seguridad con la billetera de hardware superior Tangem. + Billetera de hardware + Mueva su billetera actual a Tangem. + Actualizar la billetera actual + Ir a copia de seguridad + Por favor, haga una copia de seguridad de su billetera antes de crear un código de acceso. + Finalice la copia de seguridad primero + Finalizar la copia de seguridad primero + Incompleto + Otros métodos + Guarde su frase de recuperación en un lugar seguro y manténgala en privado para proteger sus fondos. + Frase de recuperación + Para proteger su billetera con un código de acceso, complete el proceso de copia de seguridad. + Para actualizar a una billetera de hardware, complete el proceso de copia de seguridad. + Sus claves privadas están encriptadas de forma segura y almacenadas en su teléfono + Las claves privadas permanecen en su dispositivo + Cree o restaure su billetera con una frase de recuperación. + Copia de seguridad de la frase semilla + Crear una billetera móvil + Importar billetera existente + Esta frase de recuperación ya ha sido importada + Billetera móvil + Olvidar billetera + Esta billetera se eliminará permanentemente de su dispositivo. + ¿Está seguro que desea hacer esto? + Olvidar billetera + Ir a copia de seguridad + Ver copia de seguridad + Olvidar la billetera + Olvidar de todos modos + Esta billetera tiene una copia de seguridad. Asegúrese de poder recuperarla antes de olvidarla. + Si olvida esta billetera sin una copia de seguridad, perderá permanentemente el acceso a sus fondos. + ¿Estás seguro de que desea olvidar esta billetera? + Entiendo que si no he hecho una copia de seguridad de mi billetera antes de eliminarla, perderé el acceso a ella. + Entiendo que quitar mi billetera no la borra, solo la elimina de mi dispositivo. + Actualizar + No se requiere frase semilla. Su tarjeta o anillo Tangem se convierte en su copia de seguridad. + Copia de seguridad con Tangem + No se puede actualizar. Ya existe una billetera en este dispositivo. + Elija otro dispositivo. Este no se puede usar para la actualización. + Se produjo un error durante la operación. + Sus fondos permanecen seguros y totalmente accesibles durante el proceso + Acceso a los fondos + Los datos de su billetera se borrarán de la aplicación y se almacenarán en su billetera de hardware. + Seguridad general + Las claves privadas se transferirán de la aplicación a su billetera de hardware Tangem + Migración de claves + Escanear dispositivo + Iniciar actualización + Estás a punto de actualizarte a nuestra billetera de hardware. Mantendrá sus activos seguros en almacenamiento en frío. + Tangem Wallet + Actualice a nuestra billetera de hardware + Mantenga sus criptomonedas seguras con la billetera de hardware de primer nivel de Tangem. + Actualice su billetera a la seguridad del hardware Esta información fue generada con IA.\nPulse aquí si encuentra algún error. Para cambiar el código de acceso coloque la tarjeta o el anillo como se muestra arriba y no lo retire hasta el fin de la operación Toque para cambiar la contraseña @@ -1299,7 +1374,7 @@ Error al emitir la tarjeta Ha ocurrido un error técnico, por favor inténtalo de nuevo haciendo clic en el botón de abajo Ha ocurrido un error técnico, por favor contacta con el soporte - Usa tus criptomonedas para compras en el mundo real. \nEs una tarjeta de pago única en su tipo. + Obtén tu tarjeta virtual Tangem Visa gratuita Obtener Tangem Pay Ir a Soporte Suele tardar hasta 15 minutos @@ -1312,8 +1387,8 @@ KYC en curso Ver estado KYC en progreso para Tangem Pay - Usa tus criptomonedas para compras en el mundo real. \nEs una tarjeta de pago única en su tipo. - Tangem Visa Card + Obtén tu tarjeta virtual Tangem Visa gratuita + Usa USDC para pagos cotidianos Obtener tarjeta Con tarjeta digital que funciona con Apple Pay y Google Pay Gasta tus activos en cualquier lugar @@ -1323,15 +1398,15 @@ Privacidad inigualable Obtén tu tarjeta Tangem Pay gratuita en minutos Cuenta de pago - Sincronización de cuenta de pago necesaria + La cuenta de pago no está sincronizada Estamos solucionando un problema técnico. Por favor, inténtelo de nuevo más tarde. Servicio temporalmente no disponible No es posible mostrar los datos en este momento, pero los pagos con tarjeta siguen funcionando. Sincronización necesaria - Tangem Visa Card + Usa USDC para pagos cotidianos Tangem Pay temporalmente no disponible Tangem Pay - Usa tu tarjeta o anillo para restaurar el acceso a tu cuenta de pago + Haga clic en el botón de abajo para restaurar el acceso Tu código PIN Esta es mi billetera Saldos ocultos @@ -1412,6 +1487,7 @@ Active las notificaciones push y le avisaremos al instante cuando le lleguen fondos. No se pierda ninguna transacción Agregar una nueva billetera + Si olvida esta billetera sin una copia de seguridad, perderá permanentemente el acceso a sus fondos. ¿Estás seguro de que deseas olvidar esta billetera? Ha ocurrido un error, por favor escanee su tarjeta o anillo para iniciar sesión Esta billetera ya se ha guardado, puede agregar otro diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index dea8c07645..24e86ad9cd 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -72,7 +72,19 @@ Ajouter un wallet Sélectionnez un wallet pour vous connecter Heureux de te revoir! + Vous avez sauvegardé votre portefeuille avec succès. Ces mots ne peuvent pas être récupérés en cas de perte. Assurez-vous de les conserver en lieu sûr. + Sauvegarde terminée + Votre seed phrase est un ensemble fixe de %s mots aléatoires permettant d\'accéder à votre portefeuille et de le récupérer. + Ces mots ne peuvent être récupérés s\'ils sont perdus. Conservez-les précieusement. + Gardez-les en sécurité + Conservez ces %s mots dans un endroit sûr et ne les communiquez à personne. + Aucune récupération possible + Seed phrase + Ne communiquez jamais ces mots à qui que ce soit. Tangem ne vous les demandera jamais. Les %s mots ci-dessous constituent la seed phrase de votre portefeuille. Utilisez-les pour restaurer votre portefeuille si vous perdez votre appareil. + Notez ces %s mots dans l\'ordre numérique et conservez-les en lieu sûr et confidentiel. + Vous êtes entièrement responsable de la sécurité de votre portefeuille et de la sauvegarde de votre seed phrase. + Seed phrase Pour masquer ou afficher vos soldes, il suffit de retourner l\'écran de votre appareil vers le bas ou de le désactiver dans les paramètres Ne plus afficher Compris @@ -488,6 +500,13 @@ Pour continuer, accordez aux smart contracts de %1s l\'autorisation d\'utiliser votre %2s Donner l\'autorisation Illimité + Votre sauvegarde est créée à l\'aide de 2 ou 3 cartes Tangem. Conservez-les dans des endroits sûrs distincts afin de les protéger contre toute perte ou tout dommage. Aucune seed phrase n\'est nécessaire. + Sauvegarde avec plusieurs cartes + Ajouter le wallet Tangem + Votre clé privée est générée directement dans la carte Tangem et ne la quitte jamais. + Génération de clés + Toutes les opérations cryptographiques s\'effectuent à l\'intérieur de la puce sécurisée, certifiée contre le clonage et la falsification physique. + Sécurité au niveau matériel Ajouter un Portefeuille existant Créer un nouveau Portefeuille Commandez @@ -496,6 +515,73 @@ à %s Via %s Êtes-vous sûr de vouloir annuler la configuration du code d\'accès ? + Sauvegarder maintenant + Pour terminer la configuration, sauvegardez votre portefeuille et sécurisez l\'application à l\'aide d\'un code d\'accès. + Finaliser maintenant + Finaliser la configuration du portefeuille + Terminez la configuration en sécurisant l\'application à l\'aide d\'un code d\'accès. + Si vous quittez, vous devrez recommencer depuis le début. + Êtes-vous sûr de vouloir quitter le processus d\'installation ? + Gardez vos cryptomonnaies en sécurité et hors ligne. Aussi fin qu\'une carte de crédit, plus sûr qu\'un coffre-fort bancaire. + Si vous le faites, vous devrez recommencer depuis le début. + Récupérer un portefeuille existant via la sauvegarde Google Drive + Sauvegarde Google Drive + Créez un portefeuille sécurisé et transférez vos fonds pour bénéficier d\'une protection supplémentaire. + Créer un nouveau portefeuille + Renforcez votre sécurité grâce au Hardware wallet haut de gamme Tangem. + Hardware wallet + Transférez votre portefeuille actuel vers Tangem. + Améliorer le wallet actuel + Aller à la sauvegarde + Veuillez sauvegarder votre portefeuille avant de créer un code d\'accès. + Terminez d\'abord la sauvegarde. + Finalisez d\'abord la sauvegarde. + Incomplet + Autres méthodes + Conservez votre seed phrase dans un endroit sûr et gardez-la confidentielle afin de protéger vos fonds. + Seed phrase + Pour sécuriser votre wallet avec un code d\'accès, effectuez la procédure de sauvegarde. + Pour passer à un portefeuille matériel, terminez le processus de sauvegarde. + Vos clés privées sont cryptées et stockées en toute sécurité sur votre téléphone. + Les clés privées restent sur votre appareil + Créez ou restaurez votre portefeuille à l\'aide d\'une seed phrase. + Sauvegarde de la seed phrase + Créer un wallet mobile + Importer un portefeuille existant + Cette seed phrase a déjà été importée. + Wallet mobile + Oubliez votre portefeuille + Ce portefeuille sera définitivement supprimé de votre appareil. + Êtes-vous sûr de vouloir faire cela ? + Oubliez votre portefeuille + Aller à la sauvegarde + Afficher la sauvegarde + Oubliez votre portefeuille + Oubliez quand même + Ce portefeuille dispose d\'une sauvegarde. Assurez-vous de pouvoir la récupérer avant d\'oublier le portefeuille. + Si vous oubliez ce portefeuille sans sauvegarde, vous perdrez définitivement l\'accès à vos fonds. + Êtes-vous sûr de vouloir oublier ce portefeuille ? + Je comprends que si je n\'ai pas sauvegardé mon portefeuille avant de le supprimer, je perdrai l\'accès à celui-ci. + Je comprends que le fait de supprimer mon portefeuille ne l\'efface pas, mais le supprime uniquement de mon appareil. + Améliorer + Aucune seed phrase n\'est requise. Votre carte ou bague Tangem devient votre sauvegarde sécurisée. + Sauvegarde avec Tangem + Impossible de mettre à niveau. Un portefeuille existe déjà sur cet appareil. + Choisissez un autre appareil. Celui-ci ne peut pas être utilisé pour la mise à niveau. + Une erreur s\'est produite pendant l\'opération. + Vos fonds restent en sécurité et entièrement accessibles pendant toute la durée du processus. + Accès aux fonds + Les données de votre wallet seront effacées de l\'application et stockées sur votre hardware wallet. + Sécurité générale + Les clés privées seront transférées de l\'application vers votre hardware wallet Tangem. + Migration des clés + Scannez l\'appareil + Lancer la mise à niveau + Vous êtes sur le point de passer à notre hardware wallet. Il assurera la sécurité de vos actifs grâce au stockage hors ligne. + Tangem Wallet + Passez à notre Hardware Wallet + Protégez vos cryptomonnaies grâce au hardware wallet haut de gamme de Tangem. + Améliorez la sécurité de votre wallet grâce à un dispositif matériel Ces informations ont été générées avec l\'IA.\nAppuyez ici si vous trouvez des erreurs. Touchez, pour modifier le code d\'accès Touchez, pour modifier le mot de passe @@ -1280,7 +1366,7 @@ Échec de l\'émission de la carte Une erreur technique s\'est produite, veuillez réessayer en cliquant sur le bouton ci-dessous Une erreur technique s\'est produite, veuillez contacter le support - Utilisez vos cryptomonnaies pour vos dépenses quotidiennes. \nC\'est une carte de paiement unique en son genre. + Obtenez votre carte virtuelle Tangem Visa gratuite Obtenir Tangem Pay Contacter le support Cela prend généralement jusqu\'à 15 minutes @@ -1293,8 +1379,8 @@ KYC en cours Voir le statut KYC en cours pour Tangem Pay - Utilisez vos cryptomonnaies pour vos dépenses du quotidien. \nC\'est une carte de paiement unique en son genre. - Tangem Visa Card + Obtenez votre carte virtuelle Tangem Visa gratuite + Utilisez USDC pour les paiements quotidiens Obtenir la carte Avec carte numérique compatible Apple Pay et Google Pay Dépensez vos actifs partout @@ -1304,15 +1390,15 @@ Confidentialité inégalée Obtenez votre carte Tangem Pay gratuite en quelques minutes Compte de paiement - Synchronisation du compte de paiement nécessaire + Le compte de paiement n\'est pas synchronisé Nous réparons un problème technique. Veuillez réessayer plus tard. Service temporairement indisponible Les données ne peuvent pas être affichées pour le moment, mais les paiements par carte fonctionnent toujours. Synchronisation requise - Tangem Visa Card + Utilisez USDC pour les paiements quotidiens Tangem Pay est temporairement indisponible Tangem Pay - Utilisez votre carte ou votre bague pour restaurer l\'accès à votre compte de paiement + Cliquez sur le bouton ci-dessous pour restaurer l\'accès Votre code PIN C\'est mon portefeuille Soldes masqués @@ -1392,6 +1478,7 @@ Activez les notifications pour recevoir des alertes lorsque des fonds arrivent dans votre portefeuille. Ne manquez aucune transaction Ajouter un nouveau portefeuille + Si vous supprimez ce portefeuille sans sauvegarde, vous perdrez définitivement l\'accès à vos fonds. Êtes-vous sûr de vouloir supprimer ce portefeuille ? Une erreur s\'est produite, veuillez scanner votre carte ou bague pour vous connecter Ce portefeuille a déjà été enregistré, vous pouvez en ajouter un autre diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index b7536b13ca..2e418c1d4c 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -139,7 +139,7 @@ Impossibile emettere la carta Si è verificato un errore tecnico, riprova cliccando il pulsante qui sotto Si è verificato un errore tecnico, contatta il supporto - Utilizza le tue attività per fare acquisti nel mondo reale. \nÈ una carta di pagamento diversa da qualsiasi altra. + Ottieni la tua carta virtuale Tangem Visa gratuita Ottieni Tangem Pay Vai al supporto Di solito richiede fino a 15 minuti @@ -152,8 +152,8 @@ KYC in corso Visualizza stato KYC in corso per Tangem Pay - Utilizza le tue attività per fare acquisti nel mondo reale. \nÈ una carta di pagamento diversa da qualsiasi altra. - Tangem Visa Card + Ottieni la tua carta virtuale Tangem Visa gratuita + Usa USDC per i pagamenti quotidiani Ottieni carta Con carta digitale che funziona con Apple Pay e Google Pay Spendi i tuoi asset ovunque @@ -163,15 +163,15 @@ Privacy senza rivali Ottieni la tua carta Tangem Pay gratuita in pochi minuti Conto di pagamento - Sincronizzazione del conto di pagamento necessaria + Il conto di pagamento non è sincronizzato Stiamo risolvendo un problema tecnico. Riprova più tardi. Servizio temporaneamente non disponibile Al momento non è possibile visualizzare i dati, ma i pagamenti con carta continuano a funzionare. Sincronizzazione necessaria - Tangem Visa Card + Usa USDC per i pagamenti quotidiani Tangem Pay è temporaneamente non disponibile Tangem Pay - Usa la tua carta o il tuo anello per ripristinare l\'accesso al tuo conto di pagamento + Fare clic sul pulsante in basso per ripristinare l\'accesso Il tuo codice PIN Tangem Twin Imposta un codice di 4 cifre.\nVerrà utilizzato per i pagamenti. diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 5ba1fbe88a..f884797c15 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -23,7 +23,7 @@ 回復する 「 %1$s 」を回復しようとしています。 アカウントを回復する - すでにアクティブアカウントの上限(20件)に達しています。復元するには、1つをアーカイブしてください。 + 有効なアカウントは最大20件までです。1つのアカウントをアーカイブすると、このアカウントを復元できます。 アカウントを復元できません アーカイブ済み アカウントをアーカイブできませんでした。しばらくしてからもう一度お試しください。 @@ -43,12 +43,13 @@ アカウントを追加 保存 アカウント名 - アカウント名はすでに存在しています + この名前のアカウントはすでに存在します。別の名前を選択してください。 + このアカウント名はすでに使用されています アカウント 新しいアカウント アカウントを追加 アカウントを編集 - 少し時間をおいて再度お試しください。問題が続く場合はサポートへご連絡ください。こちらで解決をお手伝いします。 + しばらく時間をおいてから、もう一度お試しください。問題が解決しない場合は、サポートにお問い合わせください。こちらで解決をお手伝いします。 %1$s ( %2$s内) メインアカウント すでにアクティブアカウントの上限%1$s件を超えています。復元するには、1つをアーカイブしてください。 @@ -592,11 +593,13 @@ アクセスコードを作成する前にウォレットをバックアップしてください。 先にバックアップを完了してください まずバックアップを完了する + 未完了 その他の方法 資金を保護するため、リカバリーフレーズは安全な場所に保管し、他人に知られないようにしてください。 リカバリーフレーズ アクセスコードでウォレットを保護するには、バックアップの手続きを完了してください。 ハードウェアウォレットにアップグレードするには、バックアップの手続きを完了してください。 + 秘密鍵は安全に暗号化され、スマートフォン上に保存されています 秘密鍵はデバイス上に保持されます リカバリーフレーズを使ってウォレットを作成または復元してください。 シードフレーズのバックアップ @@ -617,6 +620,7 @@ このウォレットを削除してもよろしいですか? ウォレットを削除する前にバックアップを行っていない場合、ウォレットへのアクセスを失うことを理解しています。 ウォレットを削除しても中身自体が消えるわけではなく、このデバイスから表示が消えるだけであることを理解しています。 + アップグレード シードフレーズは不要です。Tangemカードまたはリングが安全なバックアップとなります。 Tangemでバックアップ アップグレードできません。このデバイスにはすでにウォレットが存在します。 @@ -789,12 +793,16 @@ モバイルウォレットを作成するには、%1$sにアップデートする必要があります モバイルウォレットを使用するには、%1$s以降が必要です すべてのニュース + いいね %d時間前 %d分前 + クイックまとめ + 関連ニュース + 情報源 最新情報を入手 お使いのデバイスではNFCが使用できません NFTについて @@ -941,7 +949,7 @@ 通知 バックアップデバイスが1つ追加されました カードまたはリングを用意してください - バックアップデバイス2つが追加されました + バックアップデバイスが2つ追加されました 始めるには、ウォレットに任意の金額を入金するだけです 始めるには、ウォレットに%1$s %2$s以上入金するだけです 暗号資産を購入する @@ -1468,7 +1476,7 @@ カードの発行に失敗しました 技術的なエラーが発生しました。下のボタンをクリックして、もう一度お試しください。 技術的なエラーが発生しました。サポートへお問い合わせください。 - 暗号資産を日常の支払いに使おう。\n\nこれまでにないタイプの決済カード。 + 無料のTangem Visaバーチャルカードを入手 Tangem Payを入手 サポートへ移動 通常は最大で15分ほどかかります @@ -1476,14 +1484,16 @@ カードを発行しています カードを準備しています。少し時間がかかる場合があります。 Tangem Pay + 中止を確定する + KYC手続きを中止しますか?いつでも再開できます。 プロフィールを確認できませんでした。ご不明な点があればサポートまでお問い合わせください。 申し訳ございませんが、本人確認を行うことができませんでした KYC進行中 ステータスを表示 Tangem PayのKYC手続き進行中 以下のボタンから、現在のKYCステータスを確認するか、KYCをキャンセルできます。 - 暗号資産を、リアルな支払いに。\n他とはまったく違う、新しいタイプの決済カード。 - Tangem Visaカード + 無料のTangem Visaバーチャルカードを入手 + 日常の支払いにUSDCを利用 カードをGET Apple PayとGoogle Payに対応したデジタルカード付き どこでも暗号資産を使える @@ -1493,15 +1503,15 @@ 他に類を見ないプライバシー 無料のTangem Payカードを数分でゲットしましょう 支払いアカウント - 支払いアカウントの同期が必要です + 支払アカウントが同期されていません 技術的な問題を修正しています。後でもう一度お試しください。 サービスは一時的に利用できません 現在、データを表示できませんが、カードでのお支払いは引き続きご利用いただけます。 同期が必要です - Tangem Visaカード + 日常の支払いにUSDCを利用 Tangem Payは現在一時的に利用できません。 Tangem Pay - カードまたはリングを使用して、支払いアカウントへのアクセスを復元してください。 + 下のボタンをクリックしてアクセスを復元してください PINコード これは私のウォレットです 残高非表示 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 537e6d8e15..6be32ab70f 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -54,7 +54,7 @@ Нажмите и удерживайте аккаунт, чтобы изменить порядок аккаунтов. Продолжить Отменить - Вы уверены, что хотите создание нового аккаунта? + Вы уверены, что хотите отменить создание нового аккаунта? Вы уверены, что хотите отменить изменения? Несохраненные изменения Некоторые пользовательские токены были перемещены из «%1$s» в «%2$s», поскольку их путь деривации относится к этой учётной записи. @@ -1457,6 +1457,7 @@ Не удалось разморозить карту, попробуйте еще раз Карта разморожена Вывести + Запрещено использовать на root-устройствах Пополнить Способы пополнения Номер @@ -1484,6 +1485,7 @@ Всё готово! Можно пользоваться картой Добавьте карту в Google Pay Добавить карту в Apple Pay + ПИН-код Скопируйте свой адрес или покажите QR Техническая ошибка. Попробуйте позже или обратитесь в поддержку. Пополнение недоступно @@ -1492,6 +1494,7 @@ Пополните карту любым активом через обмен Реквизиты Разморозить карту + Ваш ПИН Вывести Вывод сейчас недоступен Вы не можете начать обмен или новый вывод, пока не завершится текущий. @@ -1502,7 +1505,7 @@ Не удалось выпустить карту Техническая ошибка, попробуйте ещё раз, нажав кнопку ниже Техническая ошибка, свяжитесь с поддержкой - Используйте криптовалюту в реальной жизни. \nКарта, не похожая ни на одну другую. + Откройте бесплатную виртуальную карту Tangem Visa Получить Tangem Pay Написать в поддержку Обычно это занимает до 15 минут @@ -1515,8 +1518,9 @@ KYC в процессе Посмотреть статус KYC в процессе для Tangem Pay - Используйте криптовалюту в реальной жизни. \nКарта, не похожая ни на одну другую. - Tangem Visa Card + Вы можете посмотреть текущий статус KYC или отменить его + Откройте бесплатную виртуальную карту Tangem Visa + Оплачивайте ежедневные покупки в USDC Открыть карту Виртуальную карту можно добавить в Apple Pay и Google Pay Покупайте где угодно @@ -1526,15 +1530,15 @@ Абсолютная приватность Откройте виртуальную \nTangem Pay Card Платежный аккаунт - Требуется синхронизация платежного аккаунта + Платежный аккаунт не синхронизирован Мы устраняем техническую проблему. Пожалуйста, попробуйте позже. Сервис временно недоступен Не можем показать данные карты, но оплаты продолжают работать. - Требуется синхронизация - Tangem Visa Card + Не синхронизирован + Оплачивайте ежедневные покупки в USDC Tangem Pay временно недоступен Tangem Pay - Используйте вашу карту или кольцо для восстановления доступа к платежному аккаунту + Нажмите на кнопку ниже, чтобы восстановить доступ Ваш PIN-код Это мой кошелек Балансы скрыты 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 92eff0a832..968fdbb71e 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -49,6 +49,19 @@ Системна Тема Налаштування застосунку + Ви успішно створили резервну копію свого гаманця. + Ці слова неможливо відновити у разі втрати. Зберігайте їх надійно. + Бекап завершено + Ваша фраза відновлення — це набір випадкових слів %s для доступу та відновлення гаманця. + Ці слова неможливо відновити, якщо їх загубити. Зберігайте їх у безпеці. + Зберігайте в безпеці + Збережіть ці %s слова в безпечному місці та нікому не розповідайте про них. + Відновлення неможливе + Фраза відновлення + Наведені нижче слова %s - це фраза для відновлення вашого гаманця. Ніколи і нікому не повідомляйте ці слова. Tangem ніколи не запитає їх у вас. Використовуйте їх, щоб відновити свій гаманець, якщо ви втратите пристрій. + Запишіть ці %s слова в указаному порядку і зберігайте їх у безпеці та таємниці. + Ви несете повну відповідальність за безпеку свого гаманця і фрази відновлення. + Фраза відновлення Щоб приховати або показати свій баланс, просто переверніть екран пристрою вниз або вимкніть його в налаштуваннях Більше не показувати Зрозуміло @@ -413,11 +426,85 @@ Щоб продовжити, вам потрібно дозволити смарт-контракту %1s використовувати ваш %2s Надати дозвіл Необмежено + Резервна копія створюється на 2–3 картках Tangem. Зберігайте їх окремо для безпеки — seed-фраза не потрібна. + Бекап на декілька карток + Додати гаманець Tangem + Ваш приватний ключ генерується на картці Tangem і ніколи не покидає її. + Генерація ключа + Операції з криптографією відбуваються всередині захищеного чіпу, стійкого до клонування та фізичному взлому. + Безпека на апаратному рівні Створити новий гаманець Купити Сканувати в %s В мережі %s + Ви впевнені, що хочете скасувати процес створення коду доступу? + Створити бекап + Щоб завершити налаштування, створіть резервну копію свого гаманця та захистіть додаток за допомогою коду доступу. + Завершити зараз + Завершити налаштування гаманця + Завершіть налаштування, захистивши додаток кодом доступу. + Якщо ви вийдете, вам доведеться починати спочатку. + Ви впевнені, що хочете вийти з процесу активації? + Зберігає ваші криптовалюти в безпеці та в режимі офлайн. Тонкий, як кредитна картка, безпечніший за банківське сховище. + Якщо ви це зробите, доведеться почати спочатку. + Відновлення існуючого гаманця за допомогою резервної копії Google Диску + Google Диск бекап + Створіть новий захищений гаманець і переведіть свої кошти для додаткового захисту. + Створити новий гаманець + Підвищіть рівень своєї безпеки за допомогою просунутого апаратного гаманця Tangem. + Апаратний гаманець + Перенесіть свій поточний гаманець у Tangem. + Оновіть поточний гаманець + Перейти до бекапу + Будь ласка, створіть резервну копію свого гаманця, перш ніж створювати код доступу. + Спочатку завершіть резервне копіювання + Спочатку завершіть резервне копіювання + Не завершено + Інші методи + Збережіть фразу відновлення у безпечному місці і тримайте її у таємниці. + Фраза відновлення + Щоб захистити свій гаманець за допомогою коду доступу, завершіть процес резервного копіювання. + Щоб покращити гаманець до апаратного, спочатку створіть резервну копію. + Ваші приватні ключі надійно зашифровані та зберігаються на вашому телефоні + Ключі зберігаються у застосунку + Створіть або відновіть свій гаманець за допомогою вашої фрази відновлення. + Резервна копія + Створити мобільний гаманець + Імпортувати існуючий гаманець + Ця фраза відновлення вже була імпортована + Мобільний гаманець + Забути гаманець + Цей гаманець буде назавжди видалено з вашого пристрою + Ви впевнені, що хочете виконати цю операцію? + Забути гаманець + Перейти до резервної копії + Переглянути резервне копіювання + Забути гаманець + Все одно забути + Резервна копія цього гаманця існує. Перевірте її перед видаленням, щоб переконатися, що зможете відновити гаманець пізніше. + Якщо ви видалите цей гаманець без резервної копії, ви назавжди втратите доступ до своїх коштів. + Забути цей гаманець? + Я розумію, що якщо я не створив резервну копію гаманця перед його видаленням, я можу втратити досту до нього. + Я розумію, що видалення мого гаманця не видаляє його повністю, а просто видаляє його з мого пристрою. + Фраза відновлення більше не потрібна — ваша картка або кільце Tangem стає вашою безпечною резервною копією. + Резервне копіювання з Tangem + Цей пристрій не може бути використаний для оновлення, він вже містить інший гаманець. + Виберіть інший пристрій. Цей не можна використовувати для оновлення. + Під час операції виникла помилка. + Ваші кошти залишаються в безпеці та повністю доступними протягом усього процесу + Доступ до коштів + Данні вашого гаманця будуть видалені із застосунку і збережені на вашому пристрої Tangem. + Загальна безпека + Приватні ключі будуть переміщені з додатку у вашу Tangem картрку або кільце + Міграція ключів + Сканувати пристрій + Розпочати оновлення + Ви збираєтеся перейти на пристрій Tangem, де ваші активи будуть у безпеці в холодному сховищі. + Tangem Wallet + Оновіть до апаратного гаманця + Зберігайте свою криптовалюту в безпеці за допомогою першокласного апаратного гаманця Tangem. + Оновіть свій гаманець до апаратної версії. Ця інформація була створена за допомогою ШІ.\nНатисніть тут, якщо знайшли помилку. Щоб змінити код доступу, прикладіть картку або кільце, як показано вище, і не прибирайте її до закінчення операції Щоб змінити пароль, прикладіть картку, як показано вище, і не прибирайте її до закінчення операції @@ -1141,9 +1228,14 @@ Показати деталі Обміняйте будь-який актив у вашому портфелі на картку Розморозити картку - Tangem Visa Card + Отримайте безкоштовну віртуальну картку Tangem Visa + Отримайте безкоштовну віртуальну картку Tangem Visa + Використовуйте USDC для щоденних платежів + Платіжний рахунок не синхронізовано Ми усуваємо технічну проблему. Будь ласка, спробуйте пізніше. Сервіс тимчасово недоступний + Використовуйте USDC для щоденних платежів + Натисніть кнопку нижче, щоб відновити доступ Це мій гаманець Баланси приховано Баланси показано @@ -1220,6 +1312,7 @@ Нові функції та важливі новини Бажаєте використовувати Push-повідомлення? Додати новий гаманець + Якщо ви видалите цей гаманець без резервної копії, ви назавжди втратите доступ до своїх коштів. Ви впевнені, що хочете видалити цей гаманець? Сталася помилка, будь ласка, відскануйте свою картку або кільце, для входу Цей гаманець вже збережено, ви можете додати інший 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 6fa2c8b69c..a79d66c1d7 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -382,7 +382,7 @@ 无法发行卡片 出现技术错误,请点击下方按钮重试 出现技术错误,请联系客服 - 使用您的加密货币进行真实世界消费。\n这是一张与众不同的支付卡。 + 獲取您的免費 Tangem Visa 虛擬卡 获取Tangem Pay 前往客服中心 通常需要最多15分钟 @@ -395,8 +395,8 @@ KYC进行中 查看状态 Tangem Pay 的 KYC 正在進行中 - 使用您的加密货币进行真实世界消费。这是一张与众不同的支付卡。 - Tangem Visa Card + 獲取您的免費 Tangem Visa 虛擬卡 + 使用 USDC 進行日常支付 获取卡片 使用支援 Apple Pay 和 Google Pay 的數位卡 在任何地方花费您的资产 @@ -406,15 +406,15 @@ 無與倫比的隱私 在幾分鐘內獲得免費的 Tangem Pay 卡 付款帳戶 - 需要同步支付账户 + 付款帳戶未同步 我们正在修复技术问题。请稍后再试。 服務暫時無法使用 目前無法顯示資料,但卡片支付仍可正常使用。 需要同步 - Tangem Visa Card + 使用 USDC 進行日常支付 Tangem Pay暂时不可用 Tangem Pay - 使用您的卡片或戒指恢复对支付账户的访问 + 點擊下方按鈕以恢復存取權限 您的PIN码 隱藏 您即將在主屏幕上隱藏此代幣。您可以隨時通過管理代幣頁面將其添加回來。 diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 76cee235d8..1bce65560b 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -23,12 +23,12 @@ Recover You’re about to recover “%1$s”. Recover account - You have already exceeded the limit of 20 active accounts. Archive one to recover. + You’ve reached the limit of 20 active accounts. Archive one account to recover this one. Can\'t recover account Archived We couldn’t archive account. Please try again later. - This account participates in the referral program. - This account cannot be archived. + This account is participating in the referral program. + This account can’t be archived We couldn’t create account. Please try again later. Account created Archive account @@ -43,12 +43,13 @@ Add account Save Account name - Account name already exists + An account with this name already exists. Please choose a different name. + Account name already in use Account New account Add account Edit account - Please try again later. If it keeps happening, get in touch with support and we’ll help you resolve it. + Please try again later. If the problem persists, contact support and we’ll help you resolve it. %1$s in %2$s Main account You have already exceeded the limit of %1$s active accounts. Archive one to recover @@ -127,15 +128,15 @@ Mobile Wallet You successfully backed up your wallet. - These words are unrecoverable if lost. Keep them somewhere safe. + These words cannot be recovered if lost. Store them securely. Backup completed - Your secret recovery phrase is a fixed set of %s random words for accessing and recovering your wallet. + Your secret recovery phrase is a set of %s random words for accessing and recovering your wallet. These words cannot be recovered if lost. Keep them safe. Keep it safe Save these %s words in a secure location and never share them with anyone. No recovery possible Recovery phrase - Never share these words with anyone. Tangem will never ask you for them. The %s words below are your wallet\'s recovery phrase. Use them to restore your wallet if you lose your device. + The %s words below are your wallet\'s recovery phrase. Never share these words with anyone. Tangem will never ask you for them. Use them to restore your wallet if you lose your device. Write down these %s words in numerical order and keep them safe and private You are fully responsible for securing your wallet and safely backing up your recovery phrase. Recovery phrase @@ -546,6 +547,7 @@ Please tell us what card or ring do you have Hi support team, Please tell us more about your issue. Every small detail can help. + Backup issue Previously activated wallet My suggestions Can\'t scan a card/ring @@ -564,8 +566,8 @@ To continue, grant %1s smart contracts permission to use your %2s Give Permission Unlimited - Your backup is created using 2 or 3 Tangem cards. Keep them in separate safe places to protect against loss or damage — no seed phrase needed. - Backup with Multiple Cards + A backup is created using 2–3 Tangem cards. Store them separately in secure locations to protect against loss or damage. No seed phrase needed. + Backup With Multiple Cards Add Tangem Wallet Your private key is generated directly inside the Tangem card and never leaves it. Key Generation @@ -585,7 +587,7 @@ Finalize wallet setup Complete setup by securing the app with an access code. If you exit, you\'ll need to start over. - Are you sure you want to quit the setup process? + Are you sure you want to quit activation? Keeps your crypto safe and offline. Slim as a credit card, safer than a bank vault. If you do, you\'ll need to start over. Recover existing wallet via Google Drive backup @@ -598,7 +600,7 @@ Upgrade current wallet Go to backup Please back up your wallet before creating an access code. - Finish backup first + Complete the backup first Finalize backup first Incomplete Other methods @@ -627,14 +629,15 @@ Are you sure you want to forget this wallet? I understand that if I haven\'t backed up my wallet before removing it, I will lose access to it. I understand that removing my wallet does not delete it, only removes it from my device. + Upgrade Seed phrase not required. Your Tangem card or ring becomes your secure backup. - Backup with Tangem + Backup With Tangem Can\'t upgrade. A wallet already exists on this device. - Pick another device. This one can’t be used for the upgrade. + Pick another device. This one can\'t be used for the upgrade. An error occurred during the operation. Your funds remain safe and fully accessible during the process Access to funds - Your wallet data will be erased from the app and stored on your hardware wallet + Your wallet information will be erased from the app and stored on your hardware wallet General security Private keys will be moved from the app to your Tangem hardware wallet Key migration @@ -802,6 +805,7 @@ You must update to %1$s before creating a mobile wallet Mobile Wallet requires %1$s or later All news + Like %dh ago %dh ago @@ -810,6 +814,9 @@ %d minute ago %d minutes ago + Quick recap + Related News + Sources Stay in the loop NFC is not available on your device About NFT @@ -893,8 +900,8 @@ Please repeat the operation. The card will be reset to factory settings. Activation error Add tokens - You\'ve added one backup card or ring. When backup process is finished you can\'t add more backup devices. If you have one more card or ring, add it to the backup. Would you like to continue the backup process? - The backup process is partly complete. You can\'t exit it now. + You\'ve added one backup card or ring. Once backup is finalized, you can\'t add more devices. If you have one more card or ring, add it now. Do you want to continue? + The backup is partially complete and can\'t be quit now. A passphrase is an optional security feature that adds a word or phrase to your recovery phrase, creating a new set of wallet addresses for extra protection. Add a card or ring Scan card @@ -944,7 +951,7 @@ Legacy To check whether you’ve written down your seed phrase correctly, please enter the 2nd, 7th and 11th words So, let’s check - To start the backup process add up to two backup cards or rings. + To start the backup process, add up to two backup cards or rings. You can add one more card or ring or finalize the backup process Prepare the backup card with number %s Scan the primary card or ring to start the backup process. @@ -1083,8 +1090,8 @@ I understand that after performing this action, I will no longer have access to the current wallet I realize that I can\'t use this card to recover my access code on the other cards of the current wallet I understand that I will completely lose access to my Tangem Pay Card and all funds on it without the possibility of recovery - Factory Reset will completely delete the wallet from the selected card or ring. You will not be able to restore the current wallet or use the card or ring to recover the access code. - Factory Reset will completely delete the wallet from the selected card or ring and remove it from the app. You will not be able to restore the current wallet. + A factory reset completely erases the wallet from the selected card or ring. You will not be able to restore the current wallet or use this card or ring to recover the access code. + A factory reset completely erases the wallet from the selected card or ring and removes it from the app. You will not be able to restore the current wallet. All Tangem devices have been reset. Something went wrong with the activation process. Please reset the cards one by one. Card verification failed @@ -1369,7 +1376,7 @@ Your stakes Store your crypto assets secure while keeping private keys contained in your card or ring Revolutionary Hardware Wallet - Up to 3 physical cards or rings to one wallet + Add up to 3 cards or rings to one wallet Ultra Secure Backup A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously — all in one card or ring Thousands of Currencies @@ -1492,7 +1499,7 @@ Failed to issue card A technical error has occurred, please try again by clicking the button below. A technical error has occurred, please contact support. - Use your crypto for real world spending. \nIt\'s a payment card unlike any other. + Get your free Tangem Visa virtual card Get Tangem Pay Go to Support It usually takes up to 15 minutes @@ -1508,8 +1515,8 @@ View Status KYC in progress for Tangem Pay Use the buttons below to view your current KYC status or cancel it. - Use your crypto for real world spending. \nIt’s a payment card unlike any other. - Tangem Visa Card + Get your free Tangem Visa virtual card + Use USDC for everyday payments Get card With digital card that works with Apple Pay and Google Pay Spend your assets anywhere @@ -1519,15 +1526,16 @@ Unrivaled privacy Get your free Tangem Pay Card in minutes Payment account - Payment account sync needed + Payment account is not synced We’re fixing a technical issue. Please try again later. Service temporarily unavailable Unable to display details. However, card payments are still working. - Sync needed - Tangem Visa Card + Not synced + Restore access + Use USDC for everyday payments Tangem Pay is temporarily unreachable Tangem Pay - Use your card or ring to restore access to your payment account + Click the button below to restore access Your PIN code This is my wallet Balances hidden @@ -1777,7 +1785,7 @@ Use %s or scan a card/ring to unlock access to your wallet The permission-granting process is currently underway and will be completed shortly Approval in Progress - It seems that the card or ring activation was not completed correctly. This could be due to an issue with your device\'s NFC module or incorrect tapping of the card or ring to your device. Please contact our Support team for assistance. + Activation was not completed successfully. This may be due to an NFC issue or incorrect tapping. Please contact our Support team for assistance. Activation error On December 3, 2024, the BEP-2 network was disabled by decision of the network developers and is no longer supported BNB Beacon Chain shut down @@ -1788,6 +1796,8 @@ Ok, Got it! Really cool! Refresh + According to Clore’s official documentation, all tokens received before December 21 will be migrated to Clore (ERC20); tokens received after will not. Transfer solution coming — stay tuned. + Clore Network Migration You are currently in the Demo mode Demo mode active The card you scanned is a developer card. Do not use it to create your wallet. @@ -1836,7 +1846,7 @@ The network is currently unreachable. Please try again later. Network is unreachable Top up your wallet - Your wallet hasn\'t been backed up. Carry out this procedure to protect your assets now. + Your wallet isn\'t backed up yet. Back it up now to protect your assets. Missing backup This card has been previously used for transactions. If received from an untrusted source, consider withdrawing all funds. If it\'s your card, no action is required. Card has already signed transactions @@ -1976,10 +1986,10 @@ Use a Tangem hardware wallet Learn more & buy Discard - You have an interrupted backup. Do you want to resume? + Your backup was interrupted. Do you want to resume? Yes, resume Discard - If you discard the backup now, then you will have to reset the devices to factory settings to start over again + If you discard the backup now, you will have to reset the devices to factory settings to start over again Resume backup This is an irreversible action Log in with %s 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 73a2e96b23..10590d9f19 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 @@ -151,13 +151,14 @@ sealed class WalletNotification(val config: NotificationConfig) { ) data class TangemPayRefreshNeeded( - @DrawableRes val tangemIcon: Int?, - val onRefreshClick: () -> Unit, + @DrawableRes private val tangemIcon: Int?, + private val onRefreshClick: () -> Unit, + private val buttonText: TextReference, ) : Warning( title = resourceReference(id = R.string.tangempay_payment_account_sync_needed), subtitle = resourceReference(id = R.string.tangempay_use_tangem_device_to_restore_payment_account), buttonsState = ButtonsState.PrimaryButtonConfig( - text = resourceReference(id = R.string.home_button_scan), + text = buttonText, iconResId = tangemIcon, onClick = onRefreshClick, ), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshNeededStateTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshNeededStateTransformer.kt index b3f487ec56..1a2c03db4d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshNeededStateTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshNeededStateTransformer.kt @@ -1,5 +1,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState @@ -8,6 +10,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState internal class TangemPayRefreshNeededStateTransformer( userWalletId: UserWalletId, + private val userWallet: UserWallet, private val onRefreshClick: () -> Unit, ) : WalletStateTransformer(userWalletId = userWalletId) { @@ -15,6 +18,10 @@ internal class TangemPayRefreshNeededStateTransformer( val tangemPayState = TangemPayState.RefreshNeeded( notification = TangemPayRefreshNeeded( tangemIcon = R.drawable.ic_tangem_24, + buttonText = when (userWallet) { + is UserWallet.Cold -> resourceReference(id = R.string.home_button_scan) + is UserWallet.Hot -> resourceReference(id = R.string.tangempay_sync_needed_restore_access) + }, onRefreshClick = onRefreshClick, ), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt index 8b890929a2..6558e26c93 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt @@ -46,6 +46,7 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( stateController.update( transformer = TangemPayRefreshNeededStateTransformer( userWalletId = userWalletId, + userWallet = userWallet, onRefreshClick = { clickIntents.onRefreshPayToken(userWalletId) }, ), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayRefreshBlock.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayRefreshBlock.kt index fc3d9c852b..5b35cfb683 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayRefreshBlock.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayRefreshBlock.kt @@ -68,6 +68,7 @@ private fun TangemPayRefreshBlockPreview() { state = TangemPayState.RefreshNeeded( TangemPayRefreshNeeded( tangemIcon = R.drawable.ic_tangem_24, + buttonText = resourceReference(id = R.string.tangempay_sync_needed_restore_access), onRefreshClick = {}, ), ), From 319f62f0082033b831ff7bce8869c09391361327 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 25 Dec 2025 17:45:47 +0500 Subject: [PATCH 20/36] Updated on 2026-08-14 --- .../main/assets/configs/feature_toggles_config.json | 4 ++++ data/visa/build.gradle.kts | 3 +++ .../data/pay/DefaultTangemPayEligibilityManager.kt | 12 +++++------- .../com/tangem/data/pay/di/TangemPayDataModule.kt | 3 +++ domain/visa/build.gradle.kts | 3 +++ .../TangemPayMainScreenCustomerInfoUseCase.kt | 13 ++++++++++--- .../tangem/features/details/model/DetailsModel.kt | 2 +- .../tangem/features/details/utils/ItemsBuilder.kt | 11 +++++++---- .../features/tangempay/TangemPayFeatureToggles.kt | 1 + .../tangempay/DefaultTangemPayFeatureToggles.kt | 2 ++ .../wallet/model/intents/TangemPayClickIntents.kt | 11 ++++++++++- 11 files changed, 49 insertions(+), 16 deletions(-) diff --git a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json index dce534df8d..1cb7bb7d24 100644 --- a/core/config-toggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/config-toggles/src/main/assets/configs/feature_toggles_config.json @@ -39,6 +39,10 @@ "name": "TANGEM_PAY_ENABLED", "version": "5.31.0" }, + { + "name": "TANGEM_PAY_ENTRYPOINT_ENABLED", + "version": "undefined" + }, { "name": "NEW_TOKEN_RECEIVE_ENABLED", "version": "5.28.0" diff --git a/data/visa/build.gradle.kts b/data/visa/build.gradle.kts index f893a530d6..e1e1568878 100644 --- a/data/visa/build.gradle.kts +++ b/data/visa/build.gradle.kts @@ -39,6 +39,9 @@ dependencies { /** Feature API - remove after removing [HotWalletFeatureToggles] */ implementation(projects.features.hotWallet.api) + /** Feature API - remove after removing [TangemPayFeatureToggles] */ + implementation(projects.features.tangempay.details.api) + /** Project - Utils */ implementation(projects.core.utils) implementation(projects.domain.legacy) diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt index 4ab4d074f2..7ccc87275c 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/DefaultTangemPayEligibilityManager.kt @@ -9,15 +9,10 @@ import com.tangem.domain.pay.TangemPayEligibilityManager import com.tangem.domain.pay.repository.OnboardingRepository import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.features.hotwallet.HotWalletFeatureToggles +import com.tangem.features.tangempay.TangemPayFeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.* import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import javax.inject.Inject @@ -27,6 +22,7 @@ internal class DefaultTangemPayEligibilityManager @Inject constructor( private val userWalletsListManager: UserWalletsListManager, private val userWalletsListRepository: UserWalletsListRepository, private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val tangemPayFeatureToggles: TangemPayFeatureToggles, private val onboardingRepository: OnboardingRepository, ) : TangemPayEligibilityManager { @@ -130,6 +126,8 @@ internal class DefaultTangemPayEligibilityManager @Inject constructor( } private suspend fun checkTangemPayEligibility(): Boolean { + if (!tangemPayFeatureToggles.isEntryPointsEnabled) return true + return onboardingRepository.getCustomerEligibility() || onboardingRepository.checkCustomerEligibility() } diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt index 719542728a..93f2455ffb 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/di/TangemPayDataModule.kt @@ -13,6 +13,7 @@ import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase import com.tangem.domain.tangempay.GetTangemPayCurrencyStatusUseCase import com.tangem.domain.tangempay.TangemPayWithdrawUseCase import com.tangem.domain.tangempay.repository.TangemPayTxHistoryRepository +import com.tangem.features.tangempay.TangemPayFeatureToggles import com.tangem.security.DeviceSecurityInfoProvider import dagger.Binds import dagger.Module @@ -77,12 +78,14 @@ internal interface TangemPayDataModule { customerOrderRepository: CustomerOrderRepository, tangemPayOnboardingRepository: OnboardingRepository, eligibilityManager: TangemPayEligibilityManager, + tangemPayFeatureToggles: TangemPayFeatureToggles, deviceSecurity: DeviceSecurityInfoProvider, ): TangemPayMainScreenCustomerInfoUseCase { return TangemPayMainScreenCustomerInfoUseCase( onboardingRepository = repository, customerOrderRepository = customerOrderRepository, eligibilityManager = eligibilityManager, + tangemPayFeatureToggles = tangemPayFeatureToggles, deviceSecurity = deviceSecurity, ) } diff --git a/domain/visa/build.gradle.kts b/domain/visa/build.gradle.kts index 3c13ebe644..3dfad027a7 100644 --- a/domain/visa/build.gradle.kts +++ b/domain/visa/build.gradle.kts @@ -25,6 +25,9 @@ dependencies { implementation(projects.domain.tokens.models) implementation(projects.domain.wallets.models) + /** Feature API - remove after removing [TangemPayFeatureToggles] */ + implementation(projects.features.tangempay.details.api) + /** Security */ implementation(deps.spongecastle.core) diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt index 16ebd064e6..78d8486b32 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt @@ -9,6 +9,7 @@ import com.tangem.domain.pay.model.* import com.tangem.domain.pay.repository.CustomerOrderRepository import com.tangem.domain.pay.repository.OnboardingRepository import com.tangem.domain.visa.error.VisaApiError +import com.tangem.features.tangempay.TangemPayFeatureToggles import com.tangem.security.DeviceSecurityInfoProvider import com.tangem.security.isSecurityExposed import kotlinx.coroutines.flow.* @@ -24,6 +25,7 @@ class TangemPayMainScreenCustomerInfoUseCase( private val onboardingRepository: OnboardingRepository, private val customerOrderRepository: CustomerOrderRepository, private val eligibilityManager: TangemPayEligibilityManager, + private val tangemPayFeatureToggles: TangemPayFeatureToggles, private val deviceSecurity: DeviceSecurityInfoProvider, ) { @@ -46,7 +48,7 @@ class TangemPayMainScreenCustomerInfoUseCase( .fold( ifLeft = { error -> Timber.tag(TAG).e("Failed checkCustomerWallet for $userWalletId: ${error.javaClass.simpleName}") - if (error is VisaApiError.NotPaeraCustomer) { + if (error is VisaApiError.NotPaeraCustomer && tangemPayFeatureToggles.isEntryPointsEnabled) { showOnboardingBannerIfEligible(userWalletId) } else { updateState(userWalletId, TangemPayCustomerInfoError.UnknownError.left()) @@ -64,8 +66,13 @@ class TangemPayMainScreenCustomerInfoUseCase( .map(MainCustomerInfoContentState::Content) updateState(userWalletId, result) } else { - // if there's no tangem pay, check eligibility and show onboarding banner - showOnboardingBannerIfEligible(userWalletId) + if (tangemPayFeatureToggles.isEntryPointsEnabled) { + // if there's no tangem pay, check eligibility and show onboarding banner + showOnboardingBannerIfEligible(userWalletId) + } else { + // ignore if there's no TangemPay + updateState(userWalletId, TangemPayCustomerInfoError.UnknownError.left()) + } } }, ) diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt index 992afae4ac..1c4c53f372 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt @@ -248,7 +248,7 @@ internal class DetailsModel @Inject constructor( } private fun addTangemPayItemIfEligible() { - if (!tangemPayFeatureToggles.isTangemPayEnabled) return + if (!tangemPayFeatureToggles.isEntryPointsEnabled) return modelScope.launch { val isEligible = tangemPayEligibilityManager .getEligibleWallets(shouldExcludePaeraCustomers = true) diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt index c8627bf1ea..7ee2b6eccd 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt @@ -54,10 +54,13 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) { } fun removeTangemPayItem(items: ImmutableList): ImmutableList { - val tangemPayItem = items.find { it.id == TANGEM_PAY_ITEM_ID } ?: return items - return items.toMutableList() - .also { list -> list.remove(tangemPayItem) } - .toImmutableList() + return items.map { block -> + if (block is DetailsItemUM.Basic && block.items.any { it.id == TANGEM_PAY_ITEM_ID }) { + block.copy(items = block.items.filter { it.id != TANGEM_PAY_ITEM_ID }.toImmutableList()) + } else { + block + } + }.toImmutableList() } private fun buildWalletConnectBlock(isWalletConnectAvailable: Boolean, userWalletId: UserWalletId): DetailsItemUM? { diff --git a/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/TangemPayFeatureToggles.kt b/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/TangemPayFeatureToggles.kt index 393e589bce..0345c3cb32 100644 --- a/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/TangemPayFeatureToggles.kt +++ b/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/TangemPayFeatureToggles.kt @@ -2,4 +2,5 @@ package com.tangem.features.tangempay interface TangemPayFeatureToggles { val isTangemPayEnabled: Boolean + val isEntryPointsEnabled: Boolean } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/DefaultTangemPayFeatureToggles.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/DefaultTangemPayFeatureToggles.kt index a51c11a3bc..9b909186a0 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/DefaultTangemPayFeatureToggles.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/DefaultTangemPayFeatureToggles.kt @@ -7,4 +7,6 @@ internal class DefaultTangemPayFeatureToggles( ) : TangemPayFeatureToggles { override val isTangemPayEnabled get() = featureTogglesManager.isFeatureEnabled("TANGEM_PAY_ENABLED") + override val isEntryPointsEnabled: Boolean + get() = featureTogglesManager.isFeatureEnabled("TANGEM_PAY_ENTRYPOINT_ENABLED") } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt index 7fc89a52ab..1a485dbf1d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt @@ -14,6 +14,7 @@ import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.pay.TangemPayDetailsConfig +import com.tangem.domain.pay.TangemPayEligibilityManager import com.tangem.domain.pay.repository.OnboardingRepository import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase @@ -55,6 +56,7 @@ internal class TangemPayClickIntentsImplementor @Inject constructor( private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase, private val tangemPayOnboardingRepository: OnboardingRepository, + private val tangemPayEligibilityManager: TangemPayEligibilityManager, private val uiMessageSender: UiMessageSender, ) : BaseWalletClickIntents(), TangemPayIntents { @@ -176,7 +178,14 @@ internal class TangemPayClickIntentsImplementor @Inject constructor( } override fun onOnboardingBannerClick(userWalletId: UserWalletId) { - router.openTangemPayOnboarding(mode = AppRoute.TangemPayOnboarding.Mode.FromBannerOnMain(userWalletId)) + modelScope.launch { + val isEligible = tangemPayEligibilityManager.getTangemPayAvailability() + if (isEligible) { + router.openTangemPayOnboarding(mode = AppRoute.TangemPayOnboarding.Mode.FromBannerOnMain(userWalletId)) + } else { + tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) + } + } } override fun onOnboardingBannerCloseClick(userWalletId: UserWalletId) { From 00032d7d11e0e092a63e3653951c9a7edd26452b Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 25 Dec 2025 18:22:53 +0500 Subject: [PATCH 21/36] Updated on 2026-08-14 --- .../components/notifications/Notification.kt | 2 ++ .../notifications/NotificationConfig.kt | 1 + .../model/intents/TangemPayClickIntents.kt | 22 +++++++++++++---- .../wallet/state/model/WalletNotification.kt | 2 ++ .../TangemPayRefreshNeededStateTransformer.kt | 1 + ...TangemPayRefreshShowProgressTransformer.kt | 24 +++++++++++++++++++ .../subscribers/TangemPayMainSubscriber.kt | 2 +- .../components/visa/TangemPayRefreshBlock.kt | 1 + 8 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshShowProgressTransformer.kt 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 20bb9fce3b..d1b06a5538 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 @@ -296,6 +296,7 @@ private fun SinglePrimaryButton(config: NotificationButtonsState.PrimaryButtonCo modifier = Modifier.fillMaxWidth(), size = TangemButtonSize.WideAction, enabled = isEnabled, + showProgress = config.shouldShowProgress, ) } else { PrimaryButton( @@ -304,6 +305,7 @@ private fun SinglePrimaryButton(config: NotificationButtonsState.PrimaryButtonCo modifier = Modifier.fillMaxWidth(), size = TangemButtonSize.WideAction, enabled = isEnabled, + showProgress = config.shouldShowProgress, ) } } diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationConfig.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationConfig.kt index 57338f98b4..9da575b6c2 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationConfig.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationConfig.kt @@ -38,6 +38,7 @@ data class NotificationConfig( val additionalText: TextReference? = null, @DrawableRes val iconResId: Int? = null, val onClick: () -> Unit, + val shouldShowProgress: Boolean = false, ) : ButtonsState() data class SecondaryButtonConfig( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt index 1a485dbf1d..c9c81a2859 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt @@ -12,6 +12,7 @@ import com.tangem.core.ui.message.bottomSheetMessage import com.tangem.domain.feedback.GetWalletMetaInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.pay.TangemPayDetailsConfig import com.tangem.domain.pay.TangemPayEligibilityManager @@ -20,6 +21,8 @@ import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase import com.tangem.domain.pay.usecase.TangemPayMainScreenCustomerInfoUseCase import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.TangemPayHideOnboardingStateTransformer +import com.tangem.feature.wallet.presentation.wallet.state.transformers.TangemPayRefreshNeededStateTransformer +import com.tangem.feature.wallet.presentation.wallet.state.transformers.TangemPayRefreshShowProgressTransformer import com.tangem.features.tangempay.TangemPayFeatureToggles import kotlinx.coroutines.launch import javax.inject.Inject @@ -28,7 +31,7 @@ internal interface TangemPayIntents { suspend fun onPullToRefresh() - fun onRefreshPayToken(userWalletId: UserWalletId) + fun onRefreshPayToken(userWallet: UserWallet) fun openDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig) @@ -70,10 +73,21 @@ internal class TangemPayClickIntentsImplementor @Inject constructor( tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) } - override fun onRefreshPayToken(userWalletId: UserWalletId) { + override fun onRefreshPayToken(userWallet: UserWallet) { + stateHolder.update(TangemPayRefreshShowProgressTransformer(userWallet.walletId)) + modelScope.launch { - produceInitialDataTangemPay.invoke(userWalletId) - tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) + produceInitialDataTangemPay.invoke(userWallet.walletId) + .onRight { tangemPayMainScreenCustomerInfoUseCase.fetch(userWallet.walletId) } + .onLeft { + stateHolder.update( + transformer = TangemPayRefreshNeededStateTransformer( + userWallet = userWallet, + userWalletId = userWallet.walletId, + onRefreshClick = { onRefreshPayToken(userWallet) }, + ) + ) + } } } 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 10590d9f19..e2dc6648fc 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 @@ -154,6 +154,7 @@ sealed class WalletNotification(val config: NotificationConfig) { @DrawableRes private val tangemIcon: Int?, private val onRefreshClick: () -> Unit, private val buttonText: TextReference, + private val shouldShowProgress: Boolean, ) : Warning( title = resourceReference(id = R.string.tangempay_payment_account_sync_needed), subtitle = resourceReference(id = R.string.tangempay_use_tangem_device_to_restore_payment_account), @@ -161,6 +162,7 @@ sealed class WalletNotification(val config: NotificationConfig) { text = buttonText, iconResId = tangemIcon, onClick = onRefreshClick, + shouldShowProgress = shouldShowProgress, ), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshNeededStateTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshNeededStateTransformer.kt index 1a2c03db4d..98a3ee0caa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshNeededStateTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshNeededStateTransformer.kt @@ -23,6 +23,7 @@ internal class TangemPayRefreshNeededStateTransformer( is UserWallet.Hot -> resourceReference(id = R.string.tangempay_sync_needed_restore_access) }, onRefreshClick = onRefreshClick, + shouldShowProgress = false, ), ) return if (prevState is WalletState.MultiCurrency.Content) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshShowProgressTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshShowProgressTransformer.kt new file mode 100644 index 0000000000..cd5885b406 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/TangemPayRefreshShowProgressTransformer.kt @@ -0,0 +1,24 @@ +package com.tangem.feature.wallet.presentation.wallet.state.transformers + +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.feature.wallet.presentation.wallet.state.model.TangemPayState +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState + +internal class TangemPayRefreshShowProgressTransformer( + userWalletId: UserWalletId, +) : WalletStateTransformer(userWalletId) { + + override fun transform(prevState: WalletState): WalletState { + val multiContentState = prevState as? WalletState.MultiCurrency.Content ?: return prevState + val refreshNeededState = multiContentState.tangemPayState as? TangemPayState.RefreshNeeded ?: return prevState + val refreshNotification = + refreshNeededState.notification as? WalletNotification.Warning.TangemPayRefreshNeeded ?: return prevState + + return multiContentState.copy( + tangemPayState = refreshNeededState.copy( + notification = refreshNotification.copy(shouldShowProgress = true), + ), + ) + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt index 6558e26c93..e6f5955bb8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/TangemPayMainSubscriber.kt @@ -47,7 +47,7 @@ internal class TangemPayMainSubscriber @AssistedInject constructor( transformer = TangemPayRefreshNeededStateTransformer( userWalletId = userWalletId, userWallet = userWallet, - onRefreshClick = { clickIntents.onRefreshPayToken(userWalletId) }, + onRefreshClick = { clickIntents.onRefreshPayToken(userWallet) }, ), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayRefreshBlock.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayRefreshBlock.kt index 5b35cfb683..b3c06f3a28 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayRefreshBlock.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/visa/TangemPayRefreshBlock.kt @@ -70,6 +70,7 @@ private fun TangemPayRefreshBlockPreview() { tangemIcon = R.drawable.ic_tangem_24, buttonText = resourceReference(id = R.string.tangempay_sync_needed_restore_access), onRefreshClick = {}, + shouldShowProgress = true, ), ), modifier = Modifier, From 258e950178ef9d677e46b41c74b0009b5290ed65 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 26 Dec 2025 15:29:35 +0500 Subject: [PATCH 22/36] Updated on 2026-08-14 --- .../tangem/datasource/api/pay/TangemPayApi.kt | 6 ++ .../api/pay/models/request/GetPinResponse.kt | 14 +++ .../models/response/CardDetailsResponse.kt | 1 - core/res/src/main/res/values-de/strings.xml | 6 +- core/res/src/main/res/values-es/strings.xml | 6 +- core/res/src/main/res/values-fr/strings.xml | 6 +- core/res/src/main/res/values-it/strings.xml | 1 + core/res/src/main/res/values-ja/strings.xml | 1 + core/res/src/main/res/values-ru/strings.xml | 6 +- .../src/main/res/values-uk-rUA/strings.xml | 5 +- core/res/src/main/res/values/strings.xml | 3 +- .../repository/DefaultOnboardingRepository.kt | 24 +++-- .../DefaultTangemPayCardDetailsRepository.kt | 87 ++++++++++--------- .../repository/TangemPayRequestPerformer.kt | 33 ------- .../TangemPayMainScreenCustomerInfoUseCase.kt | 4 - .../model/TangemPayChangePinModel.kt | 11 ++- .../TangemPayViewPinErrorStateTransformer.kt | 8 +- .../model/intents/TangemPayClickIntents.kt | 2 +- 18 files changed, 125 insertions(+), 99 deletions(-) create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/pay/models/request/GetPinResponse.kt diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt index 1054ffef58..773dbb7b72 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt @@ -62,6 +62,12 @@ interface TangemPayApi { @Body body: CardDetailsRequest, ): ApiResponse + @GET("v1/customer/card/pin") + suspend fun getPin( + @Header("Authorization") authHeader: String, + @Header("X-Session-Id") sessionId: String, + ): ApiResponse + @PUT("v1/customer/card/pin") suspend fun setPin( @Header("Authorization") authHeader: String, diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/request/GetPinResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/request/GetPinResponse.kt new file mode 100644 index 0000000000..ad9da0eda5 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/request/GetPinResponse.kt @@ -0,0 +1,14 @@ +package com.tangem.datasource.api.pay.models.request + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class GetPinResponse(@Json(name = "result") val result: Result?) { + + @JsonClass(generateAdapter = true) + data class Result( + @Json(name = "secret") val secret: String, + @Json(name = "iv") val iv: String, + ) +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/response/CardDetailsResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/response/CardDetailsResponse.kt index 17b226bacc..599d94d6b1 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/response/CardDetailsResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/pay/models/response/CardDetailsResponse.kt @@ -17,7 +17,6 @@ data class CardDetailsResponse( @Json(name = "card_number_end") val cardNumberEnd: String, @Json(name = "pan") val pan: Secret, @Json(name = "cvv") val cvv: Secret, - @Json(name = "pin") val pin: Secret?, ) @JsonClass(generateAdapter = true) diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index cefd04ae41..dcdf6d4a87 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -449,7 +449,7 @@ Überprüfe deine Internetverbindung oder wechseln zu einem anderen Netzwerk Nutzungsbedingungen Standardadresse - Legacy adresse + Legacy %s adresse Empfangen von Vermögenswerten %s Adresse Das Senden von Vermögenswerten in anderen Netzwerken führt zu dauerhaftem Verlust. @@ -542,6 +542,7 @@ Bitte sag uns, welche Karte oder Ring du hast Hallo Support-Team, Bitte erzähle uns mehr über dein Problem. Jedes kleine Detail kann helfen. + Problem mit der Sicherung Zuvor aktivierte Wallet Meine Vorschläge Kann eine Karte oder Ring nicht scannen @@ -1502,6 +1503,7 @@ Erhalten Sie Ihre kostenlose Tangem Pay Card in wenigen Minuten Zahlungskonto Zahlungskonto ist nicht synchronisiert + Ungültige PIN: Sequenzen oder Wiederholungen vermeiden Wir beheben ein technisches Problem. Bitte versuchen Sie es später erneut. Service vorübergehend nicht verfügbar Daten können derzeit nicht angezeigt werden, Kartenzahlungen funktionieren jedoch weiterhin. @@ -1770,6 +1772,8 @@ OK, habe ich verstanden! Echt toll! Aktualisieren + Laut der offiziellen Dokumentation von Clore werden alle Münzen, die vor dem 21. Dezember erhalten wurden, in Clore (ERC-20 Token) migriert; Münzen, die nach diesem Datum erhalten wurden, nicht. Eine Lösung für den Transfer ist in Arbeit — bleibt dran. + Migration des Clore-Netzwerks Du befindest sich derzeit im Demo-Modus Demo-Modus aktiv Die Karte, die du gescannt hast, ist eine Entwicklerkarte. Verwenden diese nicht zur Erstellung Ihrer Wallet. diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index c1cf00a410..1c463c9d8e 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -401,7 +401,7 @@ Compruebe su conexión a internet o cambia a una red diferente Condiciones de uso Dirección por defecto - Dirección Legacy + Dirección %s Legacy Recibir activos %s dirección Enviar activos a otras redes resultará en una pérdida permanente. @@ -491,6 +491,7 @@ Por favor, díganos qué tarjeta o anillo tiene Hola equipo de soporte, Por favor, cuéntenos más sobre tu problema. Cada pequeño detalle puede ayudar. + Problema con la copia de seguridad Billetera previamente activada Mis recomendaciones No se puede escanear una tarjeta/anillo @@ -1399,6 +1400,7 @@ Obtén tu tarjeta Tangem Pay gratuita en minutos Cuenta de pago La cuenta de pago no está sincronizada + PIN no válido: evitar secuencias o repeticiones Estamos solucionando un problema técnico. Por favor, inténtelo de nuevo más tarde. Servicio temporalmente no disponible No es posible mostrar los datos en este momento, pero los pagos con tarjeta siguen funcionando. @@ -1582,6 +1584,8 @@ Entendido ¡Realmente genial! Actualizar + Según la documentación oficial de Clore, todas las monedas recibidas antes del 21 de diciembre serán migradas a Clore (token ERC-20); las monedas recibidas después de esa fecha no lo serán. Se está desarrollando una solución de transferencia — mantente atento. + Migración de la red Clore Actualmente estás en el modo Demo Modo demo activo La tarjeta que ha escaneado es una tarjeta de desarrollador. No la use para crear su billetera. diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 24e86ad9cd..16ebbde2fe 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -394,7 +394,7 @@ Vérifiez votre connexion Internet ou passez à un réseau différent Conditions d\'utilisation Adresse par défaut - Legacy adresse + Legacy %s adresse Recevoir des actifs %s adresse L’envoi d’actifs sur d’autres réseaux entraînera une perte définitive. @@ -482,6 +482,7 @@ Veuillez nous dire quelle carte vous avez Chère équipe de support, Veuillez nous en dire plus sur votre problème. Chaque petit détail peut nous aider. + Problème de sauvegarde Portefeuille précédemment activé Mes suggestions Impossible de scanner une carte @@ -1391,6 +1392,7 @@ Obtenez votre carte Tangem Pay gratuite en quelques minutes Compte de paiement Le compte de paiement n\'est pas synchronisé + Code PIN invalide : évitez les séquences ou les répétitions Nous réparons un problème technique. Veuillez réessayer plus tard. Service temporairement indisponible Les données ne peuvent pas être affichées pour le moment, mais les paiements par carte fonctionnent toujours. @@ -1592,6 +1594,8 @@ Ok, compris! Vraiment cool ! Rafraîchir + Selon la documentation officielle de Clore, toutes les pièces reçues avant le 21 décembre seront migrées vers Clore (token ERC-20) ; les pièces reçues après cette date ne le seront pas. Une solution de transfert arrive — restez à l\'écoute. + Migration du réseau Clore Vous êtes actuellement en mode démo Mode démo actif La carte que vous avez scannée est une carte de développeur. Ne l\'utilisez pas pour créer votre portefeuille. diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index 2e418c1d4c..9128efeb7f 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -164,6 +164,7 @@ Ottieni la tua carta Tangem Pay gratuita in pochi minuti Conto di pagamento Il conto di pagamento non è sincronizzato + PIN non valido: evitare sequenze o ripetizioni Stiamo risolvendo un problema tecnico. Riprova più tardi. Servizio temporaneamente non disponibile Al momento non è possibile visualizzare i dati, ma i pagamenti con carta continuano a funzionare. diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index f884797c15..666fe8e6bb 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -1504,6 +1504,7 @@ 無料のTangem Payカードを数分でゲットしましょう 支払いアカウント 支払アカウントが同期されていません + 無効な暗証番号:連続や繰り返しを避けてください 技術的な問題を修正しています。後でもう一度お試しください。 サービスは一時的に利用できません 現在、データを表示できませんが、カードでのお支払いは引き続きご利用いただけます。 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 6be32ab70f..ee6d3b99d7 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -460,7 +460,7 @@ Проверьте подключение с интернетом или переключитесь на другую сеть Условия использования Основной адрес - Legacy адрес + Legacy %s адрес Получить активы %s адрес Отправка средств в другой сети может повлечь потерю средств. @@ -551,6 +551,7 @@ Скажите, пожалуйста, какая у вас карта или кольцо? Привет, команда поддержки, Пожалуйста, расскажите нам больше о вашей проблеме. Каждая маленькая деталь может помочь. + Проблема резервного копирования Ранее активированный кошелек Мои предложения Не могу отсканировать карту/кольцо @@ -1531,6 +1532,7 @@ Откройте виртуальную \nTangem Pay Card Платежный аккаунт Платежный аккаунт не синхронизирован + Слабый ПИН: не используйте повторы или последовательности. Мы устраняем техническую проблему. Пожалуйста, попробуйте позже. Сервис временно недоступен Не можем показать данные карты, но оплаты продолжают работать. @@ -1739,6 +1741,8 @@ Понятно! Очень круто! Обновить + Согласно официальной документации Clore, все монеты, полученные до 21 декабря, будут мигрированы в токен Clore (ERC-20); монеты, полученные после этой даты, — нет. Решение для перевода находится в разработке — следите за обновлениями. + Миграция сети Clore Вы находитесь в режиме демо Демо режим включен Отсканированная вами карта является картой разработчика. Не используйте ее для создания своего кошелька. 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 968fdbb71e..6df04c2899 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -323,7 +323,7 @@ Перевірте підключення до інтернету або змініть мережу Умови використання Основна адреса - Legacy адреса + Legacy %s адреса Отримати активи %s адреса Надсилання активів в інші мережі призведе до безповоротної втрати. @@ -408,6 +408,7 @@ Розкажіть, будь ласка, яку картку або кільце ви маєте? Привіт, команда підтримки, Будь ласка, розкажіть нам більше про вашу проблему. Кожна дрібниця може допомогти. + Проблема з резервним копіюванням Раніше активований гаманець Мої пропозиції Не вдається відсканувати картку/кільце @@ -1383,6 +1384,8 @@ Зрозуміло! Дуже круто! Оновити + Згідно з офіційною документацією Clore, усі монети, отримані до 21 грудня, будуть мігровані в токен Clore (ERC-20); монети, отримані після цієї дати, — ні. Рішення для переказу перебуває в розробці — стежте за оновленнями. + Міграція мережі Clore Ви перебуваєте в демонстраційному режимі Демонстраційний режим активовано Відсканована вами картка є карткою розробника. Не використовуйте її для створення гаманця. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 1bce65560b..1a5e95cd53 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -1527,6 +1527,7 @@ Get your free Tangem Pay Card in minutes Payment account Payment account is not synced + Invalid PIN: avoid sequences or repeats We’re fixing a technical issue. Please try again later. Service temporarily unavailable Unable to display details. However, card payments are still working. @@ -1796,7 +1797,7 @@ Ok, Got it! Really cool! Refresh - According to Clore’s official documentation, all tokens received before December 21 will be migrated to Clore (ERC20); tokens received after will not. Transfer solution coming — stay tuned. + According to Clore’s official documentation, all coins received before December 21 will be migrated to Clore (ERC-20 token); coins received after that date will not. A transfer solution is coming — stay tuned. Clore Network Migration You are currently in the Demo mode Demo mode active diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt index fe06e7b5e3..9b12c88cb6 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt @@ -1,6 +1,7 @@ package com.tangem.data.pay.repository import arrow.core.Either +import arrow.core.raise.catch import com.tangem.datasource.api.pay.TangemPayApi import com.tangem.datasource.api.pay.models.request.DeeplinkValidityRequest import com.tangem.datasource.api.pay.models.request.OrderRequest @@ -23,6 +24,7 @@ import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import timber.log.Timber import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject @@ -110,15 +112,21 @@ internal class DefaultOnboardingRepository @Inject constructor( override suspend fun createOrder(userWalletId: UserWalletId) = withContext(dispatcherProvider.io) { launch { - requestHelper.runWithErrorLogs(TAG) { - val walletAddress = requestHelper.getCustomerWalletAddress(userWalletId) - val result = requestHelper.request(userWalletId) { authHeader -> - tangemPayApi.createOrder(authHeader, body = OrderRequest(walletAddress)) - }.result ?: error("Create order result is null") + catch( + block = { + val walletAddress = requestHelper.getCustomerWalletAddress(userWalletId) + val response = requestHelper.performRequest(userWalletId) { authHeader -> + tangemPayApi.createOrder(authHeader, body = OrderRequest(walletAddress)) + }.getOrNull() - val customerWalletAddress = requireNotNull(result.data.customerWalletAddress) - tangemPayStorage.storeOrderId(customerWalletAddress, result.id) - } + val result = requireNotNull(response?.result) + val customerWalletAddress = requireNotNull(result.data.customerWalletAddress) + tangemPayStorage.storeOrderId(customerWalletAddress, result.id) + }, + catch = { + Timber.tag(TAG).e("createOrder: $it") + }, + ) } } diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayCardDetailsRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayCardDetailsRepository.kt index a05f92ee7a..3252c49c4e 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayCardDetailsRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultTangemPayCardDetailsRepository.kt @@ -120,27 +120,18 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor( block = { val publicKeyBase64 = getPublicKeyBase64() val (secretKeyBytes, sessionId) = rainCryptoUtil.generateSecretKeyAndSessionId(publicKeyBase64) - val result = requireNotNull( - requestHelper.performRequest(userWalletId = userWalletId) { authHeader -> - tangemPayApi.revealCardDetails( - authHeader = authHeader, - body = CardDetailsRequest(sessionId = sessionId), - ) - }.getOrNull()?.result, - ) + val response = requestHelper.performRequest(userWalletId = userWalletId) { authHeader -> + tangemPayApi.getPin(authHeader = authHeader, sessionId = sessionId) + }.getOrNull() + val result = requireNotNull(response?.result) + + val pin = rainCryptoUtil.decryptPin( + base64Secret = result.secret, + base64Iv = result.iv, + secretKeyBytes = secretKeyBytes, + ).takeIf { !it.isNullOrEmpty() } - val encryptedPin = result.pin - val pin = if (encryptedPin != null) { - rainCryptoUtil.decryptPin( - base64Secret = encryptedPin.secret, - base64Iv = encryptedPin.iv, - secretKeyBytes = secretKeyBytes, - ).takeIf { !it.isNullOrEmpty() } - } else { - null - } secretKeyBytes.fill(0) - pin.right() }, catch = ::catchException, @@ -148,14 +139,14 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor( } override suspend fun setPin(userWalletId: UserWalletId, pin: String): Either { - return requestHelper.runWithErrorLogs(TAG) { - val publicKeyBase64 = getPublicKeyBase64() - val (secretKeyBytes, sessionId) = rainCryptoUtil.generateSecretKeyAndSessionId(publicKeyBase64) - val encryptedData = rainCryptoUtil.encryptPin(pin = pin, secretKeyBytes = secretKeyBytes) - secretKeyBytes.fill(0) + return catch( + block = { + val publicKeyBase64 = getPublicKeyBase64() + val (secretKeyBytes, sessionId) = rainCryptoUtil.generateSecretKeyAndSessionId(publicKeyBase64) + val encryptedData = rainCryptoUtil.encryptPin(pin = pin, secretKeyBytes = secretKeyBytes) + secretKeyBytes.fill(0) - val status = requireNotNull( - requestHelper.request(userWalletId) { authHeader -> + val response = requestHelper.performRequest(userWalletId) { authHeader -> tangemPayApi.setPin( authHeader = authHeader, body = SetPinRequest( @@ -164,27 +155,41 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor( iv = encryptedData.ivBase64, ), ) - }.result?.result, - ) - when (status) { - SetPinResult.SUCCESS.name -> SetPinResult.SUCCESS - SetPinResult.PIN_TOO_WEAK.name -> SetPinResult.PIN_TOO_WEAK - SetPinResult.DECRYPTION_ERROR.name -> SetPinResult.DECRYPTION_ERROR - else -> SetPinResult.UNKNOWN_ERROR - } - } + }.getOrNull() + val status = requireNotNull(response?.result?.result) + val result = when (status) { + SetPinResult.SUCCESS.name -> SetPinResult.SUCCESS + SetPinResult.PIN_TOO_WEAK.name -> SetPinResult.PIN_TOO_WEAK + SetPinResult.DECRYPTION_ERROR.name -> SetPinResult.DECRYPTION_ERROR + else -> SetPinResult.UNKNOWN_ERROR + } + result.right() + }, + catch = ::catchException, + ) } override suspend fun isAddToWalletDone(userWalletId: UserWalletId): Either { - return requestHelper.runWithErrorLogs(TAG) { - storage.getAddToWalletDone(requestHelper.getCustomerWalletAddress(userWalletId)) - } + return catch( + block = { + storage.getAddToWalletDone( + customerWalletAddress = requestHelper.getCustomerWalletAddress(userWalletId), + ).right() + }, + catch = ::catchException, + ) } override suspend fun setAddToWalletAsDone(userWalletId: UserWalletId): Either { - return requestHelper.runWithErrorLogs(TAG) { - storage.storeAddToWalletDone(requestHelper.getCustomerWalletAddress(userWalletId), isDone = true) - } + return catch( + block = { + storage.storeAddToWalletDone( + customerWalletAddress = requestHelper.getCustomerWalletAddress(userWalletId), + isDone = true, + ).right() + }, + catch = ::catchException, + ) } override suspend fun freezeCard( diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt index 95b6decdf8..a788639680 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt @@ -18,7 +18,6 @@ import com.tangem.domain.visa.error.VisaApiError import com.tangem.domain.visa.model.TangemPayAuthTokens import com.tangem.domain.visa.model.getAuthHeader import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import kotlinx.coroutines.CancellationException import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext @@ -41,38 +40,6 @@ internal class TangemPayRequestPerformer @Inject constructor( private val customerWalletAddresses = ConcurrentHashMap() private val tokensMutex = Mutex() - @Deprecated("Do not use this method") - suspend fun runWithErrorLogs(tag: String, requestBlock: suspend () -> T): Either { - return try { - val result = requestBlock() - Either.Right(result) - } catch (exception: Exception) { - when (exception) { - is CancellationException -> { - throw exception - } - else -> { - Timber.tag(tag).e(exception) - Either.Left(errorConverter.convert(exception)) - } - } - } - } - - @Deprecated("Use perform request instead", replaceWith = ReplaceWith("performRequest")) - suspend fun request( - userWalletId: UserWalletId, - requestBlock: suspend (header: String) -> - ApiResponse, - ): T = withContext(dispatchers.io) { - performRequest(userWalletId, requestBlock = requestBlock) - // to keep behaviour as previous - .fold( - ifRight = { it }, - ifLeft = { error -> error("Cannot perform request: $error") }, - ) - } - suspend fun performWithStaticToken( requestBlock: suspend (header: String) -> ApiResponse, ): Either = withContext(dispatchers.io) { diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt index 78d8486b32..6cf5c28a6f 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/usecase/TangemPayMainScreenCustomerInfoUseCase.kt @@ -17,10 +17,6 @@ import timber.log.Timber private const val TAG = "TangemPayMainScreenCustomerInfoUseCase" -/** - * Returns tangem pay customer info for the main screen banner - * Works only if the user already authorised at least once (won't emit anything otherwise) - */ class TangemPayMainScreenCustomerInfoUseCase( private val onboardingRepository: OnboardingRepository, private val customerOrderRepository: CustomerOrderRepository, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayChangePinModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayChangePinModel.kt index 405a45ad13..6d9f9d47f2 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayChangePinModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayChangePinModel.kt @@ -5,9 +5,13 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router +import com.tangem.core.decompose.ui.UiMessageSender +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.message.ToastMessage import com.tangem.domain.pay.model.SetPinResult import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent +import com.tangem.features.tangempay.details.impl.R import com.tangem.features.tangempay.entity.TangemPayChangePinUM import com.tangem.features.tangempay.model.transformers.PinCodeChangeTransformer import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute @@ -23,6 +27,7 @@ import javax.inject.Inject internal class TangemPayChangePinModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, + private val uiMessageSender: UiMessageSender, private val router: Router, private val cardDetailsRepository: TangemPayCardDetailsRepository, ) : Model() { @@ -49,8 +54,12 @@ internal class TangemPayChangePinModel @Inject constructor( } uiState.update { it.copy(submitButtonLoading = false) } when (result) { + SetPinResult.PIN_TOO_WEAK -> { + uiMessageSender.send( + message = ToastMessage(resourceReference(R.string.tangempay_pin_validation_error_message)), + ) + } SetPinResult.SUCCESS -> router.push(TangemPayDetailsInnerRoute.ChangePINSuccess) - SetPinResult.PIN_TOO_WEAK, SetPinResult.DECRYPTION_ERROR, SetPinResult.UNKNOWN_ERROR, null, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayViewPinErrorStateTransformer.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayViewPinErrorStateTransformer.kt index eacc9656fd..abf2326617 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayViewPinErrorStateTransformer.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayViewPinErrorStateTransformer.kt @@ -4,11 +4,11 @@ import com.tangem.core.ui.R import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUMV2 import com.tangem.core.ui.components.bottomsheets.message.icon import com.tangem.core.ui.components.bottomsheets.message.infoBlock +import com.tangem.core.ui.components.bottomsheets.message.messageBottomSheetUM import com.tangem.core.ui.components.bottomsheets.message.onClick import com.tangem.core.ui.components.bottomsheets.message.secondaryButton import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.message.bottomSheetMessage import com.tangem.features.tangempay.entity.TangemPayViewPinUM import com.tangem.utils.transformer.Transformer @@ -16,7 +16,7 @@ internal class TangemPayViewPinErrorStateTransformer : Transformer Date: Fri, 26 Dec 2025 15:54:17 +0500 Subject: [PATCH 23/36] Updated on 2026-08-14 --- .../tangem/data/pay/repository/DefaultOnboardingRepository.kt | 4 ++-- .../com/tangem/domain/pay/repository/OnboardingRepository.kt | 2 +- .../child/wallet/model/intents/TangemPayClickIntents.kt | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt index 9b12c88cb6..d877f0f1f3 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt @@ -224,13 +224,13 @@ internal class DefaultOnboardingRepository @Inject constructor( tangemPayStorage.storeHideOnboardingBanner(userWalletId, hide = true) } - override suspend fun disableTangemPay(userWalletId: UserWalletId): Either { + override suspend fun disableTangemPay(userWalletId: UserWalletId): Either { return requestHelper.performRequest(userWalletId) { authHeader -> tangemPayApi.setTangemPayEnabledStatus( authHeader = authHeader, body = SetTangemPayEnabledRequest(isTangemPayEnabled = false), ) - }.onRight { + }.map { val address = requestHelper.getCustomerWalletAddress(userWalletId) tangemPayStorage.clearAll(userWalletId = userWalletId, customerWalletAddress = address) setHideMainOnboardingBanner(userWalletId) diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt index 1deca6b43a..568cf85006 100644 --- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt +++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/OnboardingRepository.kt @@ -34,5 +34,5 @@ interface OnboardingRepository { suspend fun setHideMainOnboardingBanner(userWalletId: UserWalletId) - suspend fun disableTangemPay(userWalletId: UserWalletId): Either + suspend fun disableTangemPay(userWalletId: UserWalletId): Either } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt index 4664d50c5f..e7a6f9325e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/TangemPayClickIntents.kt @@ -8,6 +8,7 @@ import com.tangem.core.ui.components.bottomsheets.message.* import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.DialogMessage import com.tangem.core.ui.message.EventMessageAction +import com.tangem.core.ui.message.ToastMessage import com.tangem.core.ui.message.bottomSheetMessage import com.tangem.domain.feedback.GetWalletMetaInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase @@ -213,6 +214,7 @@ internal class TangemPayClickIntentsImplementor @Inject constructor( modelScope.launch { tangemPayOnboardingRepository.disableTangemPay(userWalletId) .onRight { tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) } + .onLeft { uiMessageSender.send(ToastMessage(resourceReference(R.string.common_something_went_wrong))) } } } } \ No newline at end of file From 65f026b993af6a8fc5dc8fa4cc0c4e41f134f5ed Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 26 Dec 2025 15:35:20 +0300 Subject: [PATCH 24/36] Updated on 2026-08-14 --- .../tokenlist/impl/ui/components/MarketsListLazyColumn.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListLazyColumn.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListLazyColumn.kt index b74e9a3d29..bbdcbf2697 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListLazyColumn.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/tokenlist/impl/ui/components/MarketsListLazyColumn.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag +import com.tangem.core.ui.components.SpacerH12 import com.tangem.core.ui.components.UnableToLoadData import com.tangem.core.ui.components.buttons.SecondarySmallButton import com.tangem.core.ui.components.buttons.SmallButtonConfig @@ -174,6 +175,7 @@ private fun ShowTokensUnder100kItem(onShowTokensClick: () -> Unit, modifier: Mod onClick = onShowTokensClick, ), ) + SpacerH12() } } From ce37036dd56689adc6e608477664c5a31f6ec116 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 26 Dec 2025 16:59:20 +0300 Subject: [PATCH 25/36] Updated on 2026-08-14 --- .../CreateHardwareWalletModel.kt | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt index 0373179468..39a2c8b242 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt @@ -21,6 +21,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.common.wallets.error.SaveWalletError import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.wallets.analytics.WalletSettingsAnalyticEvents import com.tangem.domain.wallets.builder.ColdUserWalletBuilder @@ -133,19 +134,16 @@ internal class CreateHardwareWalletModel @Inject constructor( } saveWalletUseCase(userWallet = userWallet).fold( - ifLeft = { + ifLeft = { saveWalletError -> delay(HIDE_PROGRESS_DELAY) setLoading(false) - when (it) { - is SaveWalletError.DataError -> Timber.e(it.toString(), "Unable to save user wallet") - is SaveWalletError.WalletAlreadySaved -> { - userWalletsListRepository.unlock( - userWalletId = userWallet.walletId, - unlockMethod = UserWalletsListRepository.UnlockMethod.Scan(scanResponse), - ).onRight { - router.replaceAll(AppRoute.Wallet) - } - } + when (saveWalletError) { + is SaveWalletError.DataError -> Timber.e(saveWalletError.toString(), "Unable to save user wallet") + is SaveWalletError.WalletAlreadySaved -> handleAlreadySavedCard( + saveWalletError.messageId, + walletId = userWallet.walletId, + scanResponse = scanResponse, + ) } }, ifRight = { @@ -175,4 +173,18 @@ internal class CreateHardwareWalletModel @Inject constructor( ), ) } + + private suspend fun handleAlreadySavedCard(messageId: Int, walletId: UserWalletId, scanResponse: ScanResponse) { + uiMessageSender.send( + message = DialogMessage( + message = resourceReference(messageId), + ), + ) + userWalletsListRepository.unlock( + userWalletId = walletId, + unlockMethod = UserWalletsListRepository.UnlockMethod.Scan(scanResponse), + ).onRight { + router.replaceAll(AppRoute.Wallet) + } + } } \ No newline at end of file From c0f4f15b5da25cce6a48d7c98f32420541f3fdeb Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 29 Dec 2025 11:13:12 +0300 Subject: [PATCH 26/36] Updated on 2026-08-14 --- .../wallet/analytics/WalletScreenAnalyticsEvent.kt | 6 ++++++ .../wallet/analytics/utils/TokenListAnalyticsSender.kt | 1 + 2 files changed, 7 insertions(+) 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 c54ebcef16..033a18e216 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 @@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.analytics import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.AppsFlyerOnlyEvent import com.tangem.core.analytics.models.OneTimeAnalyticsEvent import com.tangem.domain.models.wallet.UserWalletId @@ -22,6 +23,11 @@ sealed class WalletScreenAnalyticsEvent { override val oneTimeEventId: String = id + userWalletId.stringValue } + class AppsFlyerWalletFunded(userWalletId: UserWalletId) : Basic(event = "wallet_funded"), + AppsFlyerOnlyEvent, OneTimeAnalyticsEvent { + override val oneTimeEventId: String = id + userWalletId.stringValue + } + class CardWasScanned(source: AnalyticsParam.ScreensSources) : Basic( event = "Card Was Scanned", params = mapOf( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt index b8d4f81c17..215aa3ca8d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt @@ -206,6 +206,7 @@ internal class TokenListAnalyticsSender @Inject constructor( } analyticsEventHandler.send(Basic.WalletToppedUp(userWallet.walletId, walletType)) + analyticsEventHandler.send(Basic.AppsFlyerWalletFunded(userWallet.walletId)) } } From 7a08266a066c7eef123ff22c56b569751744d451 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 29 Dec 2025 10:27:08 +0300 Subject: [PATCH 27/36] Updated on 2026-08-14 --- .../wallet/child/wallet/model/WalletModel.kt | 4 ++-- .../model/WalletsUpdateActionResolver.kt | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 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 8370377f18..ba456f80f5 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 @@ -679,7 +679,7 @@ internal class WalletModel @Inject constructor( } private suspend fun unlockWallet(action: WalletsUpdateActionResolver.Action.UnlockWallet) { - withContext(dispatchers.io) { delay(timeMillis = 700) } + delay(timeMillis = 700) stateHolder.update( transformer = UnlockWalletTransformer( @@ -696,7 +696,7 @@ internal class WalletModel @Inject constructor( ) action.unlockedWallets.onEach { userWallet -> - modelScope.launch { fetchWalletContent(userWallet = userWallet) } + fetchWalletContent(userWallet = userWallet) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt index d498e480a0..4946ef99e9 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt @@ -64,6 +64,15 @@ internal class WalletsUpdateActionResolver @Inject constructor( selectedWallet: UserWallet, ): Action { return when { + isAnyWalletUnlocked(state, wallets) -> { + Action.UnlockWallet( + selectedWallet = selectedWallet, + unlockedWallets = wallets.filterNot(UserWallet::isLocked), + ) + } + isAnyWalletNameChanged(state, wallets) -> { + getRenameWalletsAction(state, wallets) + } isAnyHotWalletUpgraded(state, wallets) -> { getHotWalletsUpgradedAction(state, wallets, selectedWallet) } @@ -79,15 +88,6 @@ internal class WalletsUpdateActionResolver @Inject constructor( selectedWallet = selectedWallet, ) } - isAnyWalletNameChanged(state, wallets) -> { - getRenameWalletsAction(state, wallets) - } - isAnyWalletUnlocked(state, wallets) -> { - Action.UnlockWallet( - selectedWallet = selectedWallet, - unlockedWallets = wallets.filterNot(UserWallet::isLocked), - ) - } isSelectedWalletCardsCountChanged(state, selectedWallet) -> { Action.UpdateWalletCardCount(selectedWallet) } From e2ebacba7693f1c9343aa64adcf76419ec81adbb Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 29 Dec 2025 13:33:21 +0300 Subject: [PATCH 28/36] 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 d167ffb2eb..3a00dc0651 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.31.1-1326" +tangemBlockchainSdk = "releases-5.31.1-1334" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.31-569" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From 3b556e261d26b57f03d6ab398d1e8af9a00c0393 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 29 Dec 2025 14:59:20 +0400 Subject: [PATCH 29/36] Updated on 2026-08-14 --- .../YieldSupplyGetRewardsBalanceUseCase.kt | 8 ++- ...YieldSupplyGetRewardsBalanceUseCaseTest.kt | 68 +++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCase.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCase.kt index f0b5c39b43..9dcaed0bd4 100644 --- a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCase.kt +++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCase.kt @@ -102,14 +102,16 @@ class YieldSupplyGetRewardsBalanceUseCase( }.flowOn(dispatcherProvider.default) private fun calculateMinVisibleDecimals(perTickDeltaAbs: BigDecimal, maxDecimals: Int): Int { - if (perTickDeltaAbs <= BigDecimal.ZERO) return MIN_DECIMALS + val effectiveMin = MIN_DECIMALS.coerceAtMost(maxDecimals) + + if (perTickDeltaAbs <= BigDecimal.ZERO) return effectiveMin val perTickAsDouble = perTickDeltaAbs.toDouble() - if (perTickAsDouble.isNaN() || perTickAsDouble.isInfinite()) return MIN_DECIMALS + if (perTickAsDouble.isNaN() || perTickAsDouble.isInfinite()) return effectiveMin val safe = if (perTickAsDouble <= 0.0) EPSILON else perTickAsDouble val raw = ceil(-ln(safe) / LN_10) - return raw.toInt().coerceIn(MIN_DECIMALS, maxDecimals) + return raw.toInt().coerceIn(effectiveMin, maxDecimals) } private fun perTickDelta(amount: BigDecimal, apyFraction: BigDecimal): BigDecimal { diff --git a/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt b/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt index d8b29bfd94..8f80623ff1 100644 --- a/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt +++ b/domain/yield-supply/src/test/java/com/tangem/domain/yield/supply/usecase/YieldSupplyGetRewardsBalanceUseCaseTest.kt @@ -459,4 +459,72 @@ class YieldSupplyGetRewardsBalanceUseCaseTest { YieldSupplyGetRewardsBalanceUseCase.FIAT_MAX_DECIMALS, ) } + + @Test + fun `GIVEN token with decimals less than MIN_DECIMALS WHEN invoke THEN does not crash`() = runTest { + val network = createNetwork() + val tokenId = CryptoCurrency.ID( + prefix = CryptoCurrency.ID.Prefix.TOKEN_PREFIX, + body = CryptoCurrency.ID.Body.NetworkId(network.rawId), + suffix = CryptoCurrency.ID.Suffix.RawID("low-decimals-token", "0xLowDecimals"), + ) + val tokenWithLowDecimals = CryptoCurrency.Token( + id = tokenId, + network = network, + name = "Low Decimals Token", + symbol = "LDT", + decimals = 0, + iconUrl = null, + isCustom = false, + contractAddress = "0xLowDecimals", + ) + + val amount = BigDecimal("100.00") + val apy = BigDecimal("10.0") + + val status = CryptoCurrencyStatus( + currency = tokenWithLowDecimals, + value = CryptoCurrencyStatus.Custom( + amount = amount, + fiatAmount = null, + fiatRate = BigDecimal.ONE, + priceChange = null, + yieldBalance = null, + yieldSupplyStatus = null, + hasCurrentNetworkTransactions = false, + pendingTransactions = emptySet(), + networkAddress = NetworkAddress.Single( + NetworkAddress.Address(value = "0xabc", type = NetworkAddress.Address.Type.Primary), + ), + sources = CryptoCurrencyStatus.Sources(), + ), + ) + + coEvery { repository.getCachedMarkets() } returns listOf( + YieldMarketToken( + tokenAddress = tokenWithLowDecimals.contractAddress, + chainId = 1, + apy = apy, + isActive = true, + maxFeeNative = BigDecimal.ZERO, + maxFeeUSD = BigDecimal.ZERO, + backendId = "id", + ), + ) + + val dispatcherProvider = testDispatcherProvider(this) + val useCase = YieldSupplyGetRewardsBalanceUseCase(repository, dispatcherProvider) + val appCurrency = AppCurrency.Default + + val deferred = async { useCase(status, appCurrency).take(2).toList() } + + testScheduler.advanceUntilIdle() + advanceTimeBy(TICK_MILLIS) + testScheduler.advanceUntilIdle() + + val emissions = deferred.await() + assertThat(emissions).hasSize(2) + assertThat(emissions[0].cryptoBalance).isNotNull() + assertThat(emissions[1].cryptoBalance).isNotNull() + } } \ No newline at end of file From 33f2e5f297c8fd8fa6a6ff018eea3640f5aaa0f5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 29 Dec 2025 15:36:22 +0500 Subject: [PATCH 30/36] Updated on 2026-08-14 --- .../utils/NetworkLogsSaveInterceptor.kt | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/core/datasource/src/main/java/com/tangem/datasource/utils/NetworkLogsSaveInterceptor.kt b/core/datasource/src/main/java/com/tangem/datasource/utils/NetworkLogsSaveInterceptor.kt index 9e3d88dcb4..55d88cd09e 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/utils/NetworkLogsSaveInterceptor.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/utils/NetworkLogsSaveInterceptor.kt @@ -32,8 +32,16 @@ class NetworkLogsSaveInterceptor( @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() + val host = request.url.host + val path = request.url.encodedPath + val isRestrictedUrl = restrictedForLogURLs.contains(host + path) + val isRestrictedHost = restrictedForLogHosts.any { host.contains(it) } - logRequestMessage(chain, request) + if (isRestrictedUrl || isRestrictedHost) { + logEmptyRequestMessage(chain, request) + } else { + logRequestMessage(chain, request) + } val startNs = System.nanoTime() val response: Response @@ -44,11 +52,6 @@ class NetworkLogsSaveInterceptor( throw e } - val host = request.url.host - val path = request.url.encodedPath - val isRestrictedUrl = restrictedForLogURLs.contains(host + path) - val isRestrictedHost = restrictedForLogHosts.any { host.contains(it) } - if (isRestrictedUrl || isRestrictedHost) { logResponseWithEmptyMessage(response, startNs) } else { @@ -58,6 +61,13 @@ class NetworkLogsSaveInterceptor( return response } + private fun logEmptyRequestMessage(chain: Interceptor.Chain, request: Request) { + val connection = chain.connection() + val connectionProtocol = if (connection != null) " ${connection.protocol()}" else "" + + saveLogMessage("--> ${request.method} ${request.url}$connectionProtocol\n") + } + private fun logRequestMessage(chain: Interceptor.Chain, request: Request) { val connection = chain.connection() val connectionProtocol = if (connection != null) " ${connection.protocol()}" else "" From 7e7a07605ae8d833b6a59460dadb4bb78ff470b7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Dec 2025 17:54:01 +0500 Subject: [PATCH 31/36] Updated on 2026-08-14 --- .../cardsettings/model/CardSettingsModel.kt | 24 +++--- .../details/ui/resetcard/ResetCardScreen.kt | 36 ++++----- .../ui/resetcard/ResetCardScreenState.kt | 19 +++-- .../ui/resetcard/api/ResetCardComponent.kt | 1 + .../ui/resetcard/model/ResetCardModel.kt | 73 +++++++++++-------- .../tangem/tap/routing/utils/ChildFactory.kt | 1 + .../com/tangem/common/routing/AppRoute.kt | 1 + core/res/src/main/res/values/strings.xml | 2 + 8 files changed, 87 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt index 08aa5ef0b0..797ef6c056 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt @@ -18,6 +18,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.wallet.requireColdWallet +import com.tangem.domain.pay.repository.OnboardingRepository import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.domain.wallets.usecase.GetUserWalletUseCase @@ -54,6 +55,7 @@ internal class CardSettingsModel @Inject constructor( private val getUserWalletUseCase: GetUserWalletUseCase, private val cardSdkConfigRepository: CardSdkConfigRepository, private val settingsRepository: SettingsRepository, + private val onboardingRepository: OnboardingRepository, ) : Model() { private val params = paramsContainer.require() @@ -218,15 +220,19 @@ internal class CardSettingsModel @Inject constructor( } else { val card = scanResponse.card - store.dispatchNavigationAction { - push( - route = AppRoute.ResetToFactory( - userWalletId = userWalletId, - cardId = card.cardId, - isActiveBackupStatus = card.backupStatus?.isActive == true, - backupCardsCount = scanResponse.getBackupCardsCount() ?: 0, - ), - ) + modelScope.launch { + val hasTangemPay = onboardingRepository.checkCustomerWallet(userWalletId).getOrNull() == true + store.dispatchNavigationAction { + push( + route = AppRoute.ResetToFactory( + userWalletId = userWalletId, + cardId = card.cardId, + isActiveBackupStatus = card.backupStatus?.isActive == true, + backupCardsCount = scanResponse.getBackupCardsCount() ?: 0, + hasTangemPay = hasTangemPay, + ), + ) + } } } } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt index 3e04e9381b..818620b38f 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreen.kt @@ -22,6 +22,7 @@ import com.tangem.core.ui.extensions.resolveReference import com.tangem.tap.features.details.ui.common.DetailsMainButton import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold import com.tangem.wallet.R +import kotlinx.collections.immutable.persistentListOf import com.tangem.tap.features.details.ui.resetcard.ResetCardScreenState.Dialog as ResetCardDialog @Composable @@ -114,22 +115,11 @@ private fun Description(text: TextReference) { @Composable private fun Conditions(state: ResetCardScreenState) { state.warningsToShow.forEach { warning -> - when (warning) { - ResetCardScreenState.WarningsToReset.LOST_WALLET_ACCESS -> { - ConditionCheckBox( - checkedState = state.isAcceptCondition1Checked, - onCheckedChange = state.onAcceptCondition1ToggleClick, - description = TextReference.Res(R.string.reset_card_to_factory_condition_1), - ) - } - ResetCardScreenState.WarningsToReset.LOST_PASSWORD_RESTORE -> { - ConditionCheckBox( - checkedState = state.isAcceptCondition2Checked, - onCheckedChange = state.onAcceptCondition2ToggleClick, - description = TextReference.Res(R.string.reset_card_to_factory_condition_2), - ) - } - } + ConditionCheckBox( + checkedState = warning.isChecked, + onCheckedChange = { state.onToggleWarning(warning.type) }, + description = warning.description, + ) } } @@ -239,14 +229,16 @@ private fun ResetCardScreenSample(modifier: Modifier = Modifier) { ResetCardScreen( state = ResetCardScreenState( isResetButtonEnabled = true, - isResetPasswordButtonShown = false, - warningsToShow = listOf(ResetCardScreenState.WarningsToReset.LOST_WALLET_ACCESS), + warningsToShow = persistentListOf( + ResetCardScreenState.WarningUM( + isChecked = false, + type = ResetCardScreenState.WarningType.LOST_WALLET_ACCESS, + description = TextReference.Res(id = R.string.reset_card_to_factory_condition_1), + ), + ), descriptionText = TextReference.Res(R.string.reset_card_with_backup_to_factory_message), - isAcceptCondition1Checked = false, - isAcceptCondition2Checked = false, - onAcceptCondition1ToggleClick = {}, - onAcceptCondition2ToggleClick = {}, onResetButtonClick = {}, + onToggleWarning = {}, dialog = null, ), onBackClick = {}, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt index 68b8585c72..0011e5dcd6 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/ResetCardScreenState.kt @@ -3,16 +3,13 @@ package com.tangem.tap.features.details.ui.resetcard import androidx.annotation.StringRes import com.tangem.core.ui.extensions.TextReference import com.tangem.wallet.R +import kotlinx.collections.immutable.ImmutableList internal data class ResetCardScreenState( val isResetButtonEnabled: Boolean, val descriptionText: TextReference, - val warningsToShow: List, - val isResetPasswordButtonShown: Boolean, - val isAcceptCondition1Checked: Boolean, - val isAcceptCondition2Checked: Boolean, - val onAcceptCondition1ToggleClick: (Boolean) -> Unit, - val onAcceptCondition2ToggleClick: (Boolean) -> Unit, + val warningsToShow: ImmutableList, + val onToggleWarning: (WarningType) -> Unit, val onResetButtonClick: () -> Unit, val dialog: Dialog?, ) { @@ -58,7 +55,13 @@ internal data class ResetCardScreenState( } } - internal enum class WarningsToReset { - LOST_WALLET_ACCESS, LOST_PASSWORD_RESTORE + internal data class WarningUM( + val isChecked: Boolean, + val type: WarningType, + val description: TextReference, + ) + + internal enum class WarningType { + LOST_WALLET_ACCESS, LOST_PASSWORD_RESTORE, LOST_TANGEM_PAY } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/api/ResetCardComponent.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/api/ResetCardComponent.kt index 64dc8b1c5d..9f24f61f9b 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/api/ResetCardComponent.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/api/ResetCardComponent.kt @@ -11,6 +11,7 @@ interface ResetCardComponent : ComposableContentComponent { val cardId: String, val isActiveBackupStatus: Boolean, val backupCardsCount: Int, + val hasTangemPay: Boolean, ) interface Factory : ComponentFactory diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt index eaa4ce0a9f..c53ead9529 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/resetcard/model/ResetCardModel.kt @@ -8,6 +8,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.core.ui.extensions.TextReference import com.tangem.domain.card.DeleteSavedAccessCodesUseCase import com.tangem.domain.card.ResetCardUseCase import com.tangem.domain.card.ResetCardUserCodeParams @@ -30,6 +31,9 @@ import com.tangem.tap.features.details.ui.resetcard.api.ResetCardComponent import com.tangem.tap.store import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE +import com.tangem.wallet.R +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update @@ -82,33 +86,22 @@ internal class ResetCardModel @Inject constructor( // TODO: move logic to separate domain entity private var resetBackupCardCount = 0 + private var warningsMap = emptyMap() + val screenState: MutableStateFlow = MutableStateFlow( value = getInitialState(), ) private fun getInitialState(): ResetCardScreenState { - val shouldShowResetPasswordButton = shouldShowResetPasswordButton() - val warningsToShow = buildList { - add(ResetCardScreenState.WarningsToReset.LOST_WALLET_ACCESS) - - if (shouldShowResetPasswordButton) { - add(ResetCardScreenState.WarningsToReset.LOST_PASSWORD_RESTORE) - } - } - return ResetCardScreenState( isResetButtonEnabled = false, descriptionText = getResetToFactoryDescription( isActiveBackupStatus = isActiveBackupPrimaryCard, typesResolver = currentCardTypesResolver, ), - warningsToShow = warningsToShow, - isResetPasswordButtonShown = shouldShowResetPasswordButton, - isAcceptCondition1Checked = false, - isAcceptCondition2Checked = false, - onAcceptCondition1ToggleClick = ::toggleFirstCondition, - onAcceptCondition2ToggleClick = ::toggleSecondCondition, + warningsToShow = buildInitialItems(), onResetButtonClick = { showDialog(ResetCardDialog.StartResetDialog) }, + onToggleWarning = ::toggleCondition, dialog = null, ) } @@ -119,28 +112,46 @@ internal class ResetCardModel @Inject constructor( return isTangemWallet && isActiveBackupPrimaryCard } - private fun toggleFirstCondition(isAccepted: Boolean) { - screenState.update { prevState -> - val isResetButtonEnabled = if (prevState.isResetPasswordButtonShown) { - isAccepted && prevState.isAcceptCondition2Checked - } else { - isAccepted - } + private fun buildInitialItems(): ImmutableList { + val shouldShowResetPasswordButton = shouldShowResetPasswordButton() + val shouldShowResetTangemPayButton = params.hasTangemPay - prevState.copy( - isAcceptCondition1Checked = isAccepted, - isResetButtonEnabled = isResetButtonEnabled, - ) + val lostWalletUM = ResetCardScreenState.WarningUM( + isChecked = false, + type = ResetCardScreenState.WarningType.LOST_WALLET_ACCESS, + description = TextReference.Res(id = R.string.reset_card_to_factory_condition_1), + ) + val lostPasswordUM = ResetCardScreenState.WarningUM( + isChecked = false, + type = ResetCardScreenState.WarningType.LOST_PASSWORD_RESTORE, + description = TextReference.Res(R.string.reset_card_to_factory_condition_2), + ) + val lostTangemPayUM = ResetCardScreenState.WarningUM( + isChecked = false, + type = ResetCardScreenState.WarningType.LOST_TANGEM_PAY, + description = TextReference.Res(R.string.reset_card_to_factory_condition_3), + ) + + warningsMap = buildMap { + put(ResetCardScreenState.WarningType.LOST_WALLET_ACCESS, lostWalletUM) + if (shouldShowResetPasswordButton) { + put(ResetCardScreenState.WarningType.LOST_PASSWORD_RESTORE, lostPasswordUM) + } + if (shouldShowResetTangemPayButton) { + put(ResetCardScreenState.WarningType.LOST_TANGEM_PAY, lostTangemPayUM) + } } + return warningsMap.values.toImmutableList() } - private fun toggleSecondCondition(isAccepted: Boolean) { + private fun toggleCondition(type: ResetCardScreenState.WarningType) { screenState.update { prevState -> - val isResetButtonEnabled = prevState.isAcceptCondition1Checked && isAccepted - + warningsMap[type]?.let { current -> + warningsMap = warningsMap + (type to current.copy(isChecked = !current.isChecked)) + } prevState.copy( - isAcceptCondition2Checked = isAccepted, - isResetButtonEnabled = isResetButtonEnabled, + warningsToShow = warningsMap.values.toImmutableList(), + isResetButtonEnabled = warningsMap.values.all { it.isChecked }, ) } } diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt index 715bf51463..19f07cabf5 100644 --- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt +++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt @@ -424,6 +424,7 @@ internal class ChildFactory @Inject constructor( cardId = route.cardId, isActiveBackupStatus = route.isActiveBackupStatus, backupCardsCount = route.backupCardsCount, + hasTangemPay = route.hasTangemPay, ), componentFactory = resetCardComponentFactory, ) diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index c2d8b480d7..e5bdf4dad1 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -112,6 +112,7 @@ sealed class AppRoute(val path: String) : Route { val cardId: String, val isActiveBackupStatus: Boolean, val backupCardsCount: Int, + val hasTangemPay: Boolean, ) : AppRoute( path = "/reset_to_factory" + "/${userWalletId.stringValue}" + diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 1a5e95cd53..9bc5664570 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -816,6 +816,7 @@ Quick recap Related News + Related tokens Sources Stay in the loop NFC is not available on your device @@ -1531,6 +1532,7 @@ We’re fixing a technical issue. Please try again later. Service temporarily unavailable Unable to display details. However, card payments are still working. + Set \nPIN code Not synced Restore access Use USDC for everyday payments From 3ef88c33eecb83f5b5111fe8de0650935982bd18 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 29 Dec 2025 16:06:50 +0300 Subject: [PATCH 32/36] 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 55284d02b1..21f77fa638 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.32-1331" +tangemBlockchainSdk = "releases-5.32-1335" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.32-574" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From d128f48b057b7b9b0584616bb6d6c152d7da2ee0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 29 Dec 2025 17:48:35 +0400 Subject: [PATCH 33/36] Updated on 2026-08-14 --- .../ui/tokens/TokenItemStateConverter.kt | 11 +++++++ .../models/event/MainScreenAnalyticsEvent.kt | 22 ++++++++++++++ .../token/internal/YieldSupplyPromoBanner.kt | 4 +++ .../components/token/state/TokenItemState.kt | 1 + .../intents/WalletContentClickIntents.kt | 30 ++++++++++++++++++- .../utils/TokenListAnalyticsSender.kt | 15 ++++++++++ .../converter/TokenListStateConverter.kt | 2 ++ 7 files changed, 84 insertions(+), 1 deletion(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt index 38a1c8c270..c92f348a54 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt @@ -51,6 +51,8 @@ class TokenItemStateConverter( }, private val onApyLabelClick: ((CryptoCurrencyStatus, ApySource, String) -> Unit)? = null, private val onYieldPromoCloseClick: (() -> Unit)? = null, + private val onYieldPromoShown: ((cryptoCurrency: CryptoCurrency) -> Unit)? = null, + private val onYieldPromoClicked: ((cryptoCurrency: CryptoCurrency) -> Unit)? = null, private val titleStateProvider: (CryptoCurrencyStatus) -> TokenItemState.TitleState = { currencyStatus -> createTitleState( currencyStatus = currencyStatus, @@ -75,6 +77,8 @@ class TokenItemStateConverter( yieldSupplyPromoBannerKey = yieldSupplyPromoBannerKey, onApyLabelClick = onApyLabelClick, onYieldPromoCloseClick = onYieldPromoCloseClick, + onYieldPromoShown = onYieldPromoShown, + onYieldPromoClicked = onYieldPromoClicked, ) }, private val onItemClick: ((TokenItemState, CryptoCurrencyStatus) -> Unit)? = null, @@ -389,12 +393,15 @@ class TokenItemStateConverter( } } + @Suppress("LongParameterList") private fun createPromoBannerState( status: CryptoCurrencyStatus, yieldModuleApyMap: Map, yieldSupplyPromoBannerKey: String?, onApyLabelClick: ((CryptoCurrencyStatus, ApySource, String) -> Unit)?, onYieldPromoCloseClick: (() -> Unit)?, + onYieldPromoShown: ((cryptoCurrency: CryptoCurrency) -> Unit)?, + onYieldPromoClicked: ((cryptoCurrency: CryptoCurrency) -> Unit)?, ): TokenItemState.PromoBannerState { val token = status.currency as? CryptoCurrency.Token ?: return TokenItemState.PromoBannerState.Empty if (status.value !is CryptoCurrencyStatus.Loaded) { @@ -414,11 +421,15 @@ class TokenItemStateConverter( wrappedList(yieldSupplyApy), ), onPromoBannerClick = { + onYieldPromoClicked?.invoke(status.currency) onApyLabelClick?.invoke(status, ApySource.YIELD_SUPPLY, yieldSupplyApy.toString()) }, onCloseClick = { onYieldPromoCloseClick?.invoke() }, + onPromoShown = { + onYieldPromoShown?.invoke(status.currency) + }, ) } diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/MainScreenAnalyticsEvent.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/MainScreenAnalyticsEvent.kt index c8864d3617..c7958a7e35 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/MainScreenAnalyticsEvent.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/MainScreenAnalyticsEvent.kt @@ -126,6 +126,28 @@ sealed class MainScreenAnalyticsEvent( STATE to state, ), ) + + data class YieldPromo( + val token: String, + val blockchain: String, + ) : MainScreenAnalyticsEvent( + event = "Yield Promo", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class YieldPromoClicked( + val token: String, + val blockchain: String, + ) : MainScreenAnalyticsEvent( + event = "Yield Promo Clicked", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) // endregion companion object { diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt index b949061451..71ccba070a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt @@ -18,6 +18,7 @@ import android.content.res.Configuration import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.material3.ripple +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource @@ -39,6 +40,9 @@ internal fun YieldSupplyPromoBanner(state: PromoBannerState, modifier: Modifier @Composable internal fun YieldSupplyPromoBanner(state: PromoBannerState.Content, modifier: Modifier = Modifier) { + LaunchedEffect(state) { + state.onPromoShown() + } val bgColor = TangemTheme.colors.control.unchecked Column(modifier = modifier) { Row( diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt index a2180bb614..7193eed339 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt @@ -269,6 +269,7 @@ sealed class TokenItemState { val title: TextReference, val onPromoBannerClick: () -> Unit, val onCloseClick: () -> Unit, + val onPromoShown: () -> Unit = {}, ) : PromoBannerState() data object Empty : PromoBannerState() diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt index 4c0038bfe2..46fbfc16d4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt @@ -7,6 +7,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.models.account.Account +import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.staking.YieldBalance import com.tangem.domain.models.wallet.UserWallet @@ -23,6 +24,7 @@ import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyEnterStatusUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplySetShouldShowMainPromoUseCase import com.tangem.feature.wallet.presentation.account.AccountDependencies +import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory import com.tangem.feature.wallet.presentation.wallet.domain.unwrap import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController @@ -60,6 +62,10 @@ internal interface WalletContentClickIntents { fun onYieldPromoCloseClick() + fun onYieldPromoShown(cryptoCurrency: CryptoCurrency) + + fun onYieldPromoClicked(cryptoCurrency: CryptoCurrency) + fun onAccountExpandClick(account: Account) fun onAccountCollapseClick(account: Account) @@ -79,7 +85,7 @@ internal interface WalletContentClickIntents { fun onNFTClick(userWallet: UserWallet) } -@Suppress("LongParameterList") +@Suppress("LongParameterList", "LargeClass") @ModelScoped internal class WalletContentClickIntentsImplementor @Inject constructor( private val stateHolder: WalletStateController, @@ -98,6 +104,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( private val accountDependencies: AccountDependencies, private val yieldSupplyEnterStatusUseCase: YieldSupplyEnterStatusUseCase, private val yieldSupplySetShouldShowMainPromoUseCase: YieldSupplySetShouldShowMainPromoUseCase, + private val tokenListAnalyticsSender: TokenListAnalyticsSender, ) : BaseWalletClickIntents(), WalletContentClickIntents { override fun onDetailsClick() { @@ -203,6 +210,27 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( } } + override fun onYieldPromoShown(cryptoCurrency: CryptoCurrency) { + modelScope.launch(dispatchers.io) { + tokenListAnalyticsSender.sendYieldPromoShown( + userWalletId = stateHolder.getSelectedWalletId(), + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ) + } + } + + override fun onYieldPromoClicked(cryptoCurrency: CryptoCurrency) { + modelScope.launch(dispatchers.io) { + analyticsEventHandler.send( + MainScreenAnalyticsEvent.YieldPromoClicked( + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ), + ) + } + } + override fun onAccountExpandClick(account: Account) { val userWalletId = stateHolder.getSelectedWalletId() accountDependencies.expandedAccountsHolder.expandAccount(userWalletId, account.accountId) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt index fe583f7183..eb12beb3f3 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt @@ -8,6 +8,7 @@ import com.tangem.blockchainsdk.utils.fromNetworkId import com.tangem.common.extensions.isZero 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.domain.analytics.CheckIsWalletToppedUpUseCase import com.tangem.domain.analytics.model.WalletBalanceState @@ -34,6 +35,7 @@ internal class TokenListAnalyticsSender @Inject constructor( ) { private val balanceWasSentMap = mutableMapOf() + private val yieldPromoShownMap = mutableMapOf() private val mutex = Mutex() private val loadingTraces = mutableMapOf() @@ -233,6 +235,19 @@ internal class TokenListAnalyticsSender @Inject constructor( } } + fun sendYieldPromoShown(userWalletId: UserWalletId, token: String, blockchain: String) { + val key = "${userWalletId.stringValue}_${blockchain}_$token" + if (yieldPromoShownMap[key] == true) return + + analyticsEventHandler.send( + MainScreenAnalyticsEvent.YieldPromo( + token = token, + blockchain = blockchain, + ), + ) + yieldPromoShownMap[key] = true + } + companion object { const val BALANCE_LOADED_TRACE_NAME = "Total_balance_loaded" const val HAS_ERROR = "has_error" diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt index 2520491085..2d42286d42 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt @@ -78,6 +78,8 @@ internal class TokenListStateConverter( onItemLongClick = { _, status -> onTokenLongClick(accountId, status) }, onApyLabelClick = { status, apySource, apy -> onApyLabelClick(status, apySource, apy) }, onYieldPromoCloseClick = clickIntents::onYieldPromoCloseClick, + onYieldPromoShown = clickIntents::onYieldPromoShown, + onYieldPromoClicked = clickIntents::onYieldPromoClicked, ) override fun convert(value: WalletTokensListState): WalletTokensListState { From 8d813113bdb8ea1adc3a51248928176cc3fbfe9d Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 29 Dec 2025 21:47:19 +0500 Subject: [PATCH 34/36] Updated on 2026-08-14 --- .../tap/domain/sdk/impl/DefaultTangemSdkManager.kt | 12 +++++++----- .../tap/domain/sdk/impl/MockTangemSdkManager.kt | 4 ++-- .../TangemPayGenerateAddressAndSignChallengeTask.kt | 4 +--- .../tasks/visa/TangemPaySignWithdrawalHashTask.kt | 10 +--------- data/visa/build.gradle.kts | 1 + .../pay/datasource/DefaultTangemPayAuthDataSource.kt | 11 +++++++++-- .../kotlin/com/tangem/sdk/api/TangemSdkManager.kt | 9 +++++++-- 7 files changed, 28 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt index 981b99ecf8..ef82b7c01f 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt @@ -519,13 +519,14 @@ internal class DefaultTangemSdkManager( } override suspend fun tangemPayProduceInitialCredentials( - cardId: String, + preflightReadFilter: PreflightReadFilter, ): Either { return coroutineScope { val result = runTaskAsyncReturnOnMain( runnable = tangemPayChallengeTaskFactory.create(coroutineScope = this), - cardId = cardId, + cardId = null, initialMessage = Message(resources.getStringSafe(R.string.initial_message_tap_header)), + preflightReadFilter = preflightReadFilter, ) return@coroutineScope when (result) { @@ -536,14 +537,15 @@ internal class DefaultTangemSdkManager( } override suspend fun getWithdrawalSignature( - cardId: String, hash: String, + preflightReadFilter: PreflightReadFilter, ): Either { return coroutineScope { val result = runTaskAsyncReturnOnMain( - runnable = TangemPaySignWithdrawalHashTask(cardId = cardId, hash = hash.hexToBytes()), - cardId = cardId, + runnable = TangemPaySignWithdrawalHashTask(hash = hash.hexToBytes()), + cardId = null, initialMessage = Message(resources.getStringSafe(R.string.initial_message_tap_header)), + preflightReadFilter = preflightReadFilter, ) return@coroutineScope when (result) { diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt index 54e9e33aca..00e4ea971e 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt @@ -219,14 +219,14 @@ class MockTangemSdkManager( } override suspend fun tangemPayProduceInitialCredentials( - cardId: String, + preflightReadFilter: PreflightReadFilter, ): Either { error("Not implemented") } override suspend fun getWithdrawalSignature( - cardId: String, hash: String, + preflightReadFilter: PreflightReadFilter, ): Either { error("Not implemented") } diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPayGenerateAddressAndSignChallengeTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPayGenerateAddressAndSignChallengeTask.kt index 4550d3dc52..c4e437b4ff 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPayGenerateAddressAndSignChallengeTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPayGenerateAddressAndSignChallengeTask.kt @@ -62,7 +62,6 @@ class TangemPayGenerateAddressAndSignChallengeTask @AssistedInject constructor( val dataToSign = VisaDataToSignByCustomerWallet(hashToSign = challenge.challenge) val approveResult = runVisaCustomerWalletApproveTask( session = session, - cardId = card.cardId, targetAddress = address, dataToSign = dataToSign, ) @@ -103,14 +102,13 @@ class TangemPayGenerateAddressAndSignChallengeTask @AssistedInject constructor( private suspend fun runVisaCustomerWalletApproveTask( session: CardSession, - cardId: String, targetAddress: String, dataToSign: VisaDataToSignByCustomerWallet, ): CompletionResult { val deferred = CompletableDeferred>() val task = VisaCustomerWalletApproveTask( visaDataForApprove = VisaCustomerWalletApproveTask.Input( - cardId = cardId, + cardId = null, targetAddress = targetAddress, hashToSign = dataToSign.hashToSign, sign = dataToSign::sign, diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPaySignWithdrawalHashTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPaySignWithdrawalHashTask.kt index 2cf1b0f42c..150c5c35ba 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPaySignWithdrawalHashTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/visa/TangemPaySignWithdrawalHashTask.kt @@ -14,10 +14,7 @@ import com.tangem.domain.visa.error.VisaActivationError import com.tangem.operations.derivation.DeriveWalletPublicKeyTask import com.tangem.operations.sign.SignHashCommand -class TangemPaySignWithdrawalHashTask( - private val cardId: String, - private val hash: ByteArray, -) : CardSessionRunnable { +class TangemPaySignWithdrawalHashTask(private val hash: ByteArray) : CardSessionRunnable { override fun run(session: CardSession, callback: CompletionCallback) { val card = session.environment.card ?: run { @@ -25,11 +22,6 @@ class TangemPaySignWithdrawalHashTask( return } - if (card.cardId != cardId) { - callback(CompletionResult.Failure(VisaActivationError.CardIdNotMatched.tangemError)) - return - } - proceedSign(card, session, callback) } diff --git a/data/visa/build.gradle.kts b/data/visa/build.gradle.kts index e1e1568878..3c9ef9ff07 100644 --- a/data/visa/build.gradle.kts +++ b/data/visa/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { implementation(projects.core.error.ext) implementation(projects.core.security) implementation(projects.data.common) + implementation(projects.data.wallets) /** Project - Domain */ implementation(projects.domain.visa) diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/datasource/DefaultTangemPayAuthDataSource.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/datasource/DefaultTangemPayAuthDataSource.kt index 6af402c591..8198c181ce 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/datasource/DefaultTangemPayAuthDataSource.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/datasource/DefaultTangemPayAuthDataSource.kt @@ -1,6 +1,7 @@ package com.tangem.data.pay.datasource import arrow.core.Either +import com.tangem.data.wallets.cold.UserWalletIdPreflightReadFilter import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.pay.WithdrawalSignatureResult import com.tangem.domain.pay.datasource.TangemPayAuthDataSource @@ -17,7 +18,10 @@ internal class DefaultTangemPayAuthDataSource @Inject constructor( userWallet: UserWallet, ): Either { return when (userWallet) { - is UserWallet.Cold -> tangemSdkManager.tangemPayProduceInitialCredentials(cardId = userWallet.cardId) + is UserWallet.Cold -> { + val preflightReadFilter = UserWalletIdPreflightReadFilter(userWallet.walletId) + tangemSdkManager.tangemPayProduceInitialCredentials(preflightReadFilter = preflightReadFilter) + } is UserWallet.Hot -> tangemPayHotSdkManager.produceInitialCredentials(userWallet) } } @@ -27,7 +31,10 @@ internal class DefaultTangemPayAuthDataSource @Inject constructor( hash: String, ): Either { return when (userWallet) { - is UserWallet.Cold -> tangemSdkManager.getWithdrawalSignature(cardId = userWallet.cardId, hash = hash) + is UserWallet.Cold -> { + val preflightReadFilter = UserWalletIdPreflightReadFilter(userWallet.walletId) + tangemSdkManager.getWithdrawalSignature(hash = hash, preflightReadFilter = preflightReadFilter) + } is UserWallet.Hot -> tangemPayHotSdkManager.getWithdrawalSignature(hotWallet = userWallet, hash = hash) } } diff --git a/libs/tangem-sdk-api/src/main/kotlin/com/tangem/sdk/api/TangemSdkManager.kt b/libs/tangem-sdk-api/src/main/kotlin/com/tangem/sdk/api/TangemSdkManager.kt index 07a2d02773..64016c2cf8 100644 --- a/libs/tangem-sdk-api/src/main/kotlin/com/tangem/sdk/api/TangemSdkManager.kt +++ b/libs/tangem-sdk-api/src/main/kotlin/com/tangem/sdk/api/TangemSdkManager.kt @@ -161,8 +161,13 @@ interface TangemSdkManager { visaDataForApprove: VisaDataForApprove, ): CompletionResult - suspend fun tangemPayProduceInitialCredentials(cardId: String): Either + suspend fun tangemPayProduceInitialCredentials( + preflightReadFilter: PreflightReadFilter, + ): Either - suspend fun getWithdrawalSignature(cardId: String, hash: String): Either + suspend fun getWithdrawalSignature( + hash: String, + preflightReadFilter: PreflightReadFilter, + ): Either // endregion } \ No newline at end of file From 0d683cbd459e674bf83640386bf74a75c0b2046b Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 30 Dec 2025 07:55:03 +0000 Subject: [PATCH 35/36] 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 3a00dc0651..21f77fa638 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,13 +5,13 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.31.1-1334" +tangemBlockchainSdk = "releases-5.32-1335" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.31-569" +tangemCardSdk = "releases-5.32-574" #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 ^ -tangemHotSdk = "develop-531" +tangemHotSdk = "develop-539" #tangemHotSdk = "0.0.1" # Keep it! - used for local builds ^ From 93ee92d3031f72b780b0f21169e65200f76543b1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 30 Dec 2025 08:44:53 +0000 Subject: [PATCH 36/36] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 21f77fa638..36965eb1e1 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.32-1335" +tangemBlockchainSdk = "develop-1330" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.32-574" +tangemCardSdk = "develop-573" #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 ^