Updated on 2026-08-14
This commit is contained in:
parent
0a442d0a72
commit
5299629221
21 changed files with 111 additions and 3 deletions
|
|
@ -694,6 +694,7 @@
|
|||
<string name="scan_card_settings_message">Отсканируйте карту или кольцо, чтобы изменить ее настройки. Изменения затронут только ту карту или кольцо, которые вы отсканировали, и не повлияют на другие устройства, привязанные к вашему кошельку.</string>
|
||||
<string name="scan_card_settings_title">Приготовьте свой Tangem!</string>
|
||||
<string name="security_alert_title">Уведомление безопасности</string>
|
||||
<string name="seed_warning_yes">Да</string>
|
||||
<string name="selling_insufficient_balance_alert_message">На вашем балансе недостаточно средств для продажи криптовалюты. Пожалуйста, пополните нужный актив, чтобы продолжить.</string>
|
||||
<string name="selling_insufficient_balance_alert_title">Недостаточно средств</string>
|
||||
<string name="selling_regional_restriction_alert_message">Продажа криптовалюты в вашем регионе временно недоступна. Мы активно работаем над тем, чтобы добавить эту возможность. Следите за нашими новостями!</string>
|
||||
|
|
@ -897,6 +898,8 @@
|
|||
<string name="story_meet_title">Встречайте Tangem</string>
|
||||
<string name="story_web3_description">Обменивайте, покупайте NFT, получайте займы и делайте вклады в более чем 100 различных децентрализованных сервисах</string>
|
||||
<string name="story_web3_title">Поддержка Web 3.0</string>
|
||||
<string name="sui_not_enough_coin_for_fee_description">Для отправки требуется входящая транзакция на сумму не менее %1$s</string>
|
||||
<string name="sui_not_enough_coin_for_fee_title">Недостаточно средств</string>
|
||||
<string name="swap_give_permission_fee_footer">Комиссия сети за одобрение токена будет взиматься за подтверждение того, что именно вы разрешаете использовать ваш токен для обмена.</string>
|
||||
<string name="swap_promo_text">Обменивайте больше токенов по лучшим курсам прямо в вашем кошельке.</string>
|
||||
<string name="swap_promo_title">Новый провайдер обмена!</string>
|
||||
|
|
@ -1110,6 +1113,7 @@
|
|||
<string name="warning_rate_app_title">Нравится Tangem?</string>
|
||||
<string name="warning_receive_blocked_hedera_token_association_required_message">Вам необходимо провести ассоциацию токена для того, чтобы иметь возможность принимать его</string>
|
||||
<string name="warning_rent_fee_title">Необходима плата за аренду сети</string>
|
||||
<string name="warning_seedphrase_contacted_support">Вы обращались в службу поддержки через приложение в течение 7 дней после создания кошелька? Если обращались или не уверены, нажмите «Да» и следуйте инструкциям.</string>
|
||||
<string name="warning_seedphrase_issue_answer_no">Спасибо! Всё в порядке! Дальнейшие действия не требуются.</string>
|
||||
<string name="warning_seedphrase_issue_answer_yes">Вы будете перенаправлены на официальный сайт Tangem. Пожалуйста, прочитайте и выполните указанные там инструкции.</string>
|
||||
<string name="warning_seedphrase_issue_message">Вы когда-либо обращались в службу поддержки Tangem напрямую из этого приложения?</string>
|
||||
|
|
|
|||
|
|
@ -886,6 +886,8 @@
|
|||
<string name="story_meet_title">Meet Tangem</string>
|
||||
<string name="story_web3_description">Exchange, buy NFT\'s, make loans and deposits in more than 100 different decentralized services</string>
|
||||
<string name="story_web3_title">Web 3.0 Compatible</string>
|
||||
<string name="sui_not_enough_coin_for_fee_description">An incoming transaction of at least %1$s is required to proceed</string>
|
||||
<string name="sui_not_enough_coin_for_fee_title">Insufficient funds</string>
|
||||
<string name="swap_give_permission_fee_footer">The network will charge a token approval fee to verify that you are authorizing the use of your token for the swap.</string>
|
||||
<string name="swap_promo_text">Exchange more tokens at better rates directly in your wallet.</string>
|
||||
<string name="swap_promo_title">New Swap Provider Available!</string>
|
||||
|
|
@ -985,6 +987,9 @@
|
|||
<string name="user_wallet_list_rename_popup_title">Rename wallet</string>
|
||||
<string name="user_wallet_list_unlock_all">Unlock all</string>
|
||||
<string name="user_wallet_list_unlock_all_with">Unlock all with %s</string>
|
||||
<string name="visa_unlock_notification_button">Unlock</string>
|
||||
<string name="visa_unlock_notification_subtitle">Scan your card to unlock access</string>
|
||||
<string name="visa_unlock_notification_title">Needed unlock</string>
|
||||
<string name="wallet_balance_blockchain_unreachable_try_later">Blockchain is unreachable. Try later</string>
|
||||
<string name="wallet_balance_missing_derivation">Scan card or ring</string>
|
||||
<string name="wallet_been_activated_message">This wallet has already been activated earlier.\nIf it was not done by you, please contact support.\nTangem never sells wallets along with pre-generated access codes.</string>
|
||||
|
|
@ -1099,7 +1104,7 @@
|
|||
<string name="warning_receive_blocked_hedera_token_association_required_message">You must associate your token before receiving tokens</string>
|
||||
<string name="warning_rent_fee_title">Network rent fee required</string>
|
||||
<string name="warning_seedphrase_action_required_title">Action required</string>
|
||||
<string name="warning_seedphrase_contacted_support">Did you contact support via the app or email within 7 days of creating a wallet? If you did or are unsure, follow and complete the instructions.</string>
|
||||
<string name="warning_seedphrase_contacted_support">Did you contact support via the app within 7 days of creating your wallet? If yes, or if you\'re unsure, click \'Yes\' and follow the instructions.</string>
|
||||
<string name="warning_seedphrase_issue_answer_no">Thank you! All set! No further actions required.</string>
|
||||
<string name="warning_seedphrase_issue_answer_yes">You will now be redirected to the official Tangem website. Please read and follow instructions there.</string>
|
||||
<string name="warning_seedphrase_issue_message">Have you ever contacted the Tangem support team directly through this application?</string>
|
||||
|
|
|
|||
|
|
@ -91,6 +91,11 @@ internal class VisaApiRequestMaker @Inject constructor(
|
|||
private suspend fun getAuthTokens(userWalletId: UserWalletId): VisaAuthTokens {
|
||||
val userWallet = findVisaUserWallet(userWalletId)
|
||||
val status = userWallet.scanResponse.visaCardActivationStatus ?: error("Visa card activation status not found")
|
||||
|
||||
if (status is VisaCardActivationStatus.RefreshTokenExpired) {
|
||||
throw RefreshTokenExpiredException()
|
||||
}
|
||||
|
||||
return (status as? VisaCardActivationStatus.Activated)?.visaAuthTokens ?: error("Visa card is not activated")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
|
|||
is WalletNotification.Warning.SomeNetworksUnreachable,
|
||||
is WalletNotification.Warning.NetworksUnreachable,
|
||||
is WalletNotification.UsedOutdatedData,
|
||||
is WalletNotification.UnlockVisaAccess,
|
||||
-> null
|
||||
is WalletNotification.Critical.SeedPhraseNotification -> MainScreen.NoticeSeedPhraseSupport
|
||||
is WalletNotification.Critical.SeedPhraseSecondNotification -> MainScreen.NoticeSeedPhraseSupportSecond
|
||||
|
|
|
|||
|
|
@ -191,6 +191,19 @@ sealed class WalletNotification(val config: NotificationConfig) {
|
|||
),
|
||||
)
|
||||
|
||||
data class UnlockVisaAccess(val onUnlockClick: () -> Unit) : WalletNotification(
|
||||
config = NotificationConfig(
|
||||
title = resourceReference(id = R.string.visa_unlock_notification_title),
|
||||
subtitle = resourceReference(id = R.string.visa_unlock_notification_subtitle),
|
||||
iconResId = R.drawable.ic_locked_24,
|
||||
buttonsState = NotificationConfig.ButtonsState.PrimaryButtonConfig(
|
||||
text = resourceReference(id = R.string.visa_unlock_notification_button),
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
onClick = onUnlockClick,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
data class RateApp(
|
||||
val onLikeClick: () -> Unit,
|
||||
val onDislikeClick: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.holder.TxHistor
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.model.holder.WalletStateHolder
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal const val NOT_INITIALIZED_WALLET_INDEX = -1
|
||||
|
||||
|
|
@ -115,5 +116,27 @@ internal sealed interface WalletState : WalletStateHolder {
|
|||
|
||||
override val balancesAndLimitBlockState: BalancesAndLimitsBlockState? = null
|
||||
}
|
||||
|
||||
data class AccessTokenLocked(
|
||||
override val walletCardState: WalletCardState,
|
||||
override val buttons: PersistentList<WalletManageButton>,
|
||||
override val bottomSheetConfig: TangemBottomSheetConfig?,
|
||||
val onExploreClick: () -> Unit,
|
||||
val onUnlockVisaAccessNotificationClick: () -> Unit,
|
||||
) : Visa(),
|
||||
TxHistoryStateHolder by LockedTxHistoryStateHolder(onExploreClick),
|
||||
WalletStateHolder by LockedWalletStateHolder(
|
||||
walletCardState = walletCardState,
|
||||
buttons = buttons,
|
||||
bottomSheetConfig = bottomSheetConfig,
|
||||
onUnlockNotificationClick = {},
|
||||
) {
|
||||
|
||||
override val warnings: ImmutableList<WalletNotification> = persistentListOf(
|
||||
WalletNotification.UnlockVisaAccess(onUnlockClick = onUnlockVisaAccessNotificationClick),
|
||||
)
|
||||
|
||||
override val balancesAndLimitBlockState: BalancesAndLimitsBlockState? = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,9 @@ internal class CloseBottomSheetTransformer(userWalletId: UserWalletId) : WalletS
|
|||
is WalletState.Visa.Locked -> prevState.copy(
|
||||
bottomSheetConfig = updateConfig(prevState),
|
||||
)
|
||||
is WalletState.Visa.AccessTokenLocked -> prevState.copy(
|
||||
bottomSheetConfig = updateConfig(prevState),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ internal class OpenBottomSheetTransformer(
|
|||
is WalletState.Visa.Locked -> prevState.copy(
|
||||
bottomSheetConfig = updateConfig(),
|
||||
)
|
||||
is WalletState.Visa.AccessTokenLocked -> prevState.copy(
|
||||
bottomSheetConfig = updateConfig(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ internal class RenameWalletsTransformer(
|
|||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> {
|
||||
Timber.e("Impossible to rename wallet in locked state")
|
||||
prevState
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.core.ui.format.bigdecimal.crypto
|
|||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.common.util.getCardsCount
|
||||
import com.tangem.domain.visa.exception.RefreshTokenExpiredException
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.BalancesAndLimitsBlockState
|
||||
|
|
@ -29,6 +30,10 @@ internal class SetBalancesAndLimitsTransformer(
|
|||
|
||||
override fun transformTyped(prevState: WalletState.Visa.Content): WalletState {
|
||||
val visaCurrency = maybeVisaCurrency.getOrElse {
|
||||
if (it is RefreshTokenExpiredException) {
|
||||
return getRefreshTokenExpiredState(prevState)
|
||||
}
|
||||
|
||||
return prevState.copy(
|
||||
walletCardState = getErrorWalletCardState(prevState.walletCardState),
|
||||
depositButtonState = prevState.depositButtonState.copy(isEnabled = false),
|
||||
|
|
@ -100,4 +105,14 @@ internal class SetBalancesAndLimitsTransformer(
|
|||
|
||||
return WalletAdditionalInfo(hideable = true, infoContent)
|
||||
}
|
||||
|
||||
private fun getRefreshTokenExpiredState(prevState: WalletState.Visa.Content): WalletState {
|
||||
return WalletState.Visa.AccessTokenLocked(
|
||||
walletCardState = prevState.walletCardState,
|
||||
buttons = prevState.buttons,
|
||||
bottomSheetConfig = prevState.bottomSheetConfig,
|
||||
onExploreClick = clickIntents::onExploreClick,
|
||||
onUnlockVisaAccessNotificationClick = clickIntents::onUnlockVisaAccessClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@ internal class SetRefreshStateTransformer(
|
|||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> prevState
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ internal class SetTxHistoryCountErrorTransformer(
|
|||
is WalletState.Visa.Content -> prevState.copy(txHistoryState = createErrorState())
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> {
|
||||
Timber.w("Impossible to load transactions history for locked wallet")
|
||||
prevState
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ internal class SetTxHistoryCountTransformer(
|
|||
)
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> {
|
||||
Timber.w("Impossible to load transactions history for locked wallet")
|
||||
prevState
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
|||
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.domain.txhistory.models.TxHistoryListError
|
||||
import com.tangem.domain.visa.exception.RefreshTokenExpiredException
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
|
||||
|
|
@ -16,9 +17,10 @@ internal class SetTxHistoryItemsErrorTransformer(
|
|||
override fun transform(prevState: WalletState): WalletState {
|
||||
return when (prevState) {
|
||||
is WalletState.SingleCurrency.Content -> prevState.copy(txHistoryState = createErrorState())
|
||||
is WalletState.Visa.Content -> prevState.copy(txHistoryState = createErrorState())
|
||||
is WalletState.Visa.Content -> transformVisaContent(prevState)
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> {
|
||||
Timber.w("Impossible to load transactions history for locked wallet")
|
||||
prevState
|
||||
|
|
@ -30,6 +32,20 @@ internal class SetTxHistoryItemsErrorTransformer(
|
|||
}
|
||||
}
|
||||
|
||||
private fun transformVisaContent(prevState: WalletState.Visa.Content): WalletState {
|
||||
return if (error.cause is RefreshTokenExpiredException) {
|
||||
WalletState.Visa.AccessTokenLocked(
|
||||
walletCardState = prevState.walletCardState,
|
||||
buttons = prevState.buttons,
|
||||
bottomSheetConfig = prevState.bottomSheetConfig,
|
||||
onExploreClick = clickIntents::onExploreClick,
|
||||
onUnlockVisaAccessNotificationClick = clickIntents::onUnlockVisaAccessClick,
|
||||
)
|
||||
} else {
|
||||
prevState.copy(txHistoryState = createErrorState())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createErrorState(): TxHistoryState.Error = when (error) {
|
||||
is TxHistoryListError.DataError -> {
|
||||
TxHistoryState.Error(
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ internal class SetTxHistoryItemsTransformer(
|
|||
)
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> {
|
||||
Timber.w("Impossible to load transactions history for locked wallet")
|
||||
prevState
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ internal class SetWalletCardDropDownItemsTransformer(
|
|||
dropDownItems = constructDropDownItems(prevState.walletCardState.id),
|
||||
),
|
||||
)
|
||||
is WalletState.Visa.AccessTokenLocked -> prevState.copy(
|
||||
walletCardState = prevState.walletCardState.copySealed(
|
||||
dropDownItems = constructDropDownItems(prevState.walletCardState.id),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ internal class SetWarningsTransformer(
|
|||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> {
|
||||
Timber.w("Impossible to update notifications for locked wallet")
|
||||
prevState
|
||||
|
|
|
|||
|
|
@ -50,8 +50,9 @@ internal class UnlockWalletTransformer(
|
|||
is WalletState.MultiCurrency.Content,
|
||||
is WalletState.SingleCurrency.Content,
|
||||
is WalletState.Visa.Content,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> {
|
||||
Timber.e("Impossible to unlock wallet with content state")
|
||||
Timber.e("Impossible to unlock wallet with not locked state")
|
||||
prevState
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ internal class UpdateWalletCardsCountTransformer(
|
|||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> {
|
||||
Timber.e("Impossible to update wallet cards count for locked wallet")
|
||||
prevState
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ internal class WalletClickIntents @Inject constructor(
|
|||
is WalletState.MultiCurrency.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.Visa.AccessTokenLocked,
|
||||
-> Unit
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ internal interface WalletWarningsClickIntents {
|
|||
|
||||
fun onUnlockWalletClick()
|
||||
|
||||
fun onUnlockVisaAccessClick()
|
||||
|
||||
fun onScanToUnlockWalletClick()
|
||||
|
||||
fun onLikeAppClick()
|
||||
|
|
@ -176,6 +178,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onUnlockVisaAccessClick() {
|
||||
openScanCardDialog()
|
||||
}
|
||||
|
||||
private fun handleUnlockWalletsError(error: UnlockWalletsError) {
|
||||
val event = when (error) {
|
||||
is UnlockWalletsError.DataError,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue