Updated on 2026-08-14
This commit is contained in:
commit
75e81283f8
108 changed files with 1345 additions and 482 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 5fc86d29bc2c0dc7c057ab0242b2cfa3e9f48daf
|
||||
Subproject commit 78be297b0f09bc2be1e9b0fbab9384f17bf94c37
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<String, String>) {
|
||||
client.logEvent(eventId, params)
|
||||
override fun send(event: AnalyticsEvent) {
|
||||
client.logEvent(event.id, event.params)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -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<String, String>) {
|
||||
appsFlyerLib.logEvent(context, event, params)
|
||||
appsFlyerLib.logEvent(
|
||||
context,
|
||||
event,
|
||||
eventConverter.convertEventParams(params),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, String>) {
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
|
@ -12,4 +12,12 @@ internal class AppsFlyerLogClient(
|
|||
override fun logEvent(event: String, params: Map<String, String>) {
|
||||
logger.logEvent(event, params)
|
||||
}
|
||||
|
||||
override fun setUserId(userId: String) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun clearUserId() {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, String>) {
|
||||
client.logEvent(eventId, params)
|
||||
override fun send(event: AnalyticsEvent) {
|
||||
client.logEvent(event.id, event.params)
|
||||
}
|
||||
|
||||
override fun sendException(event: ExceptionAnalyticsEvent) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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,
|
||||
|
|
@ -53,6 +55,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 +78,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)
|
||||
|
|
@ -109,15 +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.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<String>(PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY)
|
||||
|
|
@ -159,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"
|
||||
|
|
|
|||
|
|
@ -519,13 +519,14 @@ internal class DefaultTangemSdkManager(
|
|||
}
|
||||
|
||||
override suspend fun tangemPayProduceInitialCredentials(
|
||||
cardId: String,
|
||||
preflightReadFilter: PreflightReadFilter,
|
||||
): Either<Throwable, TangemPayInitialCredentials> {
|
||||
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<Throwable, WithdrawalSignatureResult> {
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -219,14 +219,14 @@ class MockTangemSdkManager(
|
|||
}
|
||||
|
||||
override suspend fun tangemPayProduceInitialCredentials(
|
||||
cardId: String,
|
||||
preflightReadFilter: PreflightReadFilter,
|
||||
): Either<Throwable, TangemPayInitialCredentials> {
|
||||
error("Not implemented")
|
||||
}
|
||||
|
||||
override suspend fun getWithdrawalSignature(
|
||||
cardId: String,
|
||||
hash: String,
|
||||
preflightReadFilter: PreflightReadFilter,
|
||||
): Either<Throwable, WithdrawalSignatureResult> {
|
||||
error("Not implemented")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<VisaSignedDataByCustomerWallet> {
|
||||
val deferred = CompletableDeferred<CompletionResult<VisaSignedDataByCustomerWallet>>()
|
||||
val task = VisaCustomerWalletApproveTask(
|
||||
visaDataForApprove = VisaCustomerWalletApproveTask.Input(
|
||||
cardId = cardId,
|
||||
cardId = null,
|
||||
targetAddress = targetAddress,
|
||||
hashToSign = dataToSign.hashToSign,
|
||||
sign = dataToSign::sign,
|
||||
|
|
|
|||
|
|
@ -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<String> {
|
||||
class TangemPaySignWithdrawalHashTask(private val hash: ByteArray) : CardSessionRunnable<String> {
|
||||
|
||||
override fun run(session: CardSession, callback: CompletionCallback<String>) {
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -52,6 +52,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,
|
||||
|
|
@ -76,6 +78,8 @@ class TokenItemStateConverter(
|
|||
yieldSupplyPromoBannerKey = yieldSupplyPromoBannerKey,
|
||||
onApyLabelClick = onApyLabelClick,
|
||||
onYieldPromoCloseClick = onYieldPromoCloseClick,
|
||||
onYieldPromoShown = onYieldPromoShown,
|
||||
onYieldPromoClicked = onYieldPromoClicked,
|
||||
)
|
||||
},
|
||||
private val onItemClick: ((TokenItemState, CryptoCurrencyStatus) -> Unit)? = null,
|
||||
|
|
@ -395,12 +399,15 @@ class TokenItemStateConverter(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
private fun createPromoBannerState(
|
||||
status: CryptoCurrencyStatus,
|
||||
yieldModuleApyMap: Map<String, BigDecimal>,
|
||||
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) {
|
||||
|
|
@ -420,11 +427,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)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -134,6 +134,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 {
|
||||
|
|
|
|||
|
|
@ -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<String, String> = 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")
|
||||
|
|
|
|||
|
|
@ -27,11 +27,7 @@ interface AnalyticsHandler : AnalyticsEventHandler {
|
|||
|
||||
fun id(): String
|
||||
|
||||
fun send(eventId: String, params: Map<String, String> = emptyMap())
|
||||
|
||||
override fun send(event: AnalyticsEvent) {
|
||||
send(event.id, event.params)
|
||||
}
|
||||
override fun send(event: AnalyticsEvent)
|
||||
}
|
||||
|
||||
interface AnalyticsHandlerHolder {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,12 @@ interface TangemPayApi {
|
|||
@Path("customer_wallet_id") customerWalletId: String,
|
||||
): ApiResponse<CheckCustomerWalletResponse>
|
||||
|
||||
@PATCH("v1/customer/pay-enabled")
|
||||
suspend fun setTangemPayEnabledStatus(
|
||||
@Header("Authorization") authHeader: String,
|
||||
@Body body: SetTangemPayEnabledRequest,
|
||||
): ApiResponse<Any>
|
||||
|
||||
@POST("v1/deeplink/validate")
|
||||
suspend fun validateDeeplink(@Body body: DeeplinkValidityRequest): ApiResponse<DeeplinkValidityResponse>
|
||||
|
||||
|
|
@ -56,6 +62,12 @@ interface TangemPayApi {
|
|||
@Body body: CardDetailsRequest,
|
||||
): ApiResponse<CardDetailsResponse>
|
||||
|
||||
@GET("v1/customer/card/pin")
|
||||
suspend fun getPin(
|
||||
@Header("Authorization") authHeader: String,
|
||||
@Header("X-Session-Id") sessionId: String,
|
||||
): ApiResponse<GetPinResponse>
|
||||
|
||||
@PUT("v1/customer/card/pin")
|
||||
suspend fun setPin(
|
||||
@Header("Authorization") authHeader: String,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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?,
|
||||
)
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -3,14 +3,18 @@ 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)
|
||||
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)
|
||||
|
||||
|
|
@ -33,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)
|
||||
}
|
||||
|
|
@ -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 ""
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<string name="access_code_alert_skip_ok">Trotzdem überspringen</string>
|
||||
<string name="access_code_alert_skip_title">Zugangscode nicht festgelegt</string>
|
||||
<string name="access_code_alert_validation_cancel">Code ändern</string>
|
||||
<string name="access_code_alert_validation_description">Dein Zugangscode dient zum Entsperren Deiner Wallet und zum Schutz des Zugriffs auf Deine Vermögenswerte.</string>
|
||||
<string name="access_code_alert_validation_description">Dein Zugangscode entsperrt und schützt den Zugriff auf Deine Geldbörse.</string>
|
||||
<string name="access_code_alert_validation_ok">Trotzdem verwenden</string>
|
||||
<string name="access_code_alert_validation_title">Dieser Zugangscode kann leicht erraten werden</string>
|
||||
<string name="access_code_check_title">Zugangscode eingeben</string>
|
||||
|
|
@ -44,10 +44,12 @@
|
|||
<string name="account_form_edit_button">Speichern</string>
|
||||
<string name="account_form_name">Kontoname</string>
|
||||
<string name="account_form_name_already_exist_error_description">Der Kontoname ist bereits vorhanden</string>
|
||||
<string name="account_form_name_already_exist_error_title">Der Kontoname wird bereits verwendet.</string>
|
||||
<string name="account_form_placeholder_edit_account">Konto</string>
|
||||
<string name="account_form_placeholder_new_account">Neues Konto</string>
|
||||
<string name="account_form_title_create">Konto hinzufügen</string>
|
||||
<string name="account_form_title_edit">Konto bearbeiten</string>
|
||||
<string name="account_generic_error_dialog_message">Bitte versuche es später erneut. Sollte das Problem weiterhin bestehen, kontaktiere bitte unseren Support. Wir helfen Dir gerne bei der Lösung.</string>
|
||||
<string name="account_label_tokens_info">%1$s in %2$s</string>
|
||||
<string name="account_main_account_title">Hauptkonto</string>
|
||||
<string name="account_recover_limit_dialog_description">Du hast das Limit von %1$s aktiven Konten bereits überschritten. Archiviere eines zur Wiederherstellung</string>
|
||||
|
|
@ -95,7 +97,7 @@
|
|||
<string name="alert_manage_tokens_unsupported_message">Tokens im %1$s -Netzwerk werden von dieser Karte oder Ring aufgrund einer Firmware-Einschränkung nicht unterstützt.</string>
|
||||
<string name="alert_troubleshooting_scan_card_title">Hast du Probleme beim Scannen deiner Karte oder Ring?</string>
|
||||
<string name="alert_unsupported_card">Diese Karte oder Ring ist für die Zusammenarbeit mit Tangem nicht geeignet</string>
|
||||
<string name="app_settings_access_code_warning">Lege zunächst einen Zugangscode fest, um die Biometrie zu aktivieren.</string>
|
||||
<string name="app_settings_access_code_warning">Lege einen Zugangscode fest, um die Biometrie zu aktivieren.</string>
|
||||
<string name="app_settings_biometrics_footer">Verwende die %1$s um Deine Wallet zu entsperren und sensible Aktionen wie das Signieren von Transaktionen zu bestätigen. Bei Hardware-Wallets ist zum Signieren weiterhin eine Karte oder ein Ring erforderlich.</string>
|
||||
<string name="app_settings_default_fee">Standardgebühr</string>
|
||||
<string name="app_settings_default_fee_footer">Aktiviere die Option Standardgebühr, um die Transaktionsgebühren automatisch festzulegen und die Gebührenseite beim Senden von Geldern zu überspringen. Du kannst bei Bedarf jederzeit zu dieser Seite zurückkehren.</string>
|
||||
|
|
@ -144,10 +146,10 @@
|
|||
<string name="balance_hidden_title">Guthaben sind ausgeblendet</string>
|
||||
<string name="beta_mode_warning_message">Laut den Blockchain-Entwicklern befinden sich der Kaspa-Token derzeit in der Betaphase. Bleibe dran für Updates!</string>
|
||||
<string name="beta_mode_warning_title">Beta-Phase</string>
|
||||
<string name="biometric_disabled_warning_description">Die biometrischen Daten sind auf Deinem Gerät deaktiviert, sodass Du sie nicht zum Entsperren Deine Wallet verwenden kannst. Aktiviere die Biometrie in den Einstellungen Deines Geräts, um diese Methode wieder zu verwenden.</string>
|
||||
<string name="biometric_disabled_warning_description">Die Biometrie ist auf Deinem Gerät deaktiviert, daher kannst Du sie nicht zum Entsperren Deiner Wallets verwenden. Aktiviere die Biometrie in den Geräteeinstellungen, um diese Methode wieder nutzen zu können.</string>
|
||||
<string name="biometric_disabled_warning_title">Biometrische Authentifizierung deaktiviert</string>
|
||||
<string name="biometric_lockout_permanent_warning_description">Bitte Karte oder Ring scannen</string>
|
||||
<string name="biometric_lockout_permanent_warning_description_2">Du hast das Limit an biometrischen Entsperrversuchen erreicht. Bitte entsperren Deine Wallet durch Antippen Deines Geräts oder gib den Zugangscode ein.</string>
|
||||
<string name="biometric_lockout_permanent_warning_description_2">Du hast das Limit an biometrischen Entsperrversuchen erreicht. Bitte entsperre Deine Wallet mit einer Karte/einem Ring oder gib Deinen Zugangscode ein.</string>
|
||||
<string name="biometric_lockout_permanent_warning_title">Biometrische Authentifizierung gesperrt</string>
|
||||
<string name="biometric_lockout_warning_description">Bitte versuche es in 30 Sekunden erneut oder scanne die Karte oder Ring</string>
|
||||
<string name="biometric_lockout_warning_description_2">Die biometrische Anmeldung ist vorübergehend gesperrt. Bitte versuche es in 30 Sekunden erneut oder entsperre Deine Wallet durch Antippen Deines Geräts oder mit einem Zugangscode.</string>
|
||||
|
|
@ -373,6 +375,7 @@
|
|||
<string name="common_terms_and_conditions">Allgemeine Geschäftsbedingungen</string>
|
||||
<string name="common_terms_of_use">Nutzungsbedingungen</string>
|
||||
<string name="common_to">An</string>
|
||||
<string name="common_to_wallet_name">Zu %s</string>
|
||||
<string name="common_today">Heute</string>
|
||||
<plurals name="common_tokens_count">
|
||||
<item quantity="one">%d Token</item>
|
||||
|
|
@ -384,6 +387,7 @@
|
|||
<string name="common_transfer">Überweisung</string>
|
||||
<string name="common_unable_to_load">Die Daten konnten nicht geladen werden…</string>
|
||||
<string name="common_understand">Ich verstehe</string>
|
||||
<string name="common_understand_continue">Ich verstehe, fahre bitte fort.</string>
|
||||
<string name="common_unknown_error">Es ist ein Fehler aufgetreten. Bitte versuche es erneut.</string>
|
||||
<string name="common_unreachable">Nicht erreichbar</string>
|
||||
<string name="common_unstake">Staking beenden</string>
|
||||
|
|
@ -397,6 +401,7 @@
|
|||
<string name="currency_subtitle_expanded">Verfügbare Netzwerke</string>
|
||||
<string name="custom_token_another_account_dialog_description">Die Ableitung Deines Tokens entspricht der Ableitung von %1$s. Dein Token wird diesem Konto gutgeschrieben.</string>
|
||||
<string name="custom_token_another_account_dialog_title">Die Herleitung stammt aus einem anderen Bericht.</string>
|
||||
<string name="custom_token_another_account_snackbar_text">Token hinzugefügt %1$s Konto</string>
|
||||
<string name="custom_token_contract_address_input_title">Vertragsadresse</string>
|
||||
<string name="custom_token_creation_error_invalid_contract_address">Vertragsadresse ist ungültig</string>
|
||||
<string name="custom_token_creation_error_network_not_selected">Bitte wähle das Netzwerk</string>
|
||||
|
|
@ -448,7 +453,7 @@
|
|||
<string name="disclaimer_error_loading">Überprüfe deine Internetverbindung oder wechseln zu einem anderen Netzwerk</string>
|
||||
<string name="disclaimer_title">Nutzungsbedingungen</string>
|
||||
<string name="domain_receive_assets_default_address">Standardadresse</string>
|
||||
<string name="domain_receive_assets_legacy_address">Legacy adresse</string>
|
||||
<string name="domain_receive_assets_legacy_address">Legacy %s adresse</string>
|
||||
<string name="domain_receive_assets_navigation_title">Empfangen von Vermögenswerten</string>
|
||||
<string name="domain_receive_assets_network_name_address">%s Adresse</string>
|
||||
<string name="domain_receive_assets_onboarding_description">Das Senden von Vermögenswerten in anderen Netzwerken führt zu dauerhaftem Verlust.</string>
|
||||
|
|
@ -541,6 +546,7 @@
|
|||
<string name="feedback_preface_scan_failed">Bitte sag uns, welche Karte oder Ring du hast</string>
|
||||
<string name="feedback_preface_support">Hallo Support-Team,</string>
|
||||
<string name="feedback_preface_tx_failed">Bitte erzähle uns mehr über dein Problem. Jedes kleine Detail kann helfen.</string>
|
||||
<string name="feedback_subject_backup_problem">Problem mit der Sicherung</string>
|
||||
<string name="feedback_subject_pre_activated_wallet">Zuvor aktivierte Wallet</string>
|
||||
<string name="feedback_subject_rate_negative">Meine Vorschläge</string>
|
||||
<string name="feedback_subject_scan_failed">Kann eine Karte oder Ring nicht scannen</string>
|
||||
|
|
@ -593,10 +599,13 @@
|
|||
<string name="hw_backup_hardware_upgrade_title">Aktualisiere Deine aktuelle Wallet</string>
|
||||
<string name="hw_backup_need_action">Gehe zum Backup</string>
|
||||
<string name="hw_backup_need_description">Bitte sicher Deine Wallet, bevor Du einen Zugangscode erstellst.</string>
|
||||
<string name="hw_backup_need_finish_first">Sicherung zuerst beenden</string>
|
||||
<string name="hw_backup_need_title">Zuerst die Sicherung abschließen</string>
|
||||
<string name="hw_backup_no_backup">Unvollständig</string>
|
||||
<string name="hw_backup_section_other_title">Andere Methoden</string>
|
||||
<string name="hw_backup_seed_description">Speicher Deinen Wiederherstellungssatz an einem sicheren Ort und halte diesen stets geheim, um Dein Geld zu schützen.</string>
|
||||
<string name="hw_backup_seed_title">Wiederherstellungs-Phrase</string>
|
||||
<string name="hw_backup_to_secure_description">Um Deine Wallet mit einem Zugangscode zu sichern, schließe den Sicherungsvorgang ab.</string>
|
||||
<string name="hw_backup_to_upgrade_description">Um Deine Wallet auf Hardware umzustellen, erstelle vorher ein Backup.</string>
|
||||
<string name="hw_create_keys_description">Deine privaten Schlüssel sind sicher verschlüsselt und auf Deinem Telefon gespeichert.</string>
|
||||
<string name="hw_create_keys_title">Schlüssel werden in der App gespeichert</string>
|
||||
|
|
@ -617,8 +626,9 @@
|
|||
<string name="hw_remove_wallet_notification_description_has_backup">Für diese Wallet existiert ein Backup. Überprüfe dieses bitte, bevor Du sie entfernst, um sicherzustellen, dass Du sie später wiederherstellen kannst.</string>
|
||||
<string name="hw_remove_wallet_notification_description_without_backup">Wenn Du diese Wallet ohne Backup entfernst, verlierst Du dauerhaft den Zugriff auf Deine Assets.</string>
|
||||
<string name="hw_remove_wallet_notification_title">Diese Wallet dauerhaft entfernen?</string>
|
||||
<string name="hw_remove_wallet_warning_access">Mir ist bewusst, dass ich den Zugriff auf meine Wallet verliere kann, wenn ich sie vor der Entfernung nicht gesichert habe.</string>
|
||||
<string name="hw_remove_wallet_warning_access">Mir ist bewusst, dass ich den Zugriff auf meine Wallet verlieren kann, wenn ich sie vor der Entfernung nicht gesichert habe.</string>
|
||||
<string name="hw_remove_wallet_warning_device">Mir ist bewusst, dass durch das Entfernen meiner Wallet diese nicht gelöscht, sondern lediglich von meinem Gerät entfernt wird.</string>
|
||||
<string name="hw_upgrade">Upgrade</string>
|
||||
<string name="hw_upgrade_backup_description">Es wird keine Seed-Phrase mehr benötigt – Deine Tangem-Karte oder Dein Tangem-Ring wird zu Deinem sicheren Backup.</string>
|
||||
<string name="hw_upgrade_backup_title">Backup mit Tangem</string>
|
||||
<string name="hw_upgrade_error_card_already_has_wallet">Ein Upgrade ist nicht möglich. Auf diesem Gerät ist bereits eine Wallet vorhanden.</string>
|
||||
|
|
@ -719,6 +729,7 @@
|
|||
<string name="markets_sort_by_top_gainers_title">Top-Gewinner</string>
|
||||
<string name="markets_sort_by_top_losers_title">Top-Verlierer</string>
|
||||
<string name="markets_sort_by_trending_title">Beliebt</string>
|
||||
<string name="markets_sort_by_yield_mode_title">Ertragsmodus</string>
|
||||
<string name="markets_staking_banner_description_placeholder">Staking ist der einfachste Weg, um Belohnungen für Deine Kryptowährung zu erhalten. %s</string>
|
||||
<string name="markets_staking_banner_title">Verdiene bis zu %s APY</string>
|
||||
<string name="markets_token_added">Token hinzugefügt</string>
|
||||
|
|
@ -793,6 +804,19 @@
|
|||
<string name="mobile_wallet_requires_min_os_warning_body">Du musst auf die folgende Version aktualisieren: %1$s um eine mobile Wallet zu erstellen</string>
|
||||
<string name="mobile_wallet_requires_min_os_warning_title">Mobile Wallet erfordert %1$s oder später</string>
|
||||
<string name="news_all_news">Alle Neuigkeiten</string>
|
||||
<string name="news_like">Gefällt mir</string>
|
||||
<plurals name="news_published_hours_ago">
|
||||
<item quantity="one">%dStunde her</item>
|
||||
<item quantity="other">%dStunden her</item>
|
||||
</plurals>
|
||||
<plurals name="news_published_minutes_ago">
|
||||
<item quantity="one">%dMinute her</item>
|
||||
<item quantity="other">%dMinuten her</item>
|
||||
</plurals>
|
||||
<string name="news_quick_recap">Kurze Zusammenfassung</string>
|
||||
<string name="news_related_news">Verwandte Nachrichten</string>
|
||||
<string name="news_related_tokens">Verwandte Token</string>
|
||||
<string name="news_sources">Quellen</string>
|
||||
<string name="news_stay_in_the_loop">Auf dem Laufenden bleiben</string>
|
||||
<string name="nfc_error_unavailable">NFC ist auf deinem Gerät nicht verfügbar</string>
|
||||
<string name="nft_about_title">Über NFT</string>
|
||||
|
|
@ -968,6 +992,7 @@
|
|||
<string name="onramp_currency_other">Andere Währungen</string>
|
||||
<string name="onramp_currency_popular">Beliebte Fiats</string>
|
||||
<string name="onramp_currency_search">Suche nach Währung</string>
|
||||
<string name="onramp_error_transaction_already_processed">Diese Transaktion wurde bereits verarbeitet. Es sind keine weiteren Maßnahmen erforderlich.</string>
|
||||
<string name="onramp_fetching_best_rates">Die besten Preise erzielen...</string>
|
||||
<string name="onramp_instant_status">Sofort</string>
|
||||
<string name="onramp_legal">Durch die Nutzung der Onramp-Funktionalität stimmst Du den %1$s und %2$s des Anbieters zu.</string>
|
||||
|
|
@ -1064,6 +1089,7 @@
|
|||
<string name="reset_card_to_factory_button_title">Karte oder Ring zurücksetzen</string>
|
||||
<string name="reset_card_to_factory_condition_1">Mir ist bewusst, dass ich nach der Durchführung dieser Aktion keinen Zugriff mehr auf die aktuelle Wallet habe.</string>
|
||||
<string name="reset_card_to_factory_condition_2">Mir ist klar, dass ich diese Karte oder Ring nicht verwenden kann, um meinen Zugangscode auf den anderen Karten oder Ringe der aktuellen Wallet wiederherzustellen</string>
|
||||
<string name="reset_card_to_factory_condition_3">Mir ist bewusst, dass ich den Zugang zu meiner Tangem Pay Karte und allen darauf befindlichen Geldern vollständig verliere, ohne die Möglichkeit der Wiederherstellung</string>
|
||||
<string name="reset_card_with_backup_to_factory_message">Durch das Zurücksetzen auf Werkseinstellungen wird die Wallet vollständig von der ausgewählten Karte oder Ring gelöscht. Du kannst die aktuelle Wallet nicht wiederherstellen oder die Karte oder Ring verwenden, um den Zugangscode wiederherzustellen.</string>
|
||||
<string name="reset_card_without_backup_to_factory_message">Beim Zurücksetzen auf die Werkseinstellungen wird die Wallet der ausgewählten Karte oder Ring vollständig gelöscht und aus der App entfernt. Es ist nicht möglich, die aktuelle Wallet wiederherzustellen.</string>
|
||||
<string name="reset_cards_dialog_complete_description">Alle Tangem-Geräte wurden zurückgesetzt.</string>
|
||||
|
|
@ -1217,6 +1243,8 @@
|
|||
<string name="staking_account_initialization_footer">Eine Netzwerkgebühr ist eine kleine Zahlung, die erforderlich ist, um Deine Transaktion auf der Blockchain zu verarbeiten und zu bestätigen.</string>
|
||||
<string name="staking_account_initialization_message">Um mit dem Staking zu beginnen, muss Dein TON-Konto mit einer Transaktion von 1 TON aktiviert werden. Das Guthaben verbleibt auf Deinem Konto, dieser Schritt dient lediglichder aktivierung für das Staking.</string>
|
||||
<string name="staking_account_initialization_title">Kontoaktivierung</string>
|
||||
<string name="staking_alert_network_fee_updated_message">Die Netzwerkgebühr hat sich geändert. Bitte überprüfe den neuen Betrag, bevor Du fortfährst.</string>
|
||||
<string name="staking_alert_network_fee_updated_title">Netzwerkgebühr aktualisiert</string>
|
||||
<string name="staking_amount_requirement_error">Die Anzahl der zu stakenden Krypros muss mindesten %s betragen</string>
|
||||
<string name="staking_amount_tron_integer_error">Der Stakingbetrag wird aufgrund der Netzwerkregeln auf %1$s TRX aufgerundet.</string>
|
||||
<string name="staking_amount_tron_integer_error_unstaking">Der Betrag der unstaked wird, wird aufgrund der Netzwerkregeln auf %1$s TRX gerundet.</string>
|
||||
|
|
@ -1255,6 +1283,7 @@
|
|||
<string name="staking_give_permission_fee_footer">Das Netzwerk erhebt eine Token-Genehmigungsgebühr, um zu überprüfen, ob Du die Verwendung Deines Tokens für das Staking genehmigst.</string>
|
||||
<string name="staking_legal">Indem Du die Staking-Funktionalität nutzt, stimmst Du den %1$s und %2$s des Anbieters zu.</string>
|
||||
<string name="staking_locked">Gesperrt</string>
|
||||
<string name="staking_max_amount_requirement_error">Höchstbetrag: %s</string>
|
||||
<string name="staking_migrate">Migrieren</string>
|
||||
<string name="staking_native">Natives Staking</string>
|
||||
<string name="staking_no_validators_error_message">Derzeit sind keine aktiven Validatoren für das Staking verfügbar. Bitte versuchen Sie es später erneut.</string>
|
||||
|
|
@ -1407,6 +1436,7 @@
|
|||
<string name="tangem_pay_freeze_card_success">Ihre Karte ist eingefroren.</string>
|
||||
<string name="tangem_pay_get_help">Hilfe erhalten</string>
|
||||
<string name="tangem_pay_other">Andere</string>
|
||||
<string name="tangem_pay_rooted_device_subtitle">Nicht nutzbar auf gerooteten Geräten</string>
|
||||
<string name="tangem_pay_status_completed">Abgeschlossen</string>
|
||||
<string name="tangem_pay_status_declined">Abgelehnt</string>
|
||||
<string name="tangem_pay_status_pending">Ausstehend</string>
|
||||
|
|
@ -1419,6 +1449,8 @@
|
|||
<string name="tangem_pay_unfreeze_card_failed">Entsperren der Karte fehlgeschlagen. Versuchen Sie es später erneut.</string>
|
||||
<string name="tangem_pay_unfreeze_card_success">Ihre Karte ist entsperrt.</string>
|
||||
<string name="tangem_pay_withdrawal">Abhebung</string>
|
||||
<string name="tangempay_account_unable_to_use_rooted">Auf gerooteten Geräten nicht nutzbar.</string>
|
||||
<string name="tangempay_cancel_kyc">KYC abbrechen</string>
|
||||
<string name="tangempay_card_details_add_funds">Guthaben hinzufügen</string>
|
||||
<string name="tangempay_card_details_add_funds_subtitle">Aufladeoptionen</string>
|
||||
<string name="tangempay_card_details_card_number">Kartennummer</string>
|
||||
|
|
@ -1446,6 +1478,7 @@
|
|||
<string name="tangempay_card_details_open_wallet_step_5">Alles erledigt! Deine Karte ist einsatzbereit.</string>
|
||||
<string name="tangempay_card_details_open_wallet_title">Karte zu Google Pay hinzufügen</string>
|
||||
<string name="tangempay_card_details_open_wallet_title_apple">Karte zu Apple Pay hinzufügen</string>
|
||||
<string name="tangempay_card_details_pin_code">Pin Code</string>
|
||||
<string name="tangempay_card_details_receive_description">Teile Deine Adresse mit oder zeig den QR-Code.</string>
|
||||
<string name="tangempay_card_details_receive_error_description">Es wurden technische Probleme festgestellt. Bitte versuche es später erneut oder kontaktiere den Support.</string>
|
||||
<string name="tangempay_card_details_receive_error_title">Empfangen ist jetzt nicht verfügbar</string>
|
||||
|
|
@ -1454,12 +1487,15 @@
|
|||
<string name="tangempay_card_details_swap_description">Tausche beliebige Vermögenswerte in Deinem Portfolio gegen eine Karte.</string>
|
||||
<string name="tangempay_card_details_title">Kartendetails</string>
|
||||
<string name="tangempay_card_details_unfreeze_card">Karte entsperren</string>
|
||||
<string name="tangempay_card_details_view_pin_code_description">Komm zurück zur App, falls du es vergisst.</string>
|
||||
<string name="tangempay_card_details_view_pin_code_title">Dein PIN-Code</string>
|
||||
<string name="tangempay_card_details_withdraw">Auszahlung</string>
|
||||
<string name="tangempay_card_details_withdraw_error_title">Auszahlung derzeit nicht möglich</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_description">Sie können keinen Tausch oder eine neue Auszahlung starten, bis die aktuelle abgeschlossen ist.</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_title">Auszahlung läuft</string>
|
||||
<string name="tangempay_change_pin_code">PIN-Code ändern</string>
|
||||
<string name="tangempay_come_back_if_forget_pin">Kehren Sie zur App zurück, falls Sie ihn vergessen.</string>
|
||||
<string name="tangempay_factory_settings_warning_title">Mir ist bewusst, dass ich den Zugriff auf meine Tangem Pay Card und alle darauf befindlichen Guthaben vollständig und ohne Möglichkeit der Wiederherstellung verliere.</string>
|
||||
<string name="tangempay_failed_to_issue_card">Kartenausstellung fehlgeschlagen</string>
|
||||
<string name="tangempay_failed_to_issue_card_retry_description">Ein technischer Fehler ist aufgetreten, bitte versuchen Sie es erneut, indem Sie auf die Schaltfläche unten klicken</string>
|
||||
<string name="tangempay_failed_to_issue_card_support_description">Ein technischer Fehler ist aufgetreten, bitte kontaktieren Sie den Support</string>
|
||||
|
|
@ -1471,11 +1507,14 @@
|
|||
<string name="tangempay_issuing_your_card">Ausstellung Deiner Karte</string>
|
||||
<string name="tangempay_issuing_your_card_description">Wir bereiten Ihre Karte vor. Dies kann etwas dauern.</string>
|
||||
<string name="tangempay_kyc_card_ready_notification_title">Tangem Pay</string>
|
||||
<string name="tangempay_kyc_confirm_cancellation_alert_title">Konvertierung bestätigen</string>
|
||||
<string name="tangempay_kyc_confirm_cancellation_description">Möchtest Du den KYC wirklich abbrechen? Du kannst später jederzeit weiter machen.</string>
|
||||
<string name="tangempay_kyc_failed_description">Wir konnten Ihr Profil nicht verifizieren. Bei Fragen wenden Sie sich bitte an den Support.</string>
|
||||
<string name="tangempay_kyc_failed_title">Leider konnten wir Ihre Identität nicht verifizieren</string>
|
||||
<string name="tangempay_kyc_in_progress">KYC in Bearbeitung</string>
|
||||
<string name="tangempay_kyc_in_progress_notification_button">Status anzeigen</string>
|
||||
<string name="tangempay_kyc_in_progress_notification_title">KYC für Tangem Pay in Arbeit</string>
|
||||
<string name="tangempay_kyc_in_progress_popup_description">Über die Schaltflächen unten kannst Du Deinen aktuellen KYC-Status einsehen oder ihn abbrechen.</string>
|
||||
<string name="tangempay_onboarding_banner_description">Holen Sie sich Ihre kostenlose virtuelle Tangem Visa-Karte</string>
|
||||
<string name="tangempay_onboarding_banner_title">Nutzen Sie USDC für alltägliche Zahlungen</string>
|
||||
<string name="tangempay_onboarding_get_card_button_text">Karte erhalten</string>
|
||||
|
|
@ -1487,15 +1526,18 @@
|
|||
<string name="tangempay_onboarding_security_title">Unerreichte Privatsphäre</string>
|
||||
<string name="tangempay_onboarding_title">Erhalten Sie Ihre kostenlose Tangem Pay Card in wenigen Minuten</string>
|
||||
<string name="tangempay_payment_account">Zahlungskonto</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Synchronisierung des Zahlungskontos erforderlich</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Zahlungskonto ist nicht synchronisiert</string>
|
||||
<string name="tangempay_pin_validation_error_message">Ungültige PIN: Sequenzen oder Wiederholungen vermeiden</string>
|
||||
<string name="tangempay_service_unavailable_description">Wir beheben ein technisches Problem. Bitte versuchen Sie es später erneut.</string>
|
||||
<string name="tangempay_service_unavailable_title">Service vorübergehend nicht verfügbar</string>
|
||||
<string name="tangempay_service_unreachable_try_later">Daten können derzeit nicht angezeigt werden, Kartenzahlungen funktionieren jedoch weiterhin.</string>
|
||||
<string name="tangempay_sync_needed">Synchronisation erforderlich</string>
|
||||
<string name="tangempay_set_pin_code">Satz \nPIN-Code</string>
|
||||
<string name="tangempay_sync_needed">Nicht synchronisiert</string>
|
||||
<string name="tangempay_sync_needed_restore_access">Zugang wiederherstellen</string>
|
||||
<string name="tangempay_tangem_visa_card">Nutzen Sie USDC für alltägliche Zahlungen</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Pay ist vorübergehend nicht verfügbar</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Pay ist vorübergehend nicht erreichbar.</string>
|
||||
<string name="tangempay_title">Tangem Pay</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Verwenden Sie Ihre Karte oder Ihren Ring, um den Zugriff auf Ihr Zahlungskonto wiederherzustellen</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Klicken Sie auf die Schaltfläche unten, um den Zugriff wiederherzustellen</string>
|
||||
<string name="tangempay_your_pin_code">Ihr PIN-Code</string>
|
||||
<string name="this_is_my_wallet_title">Das ist meine Wallet</string>
|
||||
<string name="toast_balances_hidden">Guthaben versteckt</string>
|
||||
|
|
@ -1756,6 +1798,8 @@
|
|||
<string name="warning_button_ok">OK, habe ich verstanden!</string>
|
||||
<string name="warning_button_really_cool">Echt toll!</string>
|
||||
<string name="warning_button_refresh">Aktualisieren</string>
|
||||
<string name="warning_clore_migration_message">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.</string>
|
||||
<string name="warning_clore_migration_title">Migration des Clore-Netzwerks</string>
|
||||
<string name="warning_demo_mode_message">Du befindest sich derzeit im Demo-Modus</string>
|
||||
<string name="warning_demo_mode_title">Demo-Modus aktiv</string>
|
||||
<string name="warning_developer_card_message">Die Karte, die du gescannt hast, ist eine Entwicklerkarte. Verwenden diese nicht zur Erstellung Ihrer Wallet.</string>
|
||||
|
|
@ -1958,7 +2002,7 @@
|
|||
<string name="xtz_withdrawal_message_warning">Damit Sie beim nächsten Aufladen Ihrer Brieftasche keine erhöhte Provision zahlen, soll der Betrag um %s XTZ reduziert werden</string>
|
||||
<string name="yield_module_alert_description">Wenn der Yield-Modus aktiviert ist, gehen alle zukünftigen Einzahlungen an diese Adresse an Aave. Du kannst über Dein Guthaben weiterhin frei verfügen.</string>
|
||||
<string name="yield_module_alert_title">Deine %s wird an Aave übermittelt</string>
|
||||
<string name="yield_module_amount_not_transfered_to_aave_title">Die Lieferung von %1$s %2$s an Aave steht noch aus.</string>
|
||||
<string name="yield_module_amount_not_transfered_to_aave_title">Lieferung %1$s %2$s nach Aave</string>
|
||||
<string name="yield_module_approve_needed_notification_cta">Genehmigen</string>
|
||||
<string name="yield_module_approve_needed_notification_description">Die Genehmigung Deines Tokens wurde widerrufen. Erteilen diese erneut, um die Servicefunktionalität fortzusetzen.</string>
|
||||
<string name="yield_module_approve_needed_notification_title">Genehmigung erforderlich</string>
|
||||
|
|
@ -2039,6 +2083,7 @@
|
|||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Ertragsmodus</string>
|
||||
<string name="yield_module_token_details_earn_notification_processing">Bearbeitung Deiner Einzahlung</string>
|
||||
<string name="yield_module_token_details_earn_notification_title">Ertragsmodus</string>
|
||||
<string name="yield_module_transaction_deploy_contract">Yield-Mode-Vertragsbereitstellung</string>
|
||||
<string name="yield_module_transaction_enter">Ertragsmodus aktivieren</string>
|
||||
<string name="yield_module_transaction_enter_subtitle">%1$s geliefert an Aave</string>
|
||||
<string name="yield_module_transaction_exit">Ertragsmodus deaktiviert</string>
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@
|
|||
<string name="auth_info_subtitle">Seleccione una billetera para iniciar sesión</string>
|
||||
<string name="auth_info_title">¡Bienvenido de nuevo!</string>
|
||||
<string name="backup_complete_description">Realizó una copia de seguridad de su billetera correctamente.</string>
|
||||
<string name="backup_complete_seed_description">Estas palabras son irrecuperables si se pierden. Guárdelas en un lugar seguro.</string>
|
||||
<string name="backup_complete_title">Copia de seguridad completada</string>
|
||||
<string name="backup_info_description">Su frase secreta de recuperación es un conjunto fijo de %s palabras aleatorias que se utilizan para acceder a su billetera y recuperarla.</string>
|
||||
<string name="backup_info_keep_description">Estas palabras no pueden recuperarse si se pierden. Asegúrese de guardarlas en un lugar seguro.</string>
|
||||
|
|
@ -87,6 +88,7 @@
|
|||
<string name="backup_info_save_description">Guarde estas %s palabras en un lugar seguro, como un administrador de contraseñas, y nunca las comparta con nadie.</string>
|
||||
<string name="backup_info_save_title">No se puede restaurar</string>
|
||||
<string name="backup_info_title">Frase de recuperación</string>
|
||||
<string name="backup_seed_caution">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.</string>
|
||||
<string name="backup_seed_description">Escriba estas %s palabras en orden y guárdelas en un lugar privado y seguro</string>
|
||||
<string name="backup_seed_responsibility">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.</string>
|
||||
<string name="backup_seed_title">Frase de recuperación</string>
|
||||
|
|
@ -399,7 +401,7 @@
|
|||
<string name="disclaimer_error_loading">Compruebe su conexión a internet o cambia a una red diferente</string>
|
||||
<string name="disclaimer_title">Condiciones de uso</string>
|
||||
<string name="domain_receive_assets_default_address">Dirección por defecto</string>
|
||||
<string name="domain_receive_assets_legacy_address">Dirección Legacy</string>
|
||||
<string name="domain_receive_assets_legacy_address">Dirección %s Legacy</string>
|
||||
<string name="domain_receive_assets_navigation_title">Recibir activos</string>
|
||||
<string name="domain_receive_assets_network_name_address">%s dirección</string>
|
||||
<string name="domain_receive_assets_onboarding_description">Enviar activos a otras redes resultará en una pérdida permanente.</string>
|
||||
|
|
@ -489,6 +491,7 @@
|
|||
<string name="feedback_preface_scan_failed">Por favor, díganos qué tarjeta o anillo tiene</string>
|
||||
<string name="feedback_preface_support">Hola equipo de soporte,</string>
|
||||
<string name="feedback_preface_tx_failed">Por favor, cuéntenos más sobre tu problema. Cada pequeño detalle puede ayudar.</string>
|
||||
<string name="feedback_subject_backup_problem">Problema con la copia de seguridad</string>
|
||||
<string name="feedback_subject_pre_activated_wallet">Billetera previamente activada</string>
|
||||
<string name="feedback_subject_rate_negative">Mis recomendaciones</string>
|
||||
<string name="feedback_subject_scan_failed">No se puede escanear una tarjeta/anillo</string>
|
||||
|
|
@ -507,6 +510,13 @@
|
|||
<string name="give_permission_swap_subtitle" formatted="false">Para continuar, conceda a los contratos inteligentes de %1s permiso para utilizar su %2s</string>
|
||||
<string name="give_permission_title">Dar autorización</string>
|
||||
<string name="give_permission_unlimited">Ilimitado</string>
|
||||
<string name="hardware_wallet_backup_feature_description">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.</string>
|
||||
<string name="hardware_wallet_backup_feature_title">Copia de seguridad con varias tarjetas</string>
|
||||
<string name="hardware_wallet_create_title">Agregar billetera Tangem</string>
|
||||
<string name="hardware_wallet_key_feature_description">Su clave privada se genera directamente dentro de la tarjeta Tangem y nunca sale de ella.</string>
|
||||
<string name="hardware_wallet_key_feature_title">Generación de claves</string>
|
||||
<string name="hardware_wallet_security_feature_description">Todas las operaciones criptográficas ocurren dentro del chip seguro, certificado contra la clonación y la manipulación física.</string>
|
||||
<string name="hardware_wallet_security_feature_title">Seguridad a nivel de hardware</string>
|
||||
<string name="home_button_add_existing_wallet">Agregar Billetera Existente</string>
|
||||
<string name="home_button_create_new_wallet">Crear Nueva Billetera</string>
|
||||
<string name="home_button_order">Pedir Tangem</string>
|
||||
|
|
@ -515,7 +525,73 @@
|
|||
<string name="hot_crypto_add_token_subtitle">a %s</string>
|
||||
<string name="hot_crypto_token_network">En la red %s</string>
|
||||
<string name="hw_access_code_create_alert_title">¿Está seguro de que desea salir del proceso de creación de código de acceso?</string>
|
||||
<string name="hw_activation_need_backup">Hacer copia ahora</string>
|
||||
<string name="hw_activation_need_description">Para completar la configuración, haga una copia de seguridad de su billetera y proteja la aplicación con un código de acceso.</string>
|
||||
<string name="hw_activation_need_finish">Finalizar ahora</string>
|
||||
<string name="hw_activation_need_title">Finalizar la configuración de la billetera</string>
|
||||
<string name="hw_activation_need_warning_description">Complete la configuración protegiendo la aplicación con un código de acceso.</string>
|
||||
<string name="hw_backup_alert_description">Si sale, tendrá que empezar de nuevo.</string>
|
||||
<string name="hw_backup_alert_title">¿Está seguro de que desea salir del proceso de configuración?</string>
|
||||
<string name="hw_backup_banner_description">Mantiene sus criptomonedas seguras y sin conexión. Tan delgadas como una tarjeta de crédito, más seguras que una bóveda bancaria.</string>
|
||||
<string name="hw_backup_close_description">Si lo hace, tendrá que empezar de nuevo.</string>
|
||||
<string name="hw_backup_google_drive_description">Recuperar la billetera existente a través de una copia de seguridad de Google Drive</string>
|
||||
<string name="hw_backup_google_drive_title">Copia de seguridad de Google Drive</string>
|
||||
<string name="hw_backup_hardware_create_description">Cree una billetera segura y transfiera sus fondos para mayor protección.</string>
|
||||
<string name="hw_backup_hardware_create_title">Crear nueva billetera</string>
|
||||
<string name="hw_backup_hardware_description">Mejore su seguridad con la billetera de hardware superior Tangem.</string>
|
||||
<string name="hw_backup_hardware_title">Billetera de hardware</string>
|
||||
<string name="hw_backup_hardware_upgrade_description">Mueva su billetera actual a Tangem.</string>
|
||||
<string name="hw_backup_hardware_upgrade_title">Actualizar la billetera actual</string>
|
||||
<string name="hw_backup_need_action">Ir a copia de seguridad</string>
|
||||
<string name="hw_backup_need_description">Por favor, haga una copia de seguridad de su billetera antes de crear un código de acceso.</string>
|
||||
<string name="hw_backup_need_finish_first">Finalice la copia de seguridad primero</string>
|
||||
<string name="hw_backup_need_title">Finalizar la copia de seguridad primero</string>
|
||||
<string name="hw_backup_no_backup">Incompleto</string>
|
||||
<string name="hw_backup_section_other_title">Otros métodos</string>
|
||||
<string name="hw_backup_seed_description">Guarde su frase de recuperación en un lugar seguro y manténgala en privado para proteger sus fondos.</string>
|
||||
<string name="hw_backup_seed_title">Frase de recuperación</string>
|
||||
<string name="hw_backup_to_secure_description">Para proteger su billetera con un código de acceso, complete el proceso de copia de seguridad.</string>
|
||||
<string name="hw_backup_to_upgrade_description">Para actualizar a una billetera de hardware, complete el proceso de copia de seguridad.</string>
|
||||
<string name="hw_create_keys_description">Sus claves privadas están encriptadas de forma segura y almacenadas en su teléfono</string>
|
||||
<string name="hw_create_keys_title">Las claves privadas permanecen en su dispositivo</string>
|
||||
<string name="hw_create_seed_description">Cree o restaure su billetera con una frase de recuperación.</string>
|
||||
<string name="hw_create_seed_title">Copia de seguridad de la frase semilla</string>
|
||||
<string name="hw_create_title">Crear una billetera móvil</string>
|
||||
<string name="hw_import_existing_wallet">Importar billetera existente</string>
|
||||
<string name="hw_import_seed_phrase_already_imported">Esta frase de recuperación ya ha sido importada</string>
|
||||
<string name="hw_mobile_wallet">Billetera móvil</string>
|
||||
<string name="hw_remove_wallet_action_forget_title">Olvidar billetera</string>
|
||||
<string name="hw_remove_wallet_attention_description">Esta billetera se eliminará permanentemente de su dispositivo.</string>
|
||||
<string name="hw_remove_wallet_confirmation_title">¿Está seguro que desea hacer esto?</string>
|
||||
<string name="hw_remove_wallet_nav_title">Olvidar billetera</string>
|
||||
<string name="hw_remove_wallet_notification_action_backup_go">Ir a copia de seguridad</string>
|
||||
<string name="hw_remove_wallet_notification_action_backup_view">Ver copia de seguridad</string>
|
||||
<string name="hw_remove_wallet_notification_action_forget">Olvidar la billetera</string>
|
||||
<string name="hw_remove_wallet_notification_action_forget_anyway">Olvidar de todos modos</string>
|
||||
<string name="hw_remove_wallet_notification_description_has_backup">Esta billetera tiene una copia de seguridad. Asegúrese de poder recuperarla antes de olvidarla.</string>
|
||||
<string name="hw_remove_wallet_notification_description_without_backup">Si olvida esta billetera sin una copia de seguridad, perderá permanentemente el acceso a sus fondos.</string>
|
||||
<string name="hw_remove_wallet_notification_title">¿Estás seguro de que desea olvidar esta billetera?</string>
|
||||
<string name="hw_remove_wallet_warning_access">Entiendo que si no he hecho una copia de seguridad de mi billetera antes de eliminarla, perderé el acceso a ella.</string>
|
||||
<string name="hw_remove_wallet_warning_device">Entiendo que quitar mi billetera no la borra, solo la elimina de mi dispositivo.</string>
|
||||
<string name="hw_upgrade">Actualizar</string>
|
||||
<string name="hw_upgrade_backup_description">No se requiere frase semilla. Su tarjeta o anillo Tangem se convierte en su copia de seguridad.</string>
|
||||
<string name="hw_upgrade_backup_title">Copia de seguridad con Tangem</string>
|
||||
<string name="hw_upgrade_error_card_already_has_wallet">No se puede actualizar. Ya existe una billetera en este dispositivo.</string>
|
||||
<string name="hw_upgrade_error_card_key_import">Elija otro dispositivo. Este no se puede usar para la actualización.</string>
|
||||
<string name="hw_upgrade_error_wallet2_card_required">Se produjo un error durante la operación.</string>
|
||||
<string name="hw_upgrade_funds_access_description">Sus fondos permanecen seguros y totalmente accesibles durante el proceso</string>
|
||||
<string name="hw_upgrade_funds_access_title">Acceso a los fondos</string>
|
||||
<string name="hw_upgrade_general_security_description">Los datos de su billetera se borrarán de la aplicación y se almacenarán en su billetera de hardware.</string>
|
||||
<string name="hw_upgrade_general_security_title">Seguridad general</string>
|
||||
<string name="hw_upgrade_key_migration_description">Las claves privadas se transferirán de la aplicación a su billetera de hardware Tangem</string>
|
||||
<string name="hw_upgrade_key_migration_title">Migración de claves</string>
|
||||
<string name="hw_upgrade_scan_device">Escanear dispositivo</string>
|
||||
<string name="hw_upgrade_start_action">Iniciar actualización</string>
|
||||
<string name="hw_upgrade_start_description">Estás a punto de actualizarte a nuestra billetera de hardware. Mantendrá sus activos seguros en almacenamiento en frío.</string>
|
||||
<string name="hw_upgrade_start_title">Tangem Wallet</string>
|
||||
<string name="hw_upgrade_title">Actualice a nuestra billetera de hardware</string>
|
||||
<string name="hw_upgrade_to_cold_banner_description">Mantenga sus criptomonedas seguras con la billetera de hardware de primer nivel de Tangem.</string>
|
||||
<string name="hw_upgrade_to_cold_banner_title">Actualice su billetera a la seguridad del hardware</string>
|
||||
<string name="information_generated_with_ai">Esta información fue generada con IA.\nPulse aquí si encuentra algún error.</string>
|
||||
<string name="initial_message_change_access_code_body">Para cambiar el código de acceso coloque la tarjeta o el anillo como se muestra arriba y no lo retire hasta el fin de la operación</string>
|
||||
<string name="initial_message_change_passcode_body">Toque para cambiar la contraseña</string>
|
||||
|
|
@ -1323,7 +1399,8 @@
|
|||
<string name="tangempay_onboarding_security_title">Privacidad inigualable</string>
|
||||
<string name="tangempay_onboarding_title">Obtén tu tarjeta Tangem Pay gratuita en minutos</string>
|
||||
<string name="tangempay_payment_account">Cuenta de pago</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Sincronización de cuenta de pago necesaria</string>
|
||||
<string name="tangempay_payment_account_sync_needed">La cuenta de pago no está sincronizada</string>
|
||||
<string name="tangempay_pin_validation_error_message">PIN no válido: evitar secuencias o repeticiones</string>
|
||||
<string name="tangempay_service_unavailable_description">Estamos solucionando un problema técnico. Por favor, inténtelo de nuevo más tarde.</string>
|
||||
<string name="tangempay_service_unavailable_title">Servicio temporalmente no disponible</string>
|
||||
<string name="tangempay_service_unreachable_try_later">No es posible mostrar los datos en este momento, pero los pagos con tarjeta siguen funcionando.</string>
|
||||
|
|
@ -1331,7 +1408,7 @@
|
|||
<string name="tangempay_tangem_visa_card">Usa USDC para pagos cotidianos</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Pay temporalmente no disponible</string>
|
||||
<string name="tangempay_title">Tangem Pay</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Usa tu tarjeta o anillo para restaurar el acceso a tu cuenta de pago</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Haga clic en el botón de abajo para restaurar el acceso</string>
|
||||
<string name="tangempay_your_pin_code">Tu código PIN</string>
|
||||
<string name="this_is_my_wallet_title">Esta es mi billetera</string>
|
||||
<string name="toast_balances_hidden">Saldos ocultos</string>
|
||||
|
|
@ -1412,6 +1489,7 @@
|
|||
<string name="user_push_notification_banner_subtitle">Active las notificaciones push y le avisaremos al instante cuando le lleguen fondos.</string>
|
||||
<string name="user_push_notification_banner_title">No se pierda ninguna transacción</string>
|
||||
<string name="user_wallet_list_add_button">Agregar una nueva billetera</string>
|
||||
<string name="user_wallet_list_delete_hw_prompt">Si olvida esta billetera sin una copia de seguridad, perderá permanentemente el acceso a sus fondos.</string>
|
||||
<string name="user_wallet_list_delete_prompt">¿Estás seguro de que deseas olvidar esta billetera?</string>
|
||||
<string name="user_wallet_list_error_unable_to_unlock">Ha ocurrido un error, por favor escanee su tarjeta o anillo para iniciar sesión</string>
|
||||
<string name="user_wallet_list_error_wallet_already_saved">Esta billetera ya se ha guardado, puede agregar otro</string>
|
||||
|
|
@ -1506,6 +1584,8 @@
|
|||
<string name="warning_button_ok">Entendido</string>
|
||||
<string name="warning_button_really_cool">¡Realmente genial!</string>
|
||||
<string name="warning_button_refresh">Actualizar</string>
|
||||
<string name="warning_clore_migration_message">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.</string>
|
||||
<string name="warning_clore_migration_title">Migración de la red Clore</string>
|
||||
<string name="warning_demo_mode_message">Actualmente estás en el modo Demo</string>
|
||||
<string name="warning_demo_mode_title">Modo demo activo</string>
|
||||
<string name="warning_developer_card_message">La tarjeta que ha escaneado es una tarjeta de desarrollador. No la use para crear su billetera.</string>
|
||||
|
|
|
|||
|
|
@ -72,7 +72,19 @@
|
|||
<string name="auth_info_add_wallet_title">Ajouter un wallet</string>
|
||||
<string name="auth_info_subtitle">Sélectionnez un wallet pour vous connecter</string>
|
||||
<string name="auth_info_title">Heureux de te revoir!</string>
|
||||
<string name="backup_complete_description">Vous avez sauvegardé votre portefeuille avec succès.</string>
|
||||
<string name="backup_complete_seed_description">Ces mots ne peuvent pas être récupérés en cas de perte. Assurez-vous de les conserver en lieu sûr.</string>
|
||||
<string name="backup_complete_title">Sauvegarde terminée</string>
|
||||
<string name="backup_info_description">Votre seed phrase est un ensemble fixe de %s mots aléatoires permettant d\'accéder à votre portefeuille et de le récupérer.</string>
|
||||
<string name="backup_info_keep_description">Ces mots ne peuvent être récupérés s\'ils sont perdus. Conservez-les précieusement.</string>
|
||||
<string name="backup_info_keep_title">Gardez-les en sécurité</string>
|
||||
<string name="backup_info_save_description">Conservez ces %s mots dans un endroit sûr et ne les communiquez à personne.</string>
|
||||
<string name="backup_info_save_title">Aucune récupération possible</string>
|
||||
<string name="backup_info_title">Seed phrase</string>
|
||||
<string name="backup_seed_caution">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.</string>
|
||||
<string name="backup_seed_description">Notez ces %s mots dans l\'ordre numérique et conservez-les en lieu sûr et confidentiel.</string>
|
||||
<string name="backup_seed_responsibility">Vous êtes entièrement responsable de la sécurité de votre portefeuille et de la sauvegarde de votre seed phrase.</string>
|
||||
<string name="backup_seed_title">Seed phrase</string>
|
||||
<string name="balance_hidden_description">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</string>
|
||||
<string name="balance_hidden_do_not_show_button">Ne plus afficher</string>
|
||||
<string name="balance_hidden_got_it_button">Compris</string>
|
||||
|
|
@ -382,7 +394,7 @@
|
|||
<string name="disclaimer_error_loading">Vérifiez votre connexion Internet ou passez à un réseau différent</string>
|
||||
<string name="disclaimer_title">Conditions d\'utilisation</string>
|
||||
<string name="domain_receive_assets_default_address">Adresse par défaut</string>
|
||||
<string name="domain_receive_assets_legacy_address">Legacy adresse</string>
|
||||
<string name="domain_receive_assets_legacy_address">Legacy %s adresse</string>
|
||||
<string name="domain_receive_assets_navigation_title">Recevoir des actifs</string>
|
||||
<string name="domain_receive_assets_network_name_address">%s adresse</string>
|
||||
<string name="domain_receive_assets_onboarding_description">L’envoi d’actifs sur d’autres réseaux entraînera une perte définitive.</string>
|
||||
|
|
@ -470,6 +482,7 @@
|
|||
<string name="feedback_preface_scan_failed">Veuillez nous dire quelle carte vous avez</string>
|
||||
<string name="feedback_preface_support">Chère équipe de support,</string>
|
||||
<string name="feedback_preface_tx_failed">Veuillez nous en dire plus sur votre problème. Chaque petit détail peut nous aider.</string>
|
||||
<string name="feedback_subject_backup_problem">Problème de sauvegarde</string>
|
||||
<string name="feedback_subject_pre_activated_wallet">Portefeuille précédemment activé</string>
|
||||
<string name="feedback_subject_rate_negative">Mes suggestions</string>
|
||||
<string name="feedback_subject_scan_failed">Impossible de scanner une carte</string>
|
||||
|
|
@ -488,6 +501,13 @@
|
|||
<string name="give_permission_swap_subtitle" formatted="false">Pour continuer, accordez aux smart contracts de %1s l\'autorisation d\'utiliser votre %2s</string>
|
||||
<string name="give_permission_title">Donner l\'autorisation</string>
|
||||
<string name="give_permission_unlimited">Illimité</string>
|
||||
<string name="hardware_wallet_backup_feature_description">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.</string>
|
||||
<string name="hardware_wallet_backup_feature_title">Sauvegarde avec plusieurs cartes</string>
|
||||
<string name="hardware_wallet_create_title">Ajouter le wallet Tangem</string>
|
||||
<string name="hardware_wallet_key_feature_description">Votre clé privée est générée directement dans la carte Tangem et ne la quitte jamais.</string>
|
||||
<string name="hardware_wallet_key_feature_title">Génération de clés</string>
|
||||
<string name="hardware_wallet_security_feature_description">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.</string>
|
||||
<string name="hardware_wallet_security_feature_title">Sécurité au niveau matériel</string>
|
||||
<string name="home_button_add_existing_wallet">Ajouter un Portefeuille existant</string>
|
||||
<string name="home_button_create_new_wallet">Créer un nouveau Portefeuille</string>
|
||||
<string name="home_button_order">Commandez</string>
|
||||
|
|
@ -496,6 +516,73 @@
|
|||
<string name="hot_crypto_add_token_subtitle">à %s</string>
|
||||
<string name="hot_crypto_token_network">Via %s</string>
|
||||
<string name="hw_access_code_create_alert_title">Êtes-vous sûr de vouloir annuler la configuration du code d\'accès ?</string>
|
||||
<string name="hw_activation_need_backup">Sauvegarder maintenant</string>
|
||||
<string name="hw_activation_need_description">Pour terminer la configuration, sauvegardez votre portefeuille et sécurisez l\'application à l\'aide d\'un code d\'accès.</string>
|
||||
<string name="hw_activation_need_finish">Finaliser maintenant</string>
|
||||
<string name="hw_activation_need_title">Finaliser la configuration du portefeuille</string>
|
||||
<string name="hw_activation_need_warning_description">Terminez la configuration en sécurisant l\'application à l\'aide d\'un code d\'accès.</string>
|
||||
<string name="hw_backup_alert_description">Si vous quittez, vous devrez recommencer depuis le début.</string>
|
||||
<string name="hw_backup_alert_title">Êtes-vous sûr de vouloir quitter le processus d\'installation ?</string>
|
||||
<string name="hw_backup_banner_description">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.</string>
|
||||
<string name="hw_backup_close_description">Si vous le faites, vous devrez recommencer depuis le début.</string>
|
||||
<string name="hw_backup_google_drive_description">Récupérer un portefeuille existant via la sauvegarde Google Drive</string>
|
||||
<string name="hw_backup_google_drive_title">Sauvegarde Google Drive</string>
|
||||
<string name="hw_backup_hardware_create_description">Créez un portefeuille sécurisé et transférez vos fonds pour bénéficier d\'une protection supplémentaire.</string>
|
||||
<string name="hw_backup_hardware_create_title">Créer un nouveau portefeuille</string>
|
||||
<string name="hw_backup_hardware_description">Renforcez votre sécurité grâce au Hardware wallet haut de gamme Tangem.</string>
|
||||
<string name="hw_backup_hardware_title">Hardware wallet</string>
|
||||
<string name="hw_backup_hardware_upgrade_description">Transférez votre portefeuille actuel vers Tangem.</string>
|
||||
<string name="hw_backup_hardware_upgrade_title">Améliorer le wallet actuel</string>
|
||||
<string name="hw_backup_need_action">Aller à la sauvegarde</string>
|
||||
<string name="hw_backup_need_description">Veuillez sauvegarder votre portefeuille avant de créer un code d\'accès.</string>
|
||||
<string name="hw_backup_need_finish_first">Terminez d\'abord la sauvegarde.</string>
|
||||
<string name="hw_backup_need_title">Finalisez d\'abord la sauvegarde.</string>
|
||||
<string name="hw_backup_no_backup">Incomplet</string>
|
||||
<string name="hw_backup_section_other_title">Autres méthodes</string>
|
||||
<string name="hw_backup_seed_description">Conservez votre seed phrase dans un endroit sûr et gardez-la confidentielle afin de protéger vos fonds.</string>
|
||||
<string name="hw_backup_seed_title">Seed phrase</string>
|
||||
<string name="hw_backup_to_secure_description">Pour sécuriser votre wallet avec un code d\'accès, effectuez la procédure de sauvegarde.</string>
|
||||
<string name="hw_backup_to_upgrade_description">Pour passer à un portefeuille matériel, terminez le processus de sauvegarde.</string>
|
||||
<string name="hw_create_keys_description">Vos clés privées sont cryptées et stockées en toute sécurité sur votre téléphone.</string>
|
||||
<string name="hw_create_keys_title">Les clés privées restent sur votre appareil</string>
|
||||
<string name="hw_create_seed_description">Créez ou restaurez votre portefeuille à l\'aide d\'une seed phrase.</string>
|
||||
<string name="hw_create_seed_title">Sauvegarde de la seed phrase</string>
|
||||
<string name="hw_create_title">Créer un wallet mobile</string>
|
||||
<string name="hw_import_existing_wallet">Importer un portefeuille existant</string>
|
||||
<string name="hw_import_seed_phrase_already_imported">Cette seed phrase a déjà été importée.</string>
|
||||
<string name="hw_mobile_wallet">Wallet mobile</string>
|
||||
<string name="hw_remove_wallet_action_forget_title">Oubliez votre portefeuille</string>
|
||||
<string name="hw_remove_wallet_attention_description">Ce portefeuille sera définitivement supprimé de votre appareil.</string>
|
||||
<string name="hw_remove_wallet_confirmation_title">Êtes-vous sûr de vouloir faire cela ?</string>
|
||||
<string name="hw_remove_wallet_nav_title">Oubliez votre portefeuille</string>
|
||||
<string name="hw_remove_wallet_notification_action_backup_go">Aller à la sauvegarde</string>
|
||||
<string name="hw_remove_wallet_notification_action_backup_view">Afficher la sauvegarde</string>
|
||||
<string name="hw_remove_wallet_notification_action_forget">Oubliez votre portefeuille</string>
|
||||
<string name="hw_remove_wallet_notification_action_forget_anyway">Oubliez quand même</string>
|
||||
<string name="hw_remove_wallet_notification_description_has_backup">Ce portefeuille dispose d\'une sauvegarde. Assurez-vous de pouvoir la récupérer avant d\'oublier le portefeuille.</string>
|
||||
<string name="hw_remove_wallet_notification_description_without_backup">Si vous oubliez ce portefeuille sans sauvegarde, vous perdrez définitivement l\'accès à vos fonds.</string>
|
||||
<string name="hw_remove_wallet_notification_title">Êtes-vous sûr de vouloir oublier ce portefeuille ?</string>
|
||||
<string name="hw_remove_wallet_warning_access">Je comprends que si je n\'ai pas sauvegardé mon portefeuille avant de le supprimer, je perdrai l\'accès à celui-ci.</string>
|
||||
<string name="hw_remove_wallet_warning_device">Je comprends que le fait de supprimer mon portefeuille ne l\'efface pas, mais le supprime uniquement de mon appareil.</string>
|
||||
<string name="hw_upgrade">Améliorer</string>
|
||||
<string name="hw_upgrade_backup_description">Aucune seed phrase n\'est requise. Votre carte ou bague Tangem devient votre sauvegarde sécurisée.</string>
|
||||
<string name="hw_upgrade_backup_title">Sauvegarde avec Tangem</string>
|
||||
<string name="hw_upgrade_error_card_already_has_wallet">Impossible de mettre à niveau. Un portefeuille existe déjà sur cet appareil.</string>
|
||||
<string name="hw_upgrade_error_card_key_import">Choisissez un autre appareil. Celui-ci ne peut pas être utilisé pour la mise à niveau.</string>
|
||||
<string name="hw_upgrade_error_wallet2_card_required">Une erreur s\'est produite pendant l\'opération.</string>
|
||||
<string name="hw_upgrade_funds_access_description">Vos fonds restent en sécurité et entièrement accessibles pendant toute la durée du processus.</string>
|
||||
<string name="hw_upgrade_funds_access_title">Accès aux fonds</string>
|
||||
<string name="hw_upgrade_general_security_description">Les données de votre wallet seront effacées de l\'application et stockées sur votre hardware wallet.</string>
|
||||
<string name="hw_upgrade_general_security_title">Sécurité générale</string>
|
||||
<string name="hw_upgrade_key_migration_description">Les clés privées seront transférées de l\'application vers votre hardware wallet Tangem.</string>
|
||||
<string name="hw_upgrade_key_migration_title">Migration des clés</string>
|
||||
<string name="hw_upgrade_scan_device">Scannez l\'appareil</string>
|
||||
<string name="hw_upgrade_start_action">Lancer la mise à niveau</string>
|
||||
<string name="hw_upgrade_start_description">Vous êtes sur le point de passer à notre hardware wallet. Il assurera la sécurité de vos actifs grâce au stockage hors ligne.</string>
|
||||
<string name="hw_upgrade_start_title">Tangem Wallet</string>
|
||||
<string name="hw_upgrade_title">Passez à notre Hardware Wallet</string>
|
||||
<string name="hw_upgrade_to_cold_banner_description">Protégez vos cryptomonnaies grâce au hardware wallet haut de gamme de Tangem.</string>
|
||||
<string name="hw_upgrade_to_cold_banner_title">Améliorez la sécurité de votre wallet grâce à un dispositif matériel</string>
|
||||
<string name="information_generated_with_ai">Ces informations ont été générées avec l\'IA.\nAppuyez ici si vous trouvez des erreurs.</string>
|
||||
<string name="initial_message_change_access_code_body">Touchez, pour modifier le code d\'accès</string>
|
||||
<string name="initial_message_change_passcode_body">Touchez, pour modifier le mot de passe</string>
|
||||
|
|
@ -1304,7 +1391,8 @@
|
|||
<string name="tangempay_onboarding_security_title">Confidentialité inégalée</string>
|
||||
<string name="tangempay_onboarding_title">Obtenez votre carte Tangem Pay gratuite en quelques minutes</string>
|
||||
<string name="tangempay_payment_account">Compte de paiement</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Synchronisation du compte de paiement nécessaire</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Le compte de paiement n\'est pas synchronisé</string>
|
||||
<string name="tangempay_pin_validation_error_message">Code PIN invalide : évitez les séquences ou les répétitions</string>
|
||||
<string name="tangempay_service_unavailable_description">Nous réparons un problème technique. Veuillez réessayer plus tard.</string>
|
||||
<string name="tangempay_service_unavailable_title">Service temporairement indisponible</string>
|
||||
<string name="tangempay_service_unreachable_try_later">Les données ne peuvent pas être affichées pour le moment, mais les paiements par carte fonctionnent toujours.</string>
|
||||
|
|
@ -1312,7 +1400,7 @@
|
|||
<string name="tangempay_tangem_visa_card">Utilisez USDC pour les paiements quotidiens</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Pay est temporairement indisponible</string>
|
||||
<string name="tangempay_title">Tangem Pay</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Utilisez votre carte ou votre bague pour restaurer l\'accès à votre compte de paiement</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Cliquez sur le bouton ci-dessous pour restaurer l\'accès</string>
|
||||
<string name="tangempay_your_pin_code">Votre code PIN</string>
|
||||
<string name="this_is_my_wallet_title">C\'est mon portefeuille</string>
|
||||
<string name="toast_balances_hidden">Soldes masqués</string>
|
||||
|
|
@ -1392,6 +1480,7 @@
|
|||
<string name="user_push_notification_banner_subtitle">Activez les notifications pour recevoir des alertes lorsque des fonds arrivent dans votre portefeuille.</string>
|
||||
<string name="user_push_notification_banner_title">Ne manquez aucune transaction</string>
|
||||
<string name="user_wallet_list_add_button">Ajouter un nouveau portefeuille</string>
|
||||
<string name="user_wallet_list_delete_hw_prompt">Si vous supprimez ce portefeuille sans sauvegarde, vous perdrez définitivement l\'accès à vos fonds.</string>
|
||||
<string name="user_wallet_list_delete_prompt">Êtes-vous sûr de vouloir supprimer ce portefeuille ?</string>
|
||||
<string name="user_wallet_list_error_unable_to_unlock">Une erreur s\'est produite, veuillez scanner votre carte ou bague pour vous connecter</string>
|
||||
<string name="user_wallet_list_error_wallet_already_saved">Ce portefeuille a déjà été enregistré, vous pouvez en ajouter un autre</string>
|
||||
|
|
@ -1505,6 +1594,8 @@
|
|||
<string name="warning_button_ok">Ok, compris!</string>
|
||||
<string name="warning_button_really_cool">Vraiment cool !</string>
|
||||
<string name="warning_button_refresh">Rafraîchir</string>
|
||||
<string name="warning_clore_migration_message">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.</string>
|
||||
<string name="warning_clore_migration_title">Migration du réseau Clore</string>
|
||||
<string name="warning_demo_mode_message">Vous êtes actuellement en mode démo</string>
|
||||
<string name="warning_demo_mode_title">Mode démo actif</string>
|
||||
<string name="warning_developer_card_message">La carte que vous avez scannée est une carte de développeur. Ne l\'utilisez pas pour créer votre portefeuille.</string>
|
||||
|
|
|
|||
|
|
@ -163,7 +163,8 @@
|
|||
<string name="tangempay_onboarding_security_title">Privacy senza rivali</string>
|
||||
<string name="tangempay_onboarding_title">Ottieni la tua carta Tangem Pay gratuita in pochi minuti</string>
|
||||
<string name="tangempay_payment_account">Conto di pagamento</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Sincronizzazione del conto di pagamento necessaria</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Il conto di pagamento non è sincronizzato</string>
|
||||
<string name="tangempay_pin_validation_error_message">PIN non valido: evitare sequenze o ripetizioni</string>
|
||||
<string name="tangempay_service_unavailable_description">Stiamo risolvendo un problema tecnico. Riprova più tardi.</string>
|
||||
<string name="tangempay_service_unavailable_title">Servizio temporaneamente non disponibile</string>
|
||||
<string name="tangempay_service_unreachable_try_later">Al momento non è possibile visualizzare i dati, ma i pagamenti con carta continuano a funzionare.</string>
|
||||
|
|
@ -171,7 +172,7 @@
|
|||
<string name="tangempay_tangem_visa_card">Usa USDC per i pagamenti quotidiani</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Pay è temporaneamente non disponibile</string>
|
||||
<string name="tangempay_title">Tangem Pay</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Usa la tua carta o il tuo anello per ripristinare l\'accesso al tuo conto di pagamento</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Fare clic sul pulsante in basso per ripristinare l\'accesso</string>
|
||||
<string name="tangempay_your_pin_code">Il tuo codice PIN</string>
|
||||
<string name="twins_recreate_toolbar">Tangem Twin</string>
|
||||
<string name="visa_onboarding_pin_code_description">Imposta un codice di 4 cifre.\nVerrà utilizzato per i pagamenti.</string>
|
||||
|
|
|
|||
|
|
@ -423,7 +423,6 @@
|
|||
<string name="custom_token_validation_error_not_found_title">トークンは誰でも作成できることに注意してください。</string>
|
||||
<string name="details_buy_wallet">Tangemウォレットを購入</string>
|
||||
<string name="details_chat">チャット</string>
|
||||
<string name="details_get_visa">Tangem Visaを入手</string>
|
||||
<string name="details_manage_security_access_code">アクセスコード</string>
|
||||
<string name="details_manage_security_access_code_description">カードをスキャンする前に、正しいアクセスコードを送信する必要があります。</string>
|
||||
<string name="details_manage_security_long_tap">長くタップ</string>
|
||||
|
|
@ -1504,7 +1503,8 @@
|
|||
<string name="tangempay_onboarding_security_title">他に類を見ないプライバシー</string>
|
||||
<string name="tangempay_onboarding_title">無料のTangem Payカードを数分でゲットしましょう</string>
|
||||
<string name="tangempay_payment_account">支払いアカウント</string>
|
||||
<string name="tangempay_payment_account_sync_needed">支払いアカウントの同期が必要です</string>
|
||||
<string name="tangempay_payment_account_sync_needed">支払アカウントが同期されていません</string>
|
||||
<string name="tangempay_pin_validation_error_message">無効な暗証番号:連続や繰り返しを避けてください</string>
|
||||
<string name="tangempay_service_unavailable_description">技術的な問題を修正しています。後でもう一度お試しください。</string>
|
||||
<string name="tangempay_service_unavailable_title">サービスは一時的に利用できません</string>
|
||||
<string name="tangempay_service_unreachable_try_later">現在、データを表示できませんが、カードでのお支払いは引き続きご利用いただけます。</string>
|
||||
|
|
@ -1512,7 +1512,7 @@
|
|||
<string name="tangempay_tangem_visa_card">日常の支払いにUSDCを利用</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Payは現在一時的に利用できません。</string>
|
||||
<string name="tangempay_title">Tangem Pay</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">カードまたはリングを使用して、支払いアカウントへのアクセスを復元してください。</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">下のボタンをクリックしてアクセスを復元してください</string>
|
||||
<string name="tangempay_your_pin_code">PINコード</string>
|
||||
<string name="this_is_my_wallet_title">これは私のウォレットです</string>
|
||||
<string name="toast_balances_hidden">残高非表示</string>
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@
|
|||
<string name="disclaimer_error_loading">Проверьте подключение с интернетом или переключитесь на другую сеть</string>
|
||||
<string name="disclaimer_title">Условия использования</string>
|
||||
<string name="domain_receive_assets_default_address">Основной адрес</string>
|
||||
<string name="domain_receive_assets_legacy_address">Legacy адрес</string>
|
||||
<string name="domain_receive_assets_legacy_address">Legacy %s адрес</string>
|
||||
<string name="domain_receive_assets_navigation_title">Получить активы</string>
|
||||
<string name="domain_receive_assets_network_name_address">%s адрес</string>
|
||||
<string name="domain_receive_assets_onboarding_description">Отправка средств в другой сети может повлечь потерю средств.</string>
|
||||
|
|
@ -551,6 +551,7 @@
|
|||
<string name="feedback_preface_scan_failed">Скажите, пожалуйста, какая у вас карта или кольцо?</string>
|
||||
<string name="feedback_preface_support">Привет, команда поддержки,</string>
|
||||
<string name="feedback_preface_tx_failed">Пожалуйста, расскажите нам больше о вашей проблеме. Каждая маленькая деталь может помочь.</string>
|
||||
<string name="feedback_subject_backup_problem">Проблема резервного копирования</string>
|
||||
<string name="feedback_subject_pre_activated_wallet">Ранее активированный кошелек</string>
|
||||
<string name="feedback_subject_rate_negative">Мои предложения</string>
|
||||
<string name="feedback_subject_scan_failed">Не могу отсканировать карту/кольцо</string>
|
||||
|
|
@ -1457,6 +1458,7 @@
|
|||
<string name="tangem_pay_unfreeze_card_failed">Не удалось разморозить карту, попробуйте еще раз</string>
|
||||
<string name="tangem_pay_unfreeze_card_success">Карта разморожена</string>
|
||||
<string name="tangem_pay_withdrawal">Вывести</string>
|
||||
<string name="tangempay_account_unable_to_use_rooted">Запрещено использовать на root-устройствах</string>
|
||||
<string name="tangempay_card_details_add_funds">Пополнить</string>
|
||||
<string name="tangempay_card_details_add_funds_subtitle">Способы пополнения</string>
|
||||
<string name="tangempay_card_details_card_number">Номер</string>
|
||||
|
|
@ -1484,6 +1486,7 @@
|
|||
<string name="tangempay_card_details_open_wallet_step_5">Всё готово! Можно пользоваться картой</string>
|
||||
<string name="tangempay_card_details_open_wallet_title">Добавьте карту в Google Pay</string>
|
||||
<string name="tangempay_card_details_open_wallet_title_apple">Добавить карту в Apple Pay</string>
|
||||
<string name="tangempay_card_details_pin_code">ПИН-код</string>
|
||||
<string name="tangempay_card_details_receive_description">Скопируйте свой адрес или покажите QR</string>
|
||||
<string name="tangempay_card_details_receive_error_description">Техническая ошибка. Попробуйте позже или обратитесь в поддержку.</string>
|
||||
<string name="tangempay_card_details_receive_error_title">Пополнение недоступно</string>
|
||||
|
|
@ -1492,6 +1495,7 @@
|
|||
<string name="tangempay_card_details_swap_description">Пополните карту любым активом через обмен </string>
|
||||
<string name="tangempay_card_details_title">Реквизиты</string>
|
||||
<string name="tangempay_card_details_unfreeze_card">Разморозить карту</string>
|
||||
<string name="tangempay_card_details_view_pin_code_title">Ваш ПИН</string>
|
||||
<string name="tangempay_card_details_withdraw">Вывести</string>
|
||||
<string name="tangempay_card_details_withdraw_error_title">Вывод сейчас недоступен</string>
|
||||
<string name="tangempay_card_details_withdraw_in_progress_description">Вы не можете начать обмен или новый вывод, пока не завершится текущий.</string>
|
||||
|
|
@ -1515,6 +1519,7 @@
|
|||
<string name="tangempay_kyc_in_progress">KYC в процессе</string>
|
||||
<string name="tangempay_kyc_in_progress_notification_button">Посмотреть статус</string>
|
||||
<string name="tangempay_kyc_in_progress_notification_title">KYC в процессе для Tangem Pay</string>
|
||||
<string name="tangempay_kyc_in_progress_popup_description">Вы можете посмотреть текущий статус KYC или отменить его</string>
|
||||
<string name="tangempay_onboarding_banner_description">Откройте бесплатную виртуальную карту Tangem Visa</string>
|
||||
<string name="tangempay_onboarding_banner_title">Оплачивайте ежедневные покупки в USDC</string>
|
||||
<string name="tangempay_onboarding_get_card_button_text">Открыть карту</string>
|
||||
|
|
@ -1526,15 +1531,16 @@
|
|||
<string name="tangempay_onboarding_security_title">Абсолютная приватность</string>
|
||||
<string name="tangempay_onboarding_title">Откройте виртуальную \nTangem Pay Card</string>
|
||||
<string name="tangempay_payment_account">Платежный аккаунт</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Требуется синхронизация платежного аккаунта</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Платежный аккаунт не синхронизирован</string>
|
||||
<string name="tangempay_pin_validation_error_message">Слабый ПИН: не используйте повторы или последовательности.</string>
|
||||
<string name="tangempay_service_unavailable_description">Мы устраняем техническую проблему. Пожалуйста, попробуйте позже.</string>
|
||||
<string name="tangempay_service_unavailable_title">Сервис временно недоступен</string>
|
||||
<string name="tangempay_service_unreachable_try_later">Не можем показать данные карты, но оплаты продолжают работать.</string>
|
||||
<string name="tangempay_sync_needed">Требуется синхронизация</string>
|
||||
<string name="tangempay_sync_needed">Не синхронизирован</string>
|
||||
<string name="tangempay_tangem_visa_card">Оплачивайте ежедневные покупки в USDC</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Pay временно недоступен</string>
|
||||
<string name="tangempay_title">Tangem Pay</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Используйте вашу карту или кольцо для восстановления доступа к платежному аккаунту</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Нажмите на кнопку ниже, чтобы восстановить доступ</string>
|
||||
<string name="tangempay_your_pin_code">Ваш PIN-код</string>
|
||||
<string name="this_is_my_wallet_title">Это мой кошелек</string>
|
||||
<string name="toast_balances_hidden">Балансы скрыты</string>
|
||||
|
|
@ -1735,6 +1741,8 @@
|
|||
<string name="warning_button_ok">Понятно!</string>
|
||||
<string name="warning_button_really_cool">Очень круто!</string>
|
||||
<string name="warning_button_refresh">Обновить</string>
|
||||
<string name="warning_clore_migration_message">Согласно официальной документации Clore, все монеты, полученные до 21 декабря, будут мигрированы в токен Clore (ERC-20); монеты, полученные после этой даты, — нет. Решение для перевода находится в разработке — следите за обновлениями.</string>
|
||||
<string name="warning_clore_migration_title">Миграция сети Clore</string>
|
||||
<string name="warning_demo_mode_message">Вы находитесь в режиме демо</string>
|
||||
<string name="warning_demo_mode_title">Демо режим включен</string>
|
||||
<string name="warning_developer_card_message">Отсканированная вами карта является картой разработчика. Не используйте ее для создания своего кошелька.</string>
|
||||
|
|
|
|||
|
|
@ -49,6 +49,19 @@
|
|||
<string name="app_settings_theme_mode_system">Системна</string>
|
||||
<string name="app_settings_theme_selector_title">Тема</string>
|
||||
<string name="app_settings_title">Налаштування застосунку</string>
|
||||
<string name="backup_complete_description">Ви успішно створили резервну копію свого гаманця.</string>
|
||||
<string name="backup_complete_seed_description">Ці слова неможливо відновити у разі втрати. Зберігайте їх надійно.</string>
|
||||
<string name="backup_complete_title">Бекап завершено</string>
|
||||
<string name="backup_info_description">Ваша фраза відновлення — це набір випадкових слів %s для доступу та відновлення гаманця.</string>
|
||||
<string name="backup_info_keep_description">Ці слова неможливо відновити, якщо їх загубити. Зберігайте їх у безпеці.</string>
|
||||
<string name="backup_info_keep_title">Зберігайте в безпеці</string>
|
||||
<string name="backup_info_save_description">Збережіть ці %s слова в безпечному місці та нікому не розповідайте про них.</string>
|
||||
<string name="backup_info_save_title">Відновлення неможливе</string>
|
||||
<string name="backup_info_title">Фраза відновлення</string>
|
||||
<string name="backup_seed_caution">Наведені нижче слова %s - це фраза для відновлення вашого гаманця. Ніколи і нікому не повідомляйте ці слова. Tangem ніколи не запитає їх у вас. Використовуйте їх, щоб відновити свій гаманець, якщо ви втратите пристрій.</string>
|
||||
<string name="backup_seed_description">Запишіть ці %s слова в указаному порядку і зберігайте їх у безпеці та таємниці.</string>
|
||||
<string name="backup_seed_responsibility">Ви несете повну відповідальність за безпеку свого гаманця і фрази відновлення.</string>
|
||||
<string name="backup_seed_title">Фраза відновлення</string>
|
||||
<string name="balance_hidden_description">Щоб приховати або показати свій баланс, просто переверніть екран пристрою вниз або вимкніть його в налаштуваннях</string>
|
||||
<string name="balance_hidden_do_not_show_button">Більше не показувати</string>
|
||||
<string name="balance_hidden_got_it_button">Зрозуміло</string>
|
||||
|
|
@ -310,7 +323,7 @@
|
|||
<string name="disclaimer_error_loading">Перевірте підключення до інтернету або змініть мережу</string>
|
||||
<string name="disclaimer_title">Умови використання</string>
|
||||
<string name="domain_receive_assets_default_address">Основна адреса</string>
|
||||
<string name="domain_receive_assets_legacy_address">Legacy адреса</string>
|
||||
<string name="domain_receive_assets_legacy_address">Legacy %s адреса</string>
|
||||
<string name="domain_receive_assets_navigation_title">Отримати активи</string>
|
||||
<string name="domain_receive_assets_network_name_address">%s адреса</string>
|
||||
<string name="domain_receive_assets_onboarding_description">Надсилання активів в інші мережі призведе до безповоротної втрати.</string>
|
||||
|
|
@ -395,6 +408,7 @@
|
|||
<string name="feedback_preface_scan_failed">Розкажіть, будь ласка, яку картку або кільце ви маєте?</string>
|
||||
<string name="feedback_preface_support">Привіт, команда підтримки,</string>
|
||||
<string name="feedback_preface_tx_failed">Будь ласка, розкажіть нам більше про вашу проблему. Кожна дрібниця може допомогти.</string>
|
||||
<string name="feedback_subject_backup_problem">Проблема з резервним копіюванням</string>
|
||||
<string name="feedback_subject_pre_activated_wallet">Раніше активований гаманець</string>
|
||||
<string name="feedback_subject_rate_negative">Мої пропозиції</string>
|
||||
<string name="feedback_subject_scan_failed">Не вдається відсканувати картку/кільце</string>
|
||||
|
|
@ -413,11 +427,85 @@
|
|||
<string name="give_permission_swap_subtitle" formatted="false">Щоб продовжити, вам потрібно дозволити смарт-контракту %1s використовувати ваш %2s</string>
|
||||
<string name="give_permission_title">Надати дозвіл</string>
|
||||
<string name="give_permission_unlimited">Необмежено</string>
|
||||
<string name="hardware_wallet_backup_feature_description">Резервна копія створюється на 2–3 картках Tangem. Зберігайте їх окремо для безпеки — seed-фраза не потрібна.</string>
|
||||
<string name="hardware_wallet_backup_feature_title">Бекап на декілька карток</string>
|
||||
<string name="hardware_wallet_create_title">Додати гаманець Tangem</string>
|
||||
<string name="hardware_wallet_key_feature_description">Ваш приватний ключ генерується на картці Tangem і ніколи не покидає її.</string>
|
||||
<string name="hardware_wallet_key_feature_title">Генерація ключа</string>
|
||||
<string name="hardware_wallet_security_feature_description">Операції з криптографією відбуваються всередині захищеного чіпу, стійкого до клонування та фізичному взлому.</string>
|
||||
<string name="hardware_wallet_security_feature_title">Безпека на апаратному рівні</string>
|
||||
<string name="home_button_create_new_wallet">Створити новий гаманець</string>
|
||||
<string name="home_button_order">Купити</string>
|
||||
<string name="home_button_scan">Сканувати</string>
|
||||
<string name="hot_crypto_add_token_subtitle">в %s</string>
|
||||
<string name="hot_crypto_token_network">В мережі %s</string>
|
||||
<string name="hw_access_code_create_alert_title">Ви впевнені, що хочете скасувати процес створення коду доступу?</string>
|
||||
<string name="hw_activation_need_backup">Створити бекап</string>
|
||||
<string name="hw_activation_need_description">Щоб завершити налаштування, створіть резервну копію свого гаманця та захистіть додаток за допомогою коду доступу.</string>
|
||||
<string name="hw_activation_need_finish">Завершити зараз</string>
|
||||
<string name="hw_activation_need_title">Завершити налаштування гаманця</string>
|
||||
<string name="hw_activation_need_warning_description">Завершіть налаштування, захистивши додаток кодом доступу.</string>
|
||||
<string name="hw_backup_alert_description">Якщо ви вийдете, вам доведеться починати спочатку.</string>
|
||||
<string name="hw_backup_alert_title">Ви впевнені, що хочете вийти з процесу активації?</string>
|
||||
<string name="hw_backup_banner_description">Зберігає ваші криптовалюти в безпеці та в режимі офлайн. Тонкий, як кредитна картка, безпечніший за банківське сховище.</string>
|
||||
<string name="hw_backup_close_description">Якщо ви це зробите, доведеться почати спочатку.</string>
|
||||
<string name="hw_backup_google_drive_description">Відновлення існуючого гаманця за допомогою резервної копії Google Диску</string>
|
||||
<string name="hw_backup_google_drive_title">Google Диск бекап</string>
|
||||
<string name="hw_backup_hardware_create_description">Створіть новий захищений гаманець і переведіть свої кошти для додаткового захисту.</string>
|
||||
<string name="hw_backup_hardware_create_title">Створити новий гаманець</string>
|
||||
<string name="hw_backup_hardware_description">Підвищіть рівень своєї безпеки за допомогою просунутого апаратного гаманця Tangem.</string>
|
||||
<string name="hw_backup_hardware_title">Апаратний гаманець</string>
|
||||
<string name="hw_backup_hardware_upgrade_description">Перенесіть свій поточний гаманець у Tangem.</string>
|
||||
<string name="hw_backup_hardware_upgrade_title">Оновіть поточний гаманець</string>
|
||||
<string name="hw_backup_need_action">Перейти до бекапу</string>
|
||||
<string name="hw_backup_need_description">Будь ласка, створіть резервну копію свого гаманця, перш ніж створювати код доступу.</string>
|
||||
<string name="hw_backup_need_finish_first">Спочатку завершіть резервне копіювання</string>
|
||||
<string name="hw_backup_need_title">Спочатку завершіть резервне копіювання</string>
|
||||
<string name="hw_backup_no_backup">Не завершено</string>
|
||||
<string name="hw_backup_section_other_title">Інші методи</string>
|
||||
<string name="hw_backup_seed_description">Збережіть фразу відновлення у безпечному місці і тримайте її у таємниці.</string>
|
||||
<string name="hw_backup_seed_title">Фраза відновлення</string>
|
||||
<string name="hw_backup_to_secure_description">Щоб захистити свій гаманець за допомогою коду доступу, завершіть процес резервного копіювання.</string>
|
||||
<string name="hw_backup_to_upgrade_description">Щоб покращити гаманець до апаратного, спочатку створіть резервну копію.</string>
|
||||
<string name="hw_create_keys_description">Ваші приватні ключі надійно зашифровані та зберігаються на вашому телефоні</string>
|
||||
<string name="hw_create_keys_title">Ключі зберігаються у застосунку</string>
|
||||
<string name="hw_create_seed_description">Створіть або відновіть свій гаманець за допомогою вашої фрази відновлення.</string>
|
||||
<string name="hw_create_seed_title">Резервна копія</string>
|
||||
<string name="hw_create_title">Створити мобільний гаманець</string>
|
||||
<string name="hw_import_existing_wallet">Імпортувати існуючий гаманець</string>
|
||||
<string name="hw_import_seed_phrase_already_imported">Ця фраза відновлення вже була імпортована</string>
|
||||
<string name="hw_mobile_wallet">Мобільний гаманець</string>
|
||||
<string name="hw_remove_wallet_action_forget_title">Забути гаманець</string>
|
||||
<string name="hw_remove_wallet_attention_description">Цей гаманець буде назавжди видалено з вашого пристрою</string>
|
||||
<string name="hw_remove_wallet_confirmation_title">Ви впевнені, що хочете виконати цю операцію?</string>
|
||||
<string name="hw_remove_wallet_nav_title">Забути гаманець</string>
|
||||
<string name="hw_remove_wallet_notification_action_backup_go">Перейти до резервної копії</string>
|
||||
<string name="hw_remove_wallet_notification_action_backup_view">Переглянути резервне копіювання</string>
|
||||
<string name="hw_remove_wallet_notification_action_forget">Забути гаманець</string>
|
||||
<string name="hw_remove_wallet_notification_action_forget_anyway">Все одно забути</string>
|
||||
<string name="hw_remove_wallet_notification_description_has_backup">Резервна копія цього гаманця існує. Перевірте її перед видаленням, щоб переконатися, що зможете відновити гаманець пізніше.</string>
|
||||
<string name="hw_remove_wallet_notification_description_without_backup">Якщо ви видалите цей гаманець без резервної копії, ви назавжди втратите доступ до своїх коштів.</string>
|
||||
<string name="hw_remove_wallet_notification_title">Забути цей гаманець?</string>
|
||||
<string name="hw_remove_wallet_warning_access">Я розумію, що якщо я не створив резервну копію гаманця перед його видаленням, я можу втратити досту до нього.</string>
|
||||
<string name="hw_remove_wallet_warning_device">Я розумію, що видалення мого гаманця не видаляє його повністю, а просто видаляє його з мого пристрою.</string>
|
||||
<string name="hw_upgrade_backup_description">Фраза відновлення більше не потрібна — ваша картка або кільце Tangem стає вашою безпечною резервною копією.</string>
|
||||
<string name="hw_upgrade_backup_title">Резервне копіювання з Tangem</string>
|
||||
<string name="hw_upgrade_error_card_already_has_wallet">Цей пристрій не може бути використаний для оновлення, він вже містить інший гаманець.</string>
|
||||
<string name="hw_upgrade_error_card_key_import">Виберіть інший пристрій. Цей не можна використовувати для оновлення.</string>
|
||||
<string name="hw_upgrade_error_wallet2_card_required">Під час операції виникла помилка.</string>
|
||||
<string name="hw_upgrade_funds_access_description">Ваші кошти залишаються в безпеці та повністю доступними протягом усього процесу</string>
|
||||
<string name="hw_upgrade_funds_access_title">Доступ до коштів</string>
|
||||
<string name="hw_upgrade_general_security_description">Данні вашого гаманця будуть видалені із застосунку і збережені на вашому пристрої Tangem.</string>
|
||||
<string name="hw_upgrade_general_security_title">Загальна безпека</string>
|
||||
<string name="hw_upgrade_key_migration_description">Приватні ключі будуть переміщені з додатку у вашу Tangem картрку або кільце</string>
|
||||
<string name="hw_upgrade_key_migration_title">Міграція ключів</string>
|
||||
<string name="hw_upgrade_scan_device">Сканувати пристрій</string>
|
||||
<string name="hw_upgrade_start_action">Розпочати оновлення</string>
|
||||
<string name="hw_upgrade_start_description">Ви збираєтеся перейти на пристрій Tangem, де ваші активи будуть у безпеці в холодному сховищі.</string>
|
||||
<string name="hw_upgrade_start_title">Tangem Wallet</string>
|
||||
<string name="hw_upgrade_title">Оновіть до апаратного гаманця</string>
|
||||
<string name="hw_upgrade_to_cold_banner_description">Зберігайте свою криптовалюту в безпеці за допомогою першокласного апаратного гаманця Tangem.</string>
|
||||
<string name="hw_upgrade_to_cold_banner_title">Оновіть свій гаманець до апаратної версії.</string>
|
||||
<string name="information_generated_with_ai">Ця інформація була створена за допомогою ШІ.\nНатисніть тут, якщо знайшли помилку.</string>
|
||||
<string name="initial_message_change_access_code_body">Щоб змінити код доступу, прикладіть картку або кільце, як показано вище, і не прибирайте її до закінчення операції</string>
|
||||
<string name="initial_message_change_passcode_body">Щоб змінити пароль, прикладіть картку, як показано вище, і не прибирайте її до закінчення операції</string>
|
||||
|
|
@ -1144,9 +1232,11 @@
|
|||
<string name="tangempay_get_banner_description">Отримайте безкоштовну віртуальну картку Tangem Visa</string>
|
||||
<string name="tangempay_onboarding_banner_description">Отримайте безкоштовну віртуальну картку Tangem Visa</string>
|
||||
<string name="tangempay_onboarding_banner_title">Використовуйте USDC для щоденних платежів</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Платіжний рахунок не синхронізовано</string>
|
||||
<string name="tangempay_service_unavailable_description">Ми усуваємо технічну проблему. Будь ласка, спробуйте пізніше.</string>
|
||||
<string name="tangempay_service_unavailable_title">Сервіс тимчасово недоступний</string>
|
||||
<string name="tangempay_tangem_visa_card">Використовуйте USDC для щоденних платежів</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Натисніть кнопку нижче, щоб відновити доступ</string>
|
||||
<string name="this_is_my_wallet_title">Це мій гаманець</string>
|
||||
<string name="toast_balances_hidden">Баланси приховано</string>
|
||||
<string name="toast_balances_shown">Баланси показано</string>
|
||||
|
|
@ -1223,6 +1313,7 @@
|
|||
<string name="user_push_notification_agreement_argument_two_title">Нові функції та важливі новини</string>
|
||||
<string name="user_push_notification_agreement_header">Бажаєте використовувати Push-повідомлення?</string>
|
||||
<string name="user_wallet_list_add_button">Додати новий гаманець</string>
|
||||
<string name="user_wallet_list_delete_hw_prompt">Якщо ви видалите цей гаманець без резервної копії, ви назавжди втратите доступ до своїх коштів.</string>
|
||||
<string name="user_wallet_list_delete_prompt">Ви впевнені, що хочете видалити цей гаманець?</string>
|
||||
<string name="user_wallet_list_error_unable_to_unlock">Сталася помилка, будь ласка, відскануйте свою картку або кільце, для входу</string>
|
||||
<string name="user_wallet_list_error_wallet_already_saved">Цей гаманець вже збережено, ви можете додати інший</string>
|
||||
|
|
@ -1293,6 +1384,8 @@
|
|||
<string name="warning_button_ok">Зрозуміло!</string>
|
||||
<string name="warning_button_really_cool">Дуже круто!</string>
|
||||
<string name="warning_button_refresh">Оновити</string>
|
||||
<string name="warning_clore_migration_message">Згідно з офіційною документацією Clore, усі монети, отримані до 21 грудня, будуть мігровані в токен Clore (ERC-20); монети, отримані після цієї дати, — ні. Рішення для переказу перебуває в розробці — стежте за оновленнями.</string>
|
||||
<string name="warning_clore_migration_title">Міграція мережі Clore</string>
|
||||
<string name="warning_demo_mode_message">Ви перебуваєте в демонстраційному режимі</string>
|
||||
<string name="warning_demo_mode_title">Демонстраційний режим активовано</string>
|
||||
<string name="warning_developer_card_message">Відсканована вами картка є карткою розробника. Не використовуйте її для створення гаманця.</string>
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@
|
|||
<string name="tangempay_onboarding_security_title">無與倫比的隱私</string>
|
||||
<string name="tangempay_onboarding_title">在幾分鐘內獲得免費的 Tangem Pay 卡</string>
|
||||
<string name="tangempay_payment_account">付款帳戶</string>
|
||||
<string name="tangempay_payment_account_sync_needed">需要同步支付账户</string>
|
||||
<string name="tangempay_payment_account_sync_needed">付款帳戶未同步</string>
|
||||
<string name="tangempay_service_unavailable_description">我们正在修复技术问题。请稍后再试。</string>
|
||||
<string name="tangempay_service_unavailable_title">服務暫時無法使用</string>
|
||||
<string name="tangempay_service_unreachable_try_later">目前無法顯示資料,但卡片支付仍可正常使用。</string>
|
||||
|
|
@ -414,7 +414,7 @@
|
|||
<string name="tangempay_tangem_visa_card">使用 USDC 進行日常支付</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Pay暂时不可用</string>
|
||||
<string name="tangempay_title">Tangem Pay</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">使用您的卡片或戒指恢复对支付账户的访问</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">點擊下方按鈕以恢復存取權限</string>
|
||||
<string name="tangempay_your_pin_code">您的PIN码</string>
|
||||
<string name="token_details_hide_alert_hide">隱藏</string>
|
||||
<string name="token_details_hide_alert_message">您即將在主屏幕上隱藏此代幣。您可以隨時通過管理代幣頁面將其添加回來。</string>
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@
|
|||
<string name="account_unsaved_dialog_message_create">Are you sure you want to discard new account?</string>
|
||||
<string name="account_unsaved_dialog_message_edit">Are you sure you want to discard edits?</string>
|
||||
<string name="account_unsaved_dialog_title">Unsaved Changes</string>
|
||||
<string name="accounts_migration_alert_message">Some custom tokens were moved from “%1$s” to “%2$s” as their derivation belongs to that account.</string>
|
||||
<string name="accounts_migration_alert_title">Some custom tokens were moved</string>
|
||||
<string name="accounts_migration_alert_message">Some custom tokens will be automatically moved from “%1$s” to “%2$s” as their derivation belongs to that account.</string>
|
||||
<string name="accounts_migration_alert_title">Some custom tokens will be automatically moved</string>
|
||||
<string name="action_buttons_buy_empty_search_message">Can’t find your token? Go to the Market section on the main page and add it to your portfolio for purchase</string>
|
||||
<string name="action_buttons_sell_empty_search_message">Can’t find your token? Go to the Market section on the main page and add it to your portfolio for selling.</string>
|
||||
<string name="action_buttons_sell_navigation_bar_title">Sell</string>
|
||||
|
|
@ -128,15 +128,15 @@
|
|||
</plurals>
|
||||
<string name="auth_wallet_mobile_description">Mobile Wallet</string>
|
||||
<string name="backup_complete_description">You successfully backed up your wallet.</string>
|
||||
<string name="backup_complete_seed_description">These words are unrecoverable if lost. Keep them somewhere safe.</string>
|
||||
<string name="backup_complete_seed_description">These words cannot be recovered if lost. Store them securely.</string>
|
||||
<string name="backup_complete_title">Backup completed</string>
|
||||
<string name="backup_info_description">Your secret recovery phrase is a fixed set of %s random words for accessing and recovering your wallet.</string>
|
||||
<string name="backup_info_description">Your secret recovery phrase is a set of %s random words for accessing and recovering your wallet.</string>
|
||||
<string name="backup_info_keep_description">These words cannot be recovered if lost. Keep them safe.</string>
|
||||
<string name="backup_info_keep_title">Keep it safe</string>
|
||||
<string name="backup_info_save_description">Save these %s words in a secure location and never share them with anyone.</string>
|
||||
<string name="backup_info_save_title">No recovery possible</string>
|
||||
<string name="backup_info_title">Recovery phrase</string>
|
||||
<string name="backup_seed_caution">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.</string>
|
||||
<string name="backup_seed_caution">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.</string>
|
||||
<string name="backup_seed_description">Write down these %s words in numerical order and keep them safe and private</string>
|
||||
<string name="backup_seed_responsibility">You are fully responsible for securing your wallet and safely backing up your recovery phrase.</string>
|
||||
<string name="backup_seed_title">Recovery phrase</string>
|
||||
|
|
@ -431,7 +431,6 @@
|
|||
<string name="custom_token_validation_error_not_found_title">Note that tokens can be created by anyone</string>
|
||||
<string name="details_buy_wallet">Buy Tangem Wallet</string>
|
||||
<string name="details_chat">Chat</string>
|
||||
<string name="details_get_visa">Get Tangem Visa</string>
|
||||
<string name="details_manage_security_access_code">Access code</string>
|
||||
<string name="details_manage_security_access_code_description">You will have to submit the correct access code before scanning the card</string>
|
||||
<string name="details_manage_security_long_tap">Long Tap</string>
|
||||
|
|
@ -567,8 +566,8 @@
|
|||
<string name="give_permission_swap_subtitle" formatted="false">To continue, grant %1s smart contracts permission to use your %2s</string>
|
||||
<string name="give_permission_title">Give Permission</string>
|
||||
<string name="give_permission_unlimited">Unlimited</string>
|
||||
<string name="hardware_wallet_backup_feature_description">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.</string>
|
||||
<string name="hardware_wallet_backup_feature_title">Backup with Multiple Cards</string>
|
||||
<string name="hardware_wallet_backup_feature_description">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.</string>
|
||||
<string name="hardware_wallet_backup_feature_title">Backup With Multiple Cards</string>
|
||||
<string name="hardware_wallet_create_title">Add Tangem Wallet</string>
|
||||
<string name="hardware_wallet_key_feature_description">Your private key is generated directly inside the Tangem card and never leaves it.</string>
|
||||
<string name="hardware_wallet_key_feature_title">Key Generation</string>
|
||||
|
|
@ -588,7 +587,7 @@
|
|||
<string name="hw_activation_need_title">Finalize wallet setup</string>
|
||||
<string name="hw_activation_need_warning_description">Complete setup by securing the app with an access code.</string>
|
||||
<string name="hw_backup_alert_description">If you exit, you\'ll need to start over.</string>
|
||||
<string name="hw_backup_alert_title">Are you sure you want to quit the setup process?</string>
|
||||
<string name="hw_backup_alert_title">Are you sure you want to quit activation?</string>
|
||||
<string name="hw_backup_banner_description">Keeps your crypto safe and offline. Slim as a credit card, safer than a bank vault.</string>
|
||||
<string name="hw_backup_close_description">If you do, you\'ll need to start over.</string>
|
||||
<string name="hw_backup_google_drive_description">Recover existing wallet via Google Drive backup</string>
|
||||
|
|
@ -601,7 +600,7 @@
|
|||
<string name="hw_backup_hardware_upgrade_title">Upgrade current wallet</string>
|
||||
<string name="hw_backup_need_action">Go to backup</string>
|
||||
<string name="hw_backup_need_description">Please back up your wallet before creating an access code.</string>
|
||||
<string name="hw_backup_need_finish_first">Finish backup first</string>
|
||||
<string name="hw_backup_need_finish_first">Complete the backup first</string>
|
||||
<string name="hw_backup_need_title">Finalize backup first</string>
|
||||
<string name="hw_backup_no_backup">Incomplete</string>
|
||||
<string name="hw_backup_section_other_title">Other methods</string>
|
||||
|
|
@ -632,13 +631,13 @@
|
|||
<string name="hw_remove_wallet_warning_device">I understand that removing my wallet does not delete it, only removes it from my device.</string>
|
||||
<string name="hw_upgrade">Upgrade</string>
|
||||
<string name="hw_upgrade_backup_description">Seed phrase not required. Your Tangem card or ring becomes your secure backup.</string>
|
||||
<string name="hw_upgrade_backup_title">Backup with Tangem</string>
|
||||
<string name="hw_upgrade_backup_title">Backup With Tangem</string>
|
||||
<string name="hw_upgrade_error_card_already_has_wallet">Can\'t upgrade. A wallet already exists on this device.</string>
|
||||
<string name="hw_upgrade_error_card_key_import">Pick another device. This one can’t be used for the upgrade.</string>
|
||||
<string name="hw_upgrade_error_card_key_import">Pick another device. This one can\'t be used for the upgrade.</string>
|
||||
<string name="hw_upgrade_error_wallet2_card_required">An error occurred during the operation.</string>
|
||||
<string name="hw_upgrade_funds_access_description">Your funds remain safe and fully accessible during the process</string>
|
||||
<string name="hw_upgrade_funds_access_title">Access to funds</string>
|
||||
<string name="hw_upgrade_general_security_description">Your wallet data will be erased from the app and stored on your hardware wallet</string>
|
||||
<string name="hw_upgrade_general_security_description">Your wallet information will be erased from the app and stored on your hardware wallet</string>
|
||||
<string name="hw_upgrade_general_security_title">General security</string>
|
||||
<string name="hw_upgrade_key_migration_description">Private keys will be moved from the app to your Tangem hardware wallet</string>
|
||||
<string name="hw_upgrade_key_migration_title">Key migration</string>
|
||||
|
|
@ -902,8 +901,8 @@
|
|||
<string name="onboarding_activation_error_message">Please repeat the operation. The card will be reset to factory settings.</string>
|
||||
<string name="onboarding_activation_error_title">Activation error</string>
|
||||
<string name="onboarding_add_tokens">Add tokens</string>
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added">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?</string>
|
||||
<string name="onboarding_backup_exit_warning">The backup process is partly complete. You can\'t exit it now.</string>
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added">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?</string>
|
||||
<string name="onboarding_backup_exit_warning">The backup is partially complete and can\'t be quit now.</string>
|
||||
<string name="onboarding_bottom_sheet_passphrase_description">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.</string>
|
||||
<string name="onboarding_button_add_backup_card">Add a card or ring</string>
|
||||
<string name="onboarding_button_backup_card">Scan card</string>
|
||||
|
|
@ -953,7 +952,7 @@
|
|||
<string name="onboarding_seed_phrase_intro_legacy">Legacy</string>
|
||||
<string name="onboarding_seed_user_validation_message">To check whether you’ve written down your seed phrase correctly, please enter the 2nd, 7th and 11th words</string>
|
||||
<string name="onboarding_seed_user_validation_title">So, let’s check</string>
|
||||
<string name="onboarding_subtitle_no_backup_cards">To start the backup process add up to two backup cards or rings.</string>
|
||||
<string name="onboarding_subtitle_no_backup_cards">To start the backup process, add up to two backup cards or rings.</string>
|
||||
<string name="onboarding_subtitle_one_backup_card">You can add one more card or ring or finalize the backup process</string>
|
||||
<string name="onboarding_subtitle_scan_backup_card_format">Prepare the backup card with number %s</string>
|
||||
<string name="onboarding_subtitle_scan_primary">Scan the primary card or ring to start the backup process.</string>
|
||||
|
|
@ -1092,8 +1091,8 @@
|
|||
<string name="reset_card_to_factory_condition_1">I understand that after performing this action, I will no longer have access to the current wallet</string>
|
||||
<string name="reset_card_to_factory_condition_2">I realize that I can\'t use this card to recover my access code on the other cards of the current wallet</string>
|
||||
<string name="reset_card_to_factory_condition_3">I understand that I will completely lose access to my Tangem Pay Card and all funds on it without the possibility of recovery</string>
|
||||
<string name="reset_card_with_backup_to_factory_message">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.</string>
|
||||
<string name="reset_card_without_backup_to_factory_message">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.</string>
|
||||
<string name="reset_card_with_backup_to_factory_message">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.</string>
|
||||
<string name="reset_card_without_backup_to_factory_message">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.</string>
|
||||
<string name="reset_cards_dialog_complete_description">All Tangem devices have been reset.</string>
|
||||
<string name="reset_cards_dialog_first_description">Something went wrong with the activation process. Please reset the cards one by one.</string>
|
||||
<string name="reset_cards_dialog_first_title">Card verification failed</string>
|
||||
|
|
@ -1378,7 +1377,7 @@
|
|||
<string name="staking_your_stakes">Your stakes</string>
|
||||
<string name="story_awe_description">Store your crypto assets secure while keeping private keys contained in your card or ring</string>
|
||||
<string name="story_awe_title">Revolutionary Hardware Wallet</string>
|
||||
<string name="story_backup_description">Up to 3 physical cards or rings to one wallet</string>
|
||||
<string name="story_backup_description">Add up to 3 cards or rings to one wallet</string>
|
||||
<string name="story_backup_title">Ultra Secure Backup</string>
|
||||
<string name="story_currencies_description">A hardware wallet for your Bitcoin, Ethereum and many more currencies simultaneously — all in one card or ring</string>
|
||||
<string name="story_currencies_title">Thousands of Currencies</string>
|
||||
|
|
@ -1528,15 +1527,18 @@
|
|||
<string name="tangempay_onboarding_security_title">Unrivaled privacy</string>
|
||||
<string name="tangempay_onboarding_title">Get your free Tangem Pay Card in minutes</string>
|
||||
<string name="tangempay_payment_account">Payment account</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Payment account sync needed</string>
|
||||
<string name="tangempay_payment_account_sync_needed">Payment account is not synced</string>
|
||||
<string name="tangempay_pin_validation_error_message">Invalid PIN: avoid sequences or repeats</string>
|
||||
<string name="tangempay_service_unavailable_description">We’re fixing a technical issue. Please try again later.</string>
|
||||
<string name="tangempay_service_unavailable_title">Service temporarily unavailable</string>
|
||||
<string name="tangempay_service_unreachable_try_later">Unable to display details. However, card payments are still working.</string>
|
||||
<string name="tangempay_sync_needed">Sync needed</string>
|
||||
<string name="tangempay_set_pin_code">Set \nPIN code</string>
|
||||
<string name="tangempay_sync_needed">Not synced</string>
|
||||
<string name="tangempay_sync_needed_restore_access">Restore access</string>
|
||||
<string name="tangempay_tangem_visa_card">Use USDC for everyday payments</string>
|
||||
<string name="tangempay_temporarily_unavailable">Tangem Pay is temporarily unreachable</string>
|
||||
<string name="tangempay_title">Tangem Pay</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Use your card or ring to restore access to your payment account</string>
|
||||
<string name="tangempay_use_tangem_device_to_restore_payment_account">Click the button below to restore access</string>
|
||||
<string name="tangempay_your_pin_code">Your PIN code</string>
|
||||
<string name="this_is_my_wallet_title">This is my wallet</string>
|
||||
<string name="toast_balances_hidden">Balances hidden</string>
|
||||
|
|
@ -1786,7 +1788,7 @@
|
|||
<string name="warning_access_denied_message">Use %s or scan a card/ring to unlock access to your wallet</string>
|
||||
<string name="warning_approval_in_progress_message">The permission-granting process is currently underway and will be completed shortly</string>
|
||||
<string name="warning_approval_in_progress_title">Approval in Progress</string>
|
||||
<string name="warning_backup_errors_message">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.</string>
|
||||
<string name="warning_backup_errors_message">Activation was not completed successfully. This may be due to an NFC issue or incorrect tapping. Please contact our Support team for assistance.</string>
|
||||
<string name="warning_backup_errors_title">Activation error</string>
|
||||
<string name="warning_beacon_chain_retirement_content">On December 3, 2024, the BEP-2 network was disabled by decision of the network developers and is no longer supported</string>
|
||||
<string name="warning_beacon_chain_retirement_title">BNB Beacon Chain shut down</string>
|
||||
|
|
@ -1797,6 +1799,8 @@
|
|||
<string name="warning_button_ok">Ok, Got it!</string>
|
||||
<string name="warning_button_really_cool">Really cool!</string>
|
||||
<string name="warning_button_refresh">Refresh</string>
|
||||
<string name="warning_clore_migration_message">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.</string>
|
||||
<string name="warning_clore_migration_title">Clore Network Migration</string>
|
||||
<string name="warning_demo_mode_message">You are currently in the Demo mode</string>
|
||||
<string name="warning_demo_mode_title">Demo mode active</string>
|
||||
<string name="warning_developer_card_message">The card you scanned is a developer card. Do not use it to create your wallet.</string>
|
||||
|
|
@ -1845,7 +1849,7 @@
|
|||
<string name="warning_network_unreachable_message">The network is currently unreachable. Please try again later.</string>
|
||||
<string name="warning_network_unreachable_title">Network is unreachable</string>
|
||||
<string name="warning_no_account_title">Top up your wallet</string>
|
||||
<string name="warning_no_backup_message">Your wallet hasn\'t been backed up. Carry out this procedure to protect your assets now.</string>
|
||||
<string name="warning_no_backup_message">Your wallet isn\'t backed up yet. Back it up now to protect your assets.</string>
|
||||
<string name="warning_no_backup_title">Missing backup</string>
|
||||
<string name="warning_number_of_signed_hashes_incorrect_message">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.</string>
|
||||
<string name="warning_number_of_signed_hashes_incorrect_title">Card has already signed transactions</string>
|
||||
|
|
@ -1985,10 +1989,10 @@
|
|||
<string name="welcome_create_wallet_use_hardware_description">Use a Tangem hardware wallet</string>
|
||||
<string name="welcome_create_wallet_use_hardware_title">Learn more & buy</string>
|
||||
<string name="welcome_interrupted_backup_alert_discard">Discard</string>
|
||||
<string name="welcome_interrupted_backup_alert_message">You have an interrupted backup. Do you want to resume?</string>
|
||||
<string name="welcome_interrupted_backup_alert_message">Your backup was interrupted. Do you want to resume?</string>
|
||||
<string name="welcome_interrupted_backup_alert_resume">Yes, resume</string>
|
||||
<string name="welcome_interrupted_backup_discard_discard">Discard</string>
|
||||
<string name="welcome_interrupted_backup_discard_message">If you discard the backup now, then you will have to reset the devices to factory settings to start over again</string>
|
||||
<string name="welcome_interrupted_backup_discard_message">If you discard the backup now, you will have to reset the devices to factory settings to start over again</string>
|
||||
<string name="welcome_interrupted_backup_discard_resume">Resume backup</string>
|
||||
<string name="welcome_interrupted_backup_discard_title">This is an irreversible action</string>
|
||||
<string name="welcome_unlock">Log in with %s</string>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ sealed class TokenItemState {
|
|||
val title: TextReference,
|
||||
val onPromoBannerClick: () -> Unit,
|
||||
val onCloseClick: () -> Unit,
|
||||
val onPromoShown: () -> Unit = {},
|
||||
) : PromoBannerState()
|
||||
|
||||
data object Empty : PromoBannerState()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -39,6 +40,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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
|
|
@ -45,6 +41,10 @@ internal class DefaultTangemPayEligibilityManager @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getTangemPayAvailability(): Boolean {
|
||||
return onboardingRepository.checkCustomerEligibility()
|
||||
}
|
||||
|
||||
private suspend fun getUserWalletsData(): List<UserWalletData> {
|
||||
cachedEligibleWallets?.let { return it }
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ internal class DefaultTangemPayEligibilityManager @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun getPossibleWalletsForTangemPay(): List<UserWallet> {
|
||||
if (!onboardingRepository.checkCustomerEligibility()) {
|
||||
if (!checkTangemPayEligibility()) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
|
|
@ -125,6 +125,12 @@ internal class DefaultTangemPayEligibilityManager @Inject constructor(
|
|||
eligibleWalletsDeferred = null
|
||||
}
|
||||
|
||||
private suspend fun checkTangemPayEligibility(): Boolean {
|
||||
if (!tangemPayFeatureToggles.isEntryPointsEnabled) return true
|
||||
|
||||
return onboardingRepository.getCustomerEligibility() || onboardingRepository.checkCustomerEligibility()
|
||||
}
|
||||
|
||||
private data class UserWalletData(
|
||||
val userWallet: UserWallet,
|
||||
val isPaeraCustomer: Boolean,
|
||||
|
|
|
|||
|
|
@ -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<Throwable, TangemPayInitialCredentials> {
|
||||
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<Throwable, WithdrawalSignatureResult> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
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
|
||||
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
|
||||
|
|
@ -22,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
|
||||
|
||||
|
|
@ -109,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")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -180,9 +189,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)
|
||||
|
|
@ -195,7 +205,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 {
|
||||
|
|
@ -205,4 +223,17 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
override suspend fun setHideMainOnboardingBanner(userWalletId: UserWalletId) {
|
||||
tangemPayStorage.storeHideOnboardingBanner(userWalletId, hide = true)
|
||||
}
|
||||
|
||||
override suspend fun disableTangemPay(userWalletId: UserWalletId): Either<VisaApiError, Unit> {
|
||||
return requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.setTangemPayEnabledStatus(
|
||||
authHeader = authHeader,
|
||||
body = SetTangemPayEnabledRequest(isTangemPayEnabled = false),
|
||||
)
|
||||
}.map {
|
||||
val address = requestHelper.getCustomerWalletAddress(userWalletId)
|
||||
tangemPayStorage.clearAll(userWalletId = userWalletId, customerWalletAddress = address)
|
||||
setHideMainOnboardingBanner(userWalletId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<UniversalError, SetPinResult> {
|
||||
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<UniversalError, Boolean> {
|
||||
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<UniversalError, Unit> {
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -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<UserWalletId, String>()
|
||||
private val tokensMutex = Mutex()
|
||||
|
||||
@Deprecated("Do not use this method")
|
||||
suspend fun <T : Any> runWithErrorLogs(tag: String, requestBlock: suspend () -> T): Either<VisaApiError, T> {
|
||||
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 <T : Any> request(
|
||||
userWalletId: UserWalletId,
|
||||
requestBlock: suspend (header: String) ->
|
||||
ApiResponse<T>,
|
||||
): 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 <T : Any> performWithStaticToken(
|
||||
requestBlock: suspend (header: String) -> ApiResponse<T>,
|
||||
): Either<VisaApiError, T> = withContext(dispatchers.io) {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ internal class DefaultWalletsRepository(
|
|||
private val upgradeWalletNotificationDisabled: MutableStateFlow<Set<UserWalletId>> =
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<Boolean> {
|
||||
return appPreferencesStore.get(PreferencesKeys.YIELD_SUPPLY_SHOULD_SHOW_MAIN_PROMO_KEY, true)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -26,9 +26,9 @@ class GetWalletTotalBalanceUseCase(
|
|||
private val walletBalanceCache = ConcurrentHashMap<UserWalletId, TotalFiatBalance.Loaded>()
|
||||
|
||||
operator fun invoke(
|
||||
userTallestIds: Collection<UserWalletId>,
|
||||
userWalletsIds: Collection<UserWalletId>,
|
||||
): LceFlow<TokenListError, Map<UserWalletId, TotalFiatBalance>> {
|
||||
val flows = userTallestIds.distinct()
|
||||
val flows = userWalletsIds.distinct()
|
||||
.map { userWalletId ->
|
||||
invoke(userWalletId).map { maybeBalance ->
|
||||
userWalletId to maybeBalance
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
interface TangemPayEligibilityManager {
|
||||
|
||||
suspend fun getEligibleWallets(shouldExcludePaeraCustomers: Boolean): List<UserWallet>
|
||||
suspend fun getTangemPayAvailability(): Boolean
|
||||
}
|
||||
|
|
@ -26,10 +26,13 @@ interface OnboardingRepository {
|
|||
suspend fun checkCustomerWallet(userWalletId: UserWalletId): Either<VisaApiError, Boolean>
|
||||
|
||||
suspend fun checkCustomerEligibility(): Boolean
|
||||
suspend fun getCustomerEligibility(): Boolean
|
||||
|
||||
fun getSavedCustomerInfo(userWalletId: UserWalletId): CustomerInfo?
|
||||
|
||||
suspend fun getHideMainOnboardingBanner(userWalletId: UserWalletId): Boolean
|
||||
|
||||
suspend fun setHideMainOnboardingBanner(userWalletId: UserWalletId)
|
||||
|
||||
suspend fun disableTangemPay(userWalletId: UserWalletId): Either<VisaApiError, Unit>
|
||||
}
|
||||
|
|
@ -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.*
|
||||
|
|
@ -16,14 +17,11 @@ 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,
|
||||
private val eligibilityManager: TangemPayEligibilityManager,
|
||||
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
||||
private val deviceSecurity: DeviceSecurityInfoProvider,
|
||||
) {
|
||||
|
||||
|
|
@ -46,7 +44,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 +62,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())
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<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")
|
||||
suspend fun saveShouldSaveUserWallets(item: Boolean)
|
||||
|
||||
suspend fun useBiometricAuthentication(): Boolean
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
stakingBalance = 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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -16,12 +16,6 @@ internal data class CreateWalletSelectionUM(
|
|||
val title: TextReference,
|
||||
val titleLabel: LabelUM?,
|
||||
val description: TextReference,
|
||||
val features: ImmutableList<Feature>,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
|
||||
data class Feature(
|
||||
val iconResId: Int,
|
||||
val title: TextReference,
|
||||
)
|
||||
}
|
||||
|
|
@ -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<CreateWalletSelectionUM.Feature>,
|
||||
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 = { },
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -248,13 +248,24 @@ internal class DetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun addTangemPayItemIfEligible() {
|
||||
if (!tangemPayFeatureToggles.isTangemPayEnabled) return
|
||||
if (!tangemPayFeatureToggles.isEntryPointsEnabled) return
|
||||
modelScope.launch {
|
||||
val isEligible = tangemPayEligibilityManager
|
||||
.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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DetailsItemUM>): ImmutableList<DetailsItemUM> {
|
||||
fun addTangemPayItem(items: ImmutableList<DetailsItemUM>, onClick: () -> Unit): ImmutableList<DetailsItemUM> {
|
||||
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,16 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) {
|
|||
}.toImmutableList()
|
||||
}
|
||||
|
||||
fun removeTangemPayItem(items: ImmutableList<DetailsItemUM>): ImmutableList<DetailsItemUM> {
|
||||
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? {
|
||||
return if (isWalletConnectAvailable) {
|
||||
DetailsItemUM.WalletConnect(
|
||||
|
|
@ -126,14 +141,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.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))
|
||||
},
|
||||
onClick = onClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -116,7 +117,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 +135,7 @@ internal class MarketsListModel @Inject constructor(
|
|||
flow3 = shouldShowYieldModeMarketPromoUseCase(
|
||||
appCurrency = currentAppCurrency.value,
|
||||
interval = marketsListUMStateManager.selectedInterval.toBatchRequestInterval(),
|
||||
),
|
||||
).conflate(),
|
||||
flow4 = getUserCountryUseCase.invoke(),
|
||||
) { uiItems, isInInitialLoadingErrorState, shouldShowYieldModePromo, userCountry ->
|
||||
MarketsItemsData(
|
||||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,14 +176,14 @@ private fun ColumnScope.Content(state: MarketsListUM, modifier: Modifier = Modif
|
|||
)
|
||||
}
|
||||
|
||||
val marketsNotification = state.marketsNotificationUM
|
||||
val marketsNotificationUM = state.marketsNotificationUM
|
||||
AnimatedVisibility(
|
||||
state.isInSearchMode.not() &&
|
||||
state.selectedSortBy != SortByTypeUM.YieldSupply,
|
||||
state.list !is ListUM.LoadingError &&
|
||||
state.isInSearchMode.not() && state.selectedSortBy != SortByTypeUM.YieldSupply,
|
||||
) {
|
||||
val showMore = stringResourceSafe(R.string.common_show_more)
|
||||
|
||||
when (marketsNotification) {
|
||||
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 = marketsNotification.config.copy(
|
||||
config = marketsNotificationUM.config.copy(
|
||||
subtitle = clickableDescription,
|
||||
),
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -707,6 +707,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) {
|
||||
|
|
@ -714,7 +719,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
is TxFeeState.MultipleFeeState -> feeState.normalFee.feeValue
|
||||
is TxFeeState.SingleFeeState -> feeState.fee.feeValue
|
||||
},
|
||||
blockchain = currency.network.toBlockchain(),
|
||||
blockchain = blockchain,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ package com.tangem.features.tangempay
|
|||
|
||||
interface TangemPayFeatureToggles {
|
||||
val isTangemPayEnabled: Boolean
|
||||
val isEntryPointsEnabled: Boolean
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<TangemPayView
|
|||
|
||||
override fun transform(prevState: TangemPayViewPinUM): TangemPayViewPinUM {
|
||||
return TangemPayViewPinUM.Error(
|
||||
errorMessage = bottomSheetMessage {
|
||||
errorMessage = messageBottomSheetUM {
|
||||
infoBlock {
|
||||
icon(R.drawable.img_attention_20) {
|
||||
backgroundType = MessageBottomSheetUMV2.Icon.BackgroundType.Attention
|
||||
|
|
@ -26,9 +26,9 @@ internal class TangemPayViewPinErrorStateTransformer : Transformer<TangemPayView
|
|||
}
|
||||
secondaryButton {
|
||||
text = resourceReference(R.string.common_got_it)
|
||||
onClick { closeBs() }
|
||||
onClick { prevState.onDismiss() }
|
||||
}
|
||||
}.messageBottomSheetUMV2,
|
||||
},
|
||||
onDismiss = prevState.onDismiss,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ internal class TokenDetailsNotificationsAnalyticsSender(
|
|||
is TokenDetailsNotification.RequiredTrustlineWarning,
|
||||
is TokenDetailsNotification.KoinosMana,
|
||||
is TokenDetailsNotification.MigrationMaticToPol,
|
||||
is TokenDetailsNotification.MigrationClore,
|
||||
is TokenDetailsNotification.UsedOutdatedData,
|
||||
-> null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ internal class TokenDetailsNotificationConverter(
|
|||
},
|
||||
)
|
||||
is CryptoCurrencyWarning.MigrationMaticToPol -> MigrationMaticToPol
|
||||
is CryptoCurrencyWarning.MigrationClore -> MigrationClore
|
||||
is CryptoCurrencyWarning.UsedOutdatedDataWarning -> UsedOutdatedData
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -677,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(
|
||||
|
|
@ -694,7 +696,7 @@ internal class WalletModel @Inject constructor(
|
|||
)
|
||||
|
||||
action.unlockedWallets.onEach { userWallet ->
|
||||
modelScope.launch { fetchWalletContent(userWallet = userWallet) }
|
||||
fetchWalletContent(userWallet = userWallet)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,24 @@ 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.ToastMessage
|
||||
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
|
||||
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||
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
|
||||
|
|
@ -24,7 +32,11 @@ internal interface TangemPayIntents {
|
|||
|
||||
suspend fun onPullToRefresh()
|
||||
|
||||
fun onRefreshPayToken(userWalletId: UserWalletId)
|
||||
fun onRefreshPayToken(userWallet: UserWallet)
|
||||
|
||||
fun openDetails(userWalletId: UserWalletId, config: TangemPayDetailsConfig)
|
||||
|
||||
fun onKycProgressClicked(userWalletId: UserWalletId)
|
||||
|
||||
fun onIssuingCardClicked()
|
||||
|
||||
|
|
@ -47,6 +59,8 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
private val getWalletMetainfoUseCase: GetWalletMetaInfoUseCase,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val tangemPayMainScreenCustomerInfoUseCase: TangemPayMainScreenCustomerInfoUseCase,
|
||||
private val tangemPayOnboardingRepository: OnboardingRepository,
|
||||
private val tangemPayEligibilityManager: TangemPayEligibilityManager,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
) : BaseWalletClickIntents(), TangemPayIntents {
|
||||
|
||||
|
|
@ -60,13 +74,69 @@ 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) },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
@ -123,7 +193,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) {
|
||||
|
|
@ -132,4 +209,12 @@ internal class TangemPayClickIntentsImplementor @Inject constructor(
|
|||
onboardingRepository.setHideMainOnboardingBanner(userWalletId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun disableTangemPay(userWalletId: UserWalletId) {
|
||||
modelScope.launch {
|
||||
tangemPayOnboardingRepository.disableTangemPay(userWalletId)
|
||||
.onRight { tangemPayMainScreenCustomerInfoUseCase.fetch(userWalletId) }
|
||||
.onLeft { uiMessageSender.send(ToastMessage(resourceReference(R.string.common_something_went_wrong))) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ 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.models.account.Account
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
|
|
@ -24,6 +25,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
|
||||
|
|
@ -61,6 +63,10 @@ internal interface WalletContentClickIntents {
|
|||
|
||||
fun onYieldPromoCloseClick()
|
||||
|
||||
fun onYieldPromoShown(cryptoCurrency: CryptoCurrency)
|
||||
|
||||
fun onYieldPromoClicked(cryptoCurrency: CryptoCurrency)
|
||||
|
||||
fun onAccountExpandClick(account: Account)
|
||||
|
||||
fun onAccountCollapseClick(account: Account)
|
||||
|
|
@ -80,7 +86,7 @@ internal interface WalletContentClickIntents {
|
|||
fun onNFTClick(userWallet: UserWallet)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
@ModelScoped
|
||||
internal class WalletContentClickIntentsImplementor @Inject constructor(
|
||||
private val stateHolder: WalletStateController,
|
||||
|
|
@ -99,6 +105,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() {
|
||||
|
|
@ -204,6 +211,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()
|
||||
analyticsEventHandler.send(MainScreenAnalyticsEvent.AccountShowTokens())
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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<String, Boolean>()
|
||||
private val yieldPromoShownMap = mutableMapOf<String, Boolean>()
|
||||
private val mutex = Mutex()
|
||||
private val loadingTraces = mutableMapOf<UserWalletId, Trace>()
|
||||
|
||||
|
|
@ -206,6 +208,7 @@ internal class TokenListAnalyticsSender @Inject constructor(
|
|||
}
|
||||
|
||||
analyticsEventHandler.send(Basic.WalletToppedUp(userWallet.walletId, walletType))
|
||||
analyticsEventHandler.send(Basic.AppsFlyerWalletFunded(userWallet.walletId))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +236,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"
|
||||
|
|
|
|||
|
|
@ -151,15 +151,18 @@ 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,
|
||||
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),
|
||||
buttonsState = ButtonsState.PrimaryButtonConfig(
|
||||
text = resourceReference(id = R.string.home_button_scan),
|
||||
text = buttonText,
|
||||
iconResId = tangemIcon,
|
||||
onClick = onRefreshClick,
|
||||
shouldShowProgress = shouldShowProgress,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,7 +18,12 @@ 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,
|
||||
shouldShowProgress = false,
|
||||
),
|
||||
)
|
||||
return if (prevState is WalletState.MultiCurrency.Content) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue