Updated on 2026-08-14
This commit is contained in:
commit
f05063eed2
12 changed files with 90 additions and 64 deletions
|
|
@ -6,7 +6,7 @@ import com.tangem.operations.backup.BackupService
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun BackupService.primaryCardIsSaltPay(): Boolean {
|
||||
fun BackupService.primaryCardIsSaltPayVisa(): Boolean {
|
||||
return primaryCardId?.slice(0..3)?.let {
|
||||
SaltPayWorkaround.isVisaBatchId(it)
|
||||
} ?: false
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import android.webkit.WebView
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun WebView.configureSettings() {
|
||||
resumeTimers()
|
||||
settings.apply {
|
||||
javaScriptEnabled = true
|
||||
domStorageEnabled = true
|
||||
|
|
@ -15,5 +16,4 @@ fun WebView.configureSettings() {
|
|||
fun WebView.stop() {
|
||||
stopLoading()
|
||||
pauseTimers()
|
||||
destroy()
|
||||
}
|
||||
|
|
@ -140,7 +140,10 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
|
|||
secretKey = moonPaySecretKey,
|
||||
logEnabled = LogConfig.network.moonPayService,
|
||||
)
|
||||
val cardProvider = { store.state.globalState.scanResponse?.card }
|
||||
val cardProvider = {
|
||||
store.state.globalState.scanResponse?.card
|
||||
?: store.state.globalState.onboardingState.onboardingManager?.scanResponse?.card
|
||||
}
|
||||
|
||||
val exchangeManager = CurrencyExchangeManager(
|
||||
buyService = buyService,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class DetailsViewModel(private val store: Store<AppState>) {
|
|||
SettingsElement.WalletConnect -> {
|
||||
if (state.scanResponse?.card?.isMultiwalletAllowed == true) it else null
|
||||
}
|
||||
SettingsElement.Chat -> if (state.scanResponse?.card?.isSaltPay != true) it else null
|
||||
SettingsElement.SendFeedback -> if (state.scanResponse?.card?.isSaltPay != true) it else null
|
||||
SettingsElement.LinkMoreCards -> {
|
||||
// if (state.createBackupAllowed) it else null
|
||||
// TODO: SaltPay: temporary excluding backup process for Visa cards
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.extensions.withIOContext
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.operations.backup.BackupService
|
||||
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
|
||||
import com.tangem.tap.backupService
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.AnalyticsEventAnOld
|
||||
import com.tangem.tap.common.analytics.AnalyticsParamAnOld
|
||||
|
|
@ -15,6 +18,7 @@ import com.tangem.tap.common.entities.IndeterminateProgressButton
|
|||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||
import com.tangem.tap.common.extensions.onCardScanned
|
||||
import com.tangem.tap.common.extensions.primaryCardIsSaltPayVisa
|
||||
import com.tangem.tap.common.postUiDelayBg
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -84,6 +88,7 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch
|
|||
onSuccess = { scanResponse ->
|
||||
store.dispatch(HomeAction.ScanInProgress(false))
|
||||
checkForUnfinishedBackupForSaltPay(
|
||||
backupService = backupService,
|
||||
scanResponse = scanResponse,
|
||||
nextHandler = {
|
||||
showDisclaimerIfNeed(
|
||||
|
|
@ -116,13 +121,23 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch
|
|||
* see BackupAction.CheckForUnfinishedBackup
|
||||
* If user touches card other than Visa SaltPay - show dialog and block next processing
|
||||
*/
|
||||
private fun checkForUnfinishedBackupForSaltPay(scanResponse: ScanResponse, nextHandler: (ScanResponse) -> Unit) {
|
||||
if (BackupAction.hasSaltPayUnfinishedBackup()) {
|
||||
if (scanResponse.isSaltPayVisa()) {
|
||||
nextHandler(scanResponse)
|
||||
} else {
|
||||
showSaltPayTapVisaLogoCardDialog()
|
||||
}
|
||||
private fun checkForUnfinishedBackupForSaltPay(
|
||||
backupService: BackupService,
|
||||
scanResponse: ScanResponse,
|
||||
nextHandler: (ScanResponse) -> Unit,
|
||||
) {
|
||||
if (!backupService.hasIncompletedBackup || !backupService.primaryCardIsSaltPayVisa()) {
|
||||
nextHandler(scanResponse)
|
||||
return
|
||||
}
|
||||
|
||||
fun isTheSamePrimaryCard(card: Card): Boolean {
|
||||
return backupService.primaryCardId?.let { it == card.cardId } ?: false
|
||||
}
|
||||
|
||||
if (scanResponse.isSaltPayWallet() || !isTheSamePrimaryCard(scanResponse.card)) {
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
showSaltPayTapVisaLogoCardDialog()
|
||||
} else {
|
||||
nextHandler(scanResponse)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayActivat
|
|||
import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError
|
||||
import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.SaltPayActivationStep
|
||||
import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.update
|
||||
import com.tangem.tap.preferencesStorage
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -19,10 +20,16 @@ class OnboardingSaltPayHelper {
|
|||
manager: SaltPayActivationManager,
|
||||
): Result<Boolean> {
|
||||
return try {
|
||||
val updatedStep = manager.update(SaltPayActivationStep.None, null).successOr { return it }
|
||||
val isRegistrationCase = updatedStep != SaltPayActivationStep.Finished
|
||||
var updatedStep = manager.update(SaltPayActivationStep.None, null).successOr { return it }
|
||||
|
||||
val cardStorage = preferencesStorage.usedCardsPrefStorage
|
||||
val activationIsFinished = cardStorage.isActivationFinished(scanResponse.card.cardId)
|
||||
if (updatedStep == SaltPayActivationStep.Success && activationIsFinished) {
|
||||
updatedStep = SaltPayActivationStep.Finished
|
||||
}
|
||||
val isActivationCase = updatedStep != SaltPayActivationStep.Finished
|
||||
val isBackupCase = scanResponse.card.backupStatus?.isActive == false
|
||||
Result.Success(isRegistrationCase || isBackupCase)
|
||||
Result.Success(isActivationCase || isBackupCase)
|
||||
} catch (ex: Exception) {
|
||||
Result.Failure(ex)
|
||||
} catch (error: SaltPayActivationError) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.redux
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.tangem.tap.backupService
|
||||
import com.tangem.tap.common.extensions.primaryCardIsSaltPay
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class OnboardingWalletAction : Action {
|
||||
|
|
@ -70,10 +68,4 @@ sealed class BackupAction : Action {
|
|||
object DiscardBackup : BackupAction()
|
||||
object DiscardSavedBackup : BackupAction()
|
||||
object ResumeFoundUnfinishedBackup : BackupAction()
|
||||
|
||||
companion object {
|
||||
fun hasSaltPayUnfinishedBackup(): Boolean {
|
||||
return backupService.hasIncompletedBackup && backupService.primaryCardIsSaltPay()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import com.tangem.tap.common.analytics.Analytics
|
|||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.primaryCardIsSaltPay
|
||||
import com.tangem.tap.common.extensions.primaryCardIsSaltPayVisa
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
|
|
@ -328,7 +328,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
backupService.discardSavedBackup()
|
||||
}
|
||||
is BackupAction.CheckForUnfinishedBackup -> {
|
||||
if (backupService.hasIncompletedBackup && !backupService.primaryCardIsSaltPay()) {
|
||||
if (backupService.hasIncompletedBackup && !backupService.primaryCardIsSaltPayVisa()) {
|
||||
store.dispatch(GlobalAction.ShowDialog(BackupDialog.UnfinishedBackupFound))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ private class BackupReducer {
|
|||
is BackupAction.IntroduceBackup -> BackupState(
|
||||
backupStep = BackupStep.InitBackup,
|
||||
maxBackupCards = if (isSaltPay) 1 else 2,
|
||||
canSkipBackup = !isSaltPay,
|
||||
canSkipBackup = state.canSkipBackup,
|
||||
)
|
||||
BackupAction.StartAddingPrimaryCard -> state.copy(backupStep = BackupStep.ScanOriginCard)
|
||||
BackupAction.StartAddingBackupCards -> {
|
||||
|
|
|
|||
|
|
@ -300,12 +300,17 @@ private fun determineStep(
|
|||
amountToClaim: Amount?,
|
||||
response: RegistrationResponse.Item,
|
||||
): SaltPayActivationStep {
|
||||
fun getStepBaseOnAmountToClaim(amount: Amount?): SaltPayActivationStep = when (amount) {
|
||||
null -> SaltPayActivationStep.Success
|
||||
else -> SaltPayActivationStep.Claim
|
||||
}
|
||||
|
||||
return when {
|
||||
response.passed != true -> throw SaltPayActivationError.CardNotPassed(response.error)
|
||||
response.disabledByAdmin == true -> throw SaltPayActivationError.CardDisabled(response.error)
|
||||
|
||||
// go to claim screen
|
||||
response.active == true -> SaltPayActivationStep.Claim
|
||||
response.active == true -> getStepBaseOnAmountToClaim(amountToClaim)
|
||||
|
||||
// pinSet is false, go toPin screen
|
||||
response.pinSet == false -> SaltPayActivationStep.NeedPin
|
||||
|
|
@ -316,10 +321,7 @@ private fun determineStep(
|
|||
KYCStatus.NOT_STARTED, KYCStatus.STARTED -> SaltPayActivationStep.KycIntro
|
||||
KYCStatus.WAITING_FOR_APPROVAL -> SaltPayActivationStep.KycWaiting
|
||||
KYCStatus.CORRECTION_REQUESTED, KYCStatus.REJECTED -> SaltPayActivationStep.KycReject
|
||||
KYCStatus.APPROVED -> when (amountToClaim) {
|
||||
null -> SaltPayActivationStep.Success
|
||||
else -> SaltPayActivationStep.Claim
|
||||
}
|
||||
KYCStatus.APPROVED -> getStepBaseOnAmountToClaim(amountToClaim)
|
||||
else -> SaltPayActivationStep.KycIntro
|
||||
}
|
||||
SaltPayActivationStep.KycReject -> when (response.kycStatus) {
|
||||
|
|
@ -327,20 +329,14 @@ private fun determineStep(
|
|||
KYCStatus.WAITING_FOR_APPROVAL -> SaltPayActivationStep.KycWaiting
|
||||
KYCStatus.CORRECTION_REQUESTED -> SaltPayActivationStep.KycStart
|
||||
KYCStatus.REJECTED -> SaltPayActivationStep.KycStart
|
||||
KYCStatus.APPROVED -> when (amountToClaim) {
|
||||
null -> SaltPayActivationStep.Success
|
||||
else -> SaltPayActivationStep.Claim
|
||||
}
|
||||
KYCStatus.APPROVED -> getStepBaseOnAmountToClaim(amountToClaim)
|
||||
else -> SaltPayActivationStep.KycIntro
|
||||
}
|
||||
else -> when (response.kycStatus) {
|
||||
KYCStatus.NOT_STARTED, KYCStatus.STARTED -> SaltPayActivationStep.KycIntro
|
||||
KYCStatus.WAITING_FOR_APPROVAL -> SaltPayActivationStep.KycWaiting
|
||||
KYCStatus.CORRECTION_REQUESTED, KYCStatus.REJECTED -> SaltPayActivationStep.KycReject
|
||||
KYCStatus.APPROVED -> when (amountToClaim) {
|
||||
null -> SaltPayActivationStep.Finished
|
||||
else -> SaltPayActivationStep.Claim
|
||||
}
|
||||
KYCStatus.APPROVED -> getStepBaseOnAmountToClaim(amountToClaim)
|
||||
else -> SaltPayActivationStep.KycIntro
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,16 +38,6 @@ class WalletBackupAnimator(
|
|||
override fun updateBackupState(backupState: BackupState) {
|
||||
}
|
||||
|
||||
override fun setupCreateWalletState() {
|
||||
currentStep = STEP_CREATE_WALLET
|
||||
|
||||
cardsWidget.toFolded(false)
|
||||
|
||||
ORIGIN.alpha(1f)
|
||||
FIRST_BACKUP.alpha(1f)
|
||||
SECOND_BACKUP.alpha(1f)
|
||||
}
|
||||
|
||||
override fun showBackupIntro(state: BackupState) {
|
||||
currentStep = STEP_BACKUP_INTRO
|
||||
|
||||
|
|
@ -58,6 +48,16 @@ class WalletBackupAnimator(
|
|||
cardsWidget.toWelcome()
|
||||
}
|
||||
|
||||
override fun setupCreateWalletState() {
|
||||
currentStep = STEP_CREATE_WALLET
|
||||
|
||||
cardsWidget.toFolded(false)
|
||||
|
||||
ORIGIN.alpha(1f)
|
||||
FIRST_BACKUP.alpha(1f)
|
||||
SECOND_BACKUP.alpha(1f)
|
||||
}
|
||||
|
||||
override fun showScanOriginCard() {
|
||||
currentStep = STEP_SCAN_ORIGIN_CARD
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ class WalletBackupAnimator(
|
|||
SECOND_BACKUP.animateAlpha(0.2f, 400)
|
||||
}
|
||||
STEP_BACKUP_INTRO -> {
|
||||
cardsWidget.toFolded(duration = 200) { cardsWidget.toFan() }
|
||||
cardsWidget.toFolded(duration = 300) { cardsWidget.toFan() }
|
||||
FIRST_BACKUP.animateAlpha(0.6f, 400, 250)
|
||||
SECOND_BACKUP.animateAlpha(0.2f, 400, 250)
|
||||
}
|
||||
|
|
@ -112,11 +112,14 @@ class WalletBackupAnimator(
|
|||
)
|
||||
}
|
||||
|
||||
override fun showWriteBackupCard(state: BackupState, backupCard: Int) {
|
||||
private var firstBackupCardAnimated = false
|
||||
private var secondBackupCardAnimated = false
|
||||
|
||||
override fun showWriteBackupCard(state: BackupState, backupCard: Int) {
|
||||
when (viewState) {
|
||||
State.TwoCards -> {
|
||||
if (currentStep == STEP_WRITE_BACKUP_CARD) return
|
||||
if (firstBackupCardAnimated) return
|
||||
firstBackupCardAnimated = true
|
||||
|
||||
val delay = if (currentStep == UNDEFINED) 700L else 0
|
||||
postUiDelayBg(delay) {
|
||||
|
|
@ -129,6 +132,8 @@ class WalletBackupAnimator(
|
|||
State.TreeCards -> {
|
||||
when (backupCard) {
|
||||
1 -> {
|
||||
if (firstBackupCardAnimated) return
|
||||
firstBackupCardAnimated = true
|
||||
FIRST_BACKUP.alpha(1f)
|
||||
cardsWidget.leapfrogWidget.leap {
|
||||
SECOND_BACKUP.alpha(0.4f)
|
||||
|
|
@ -136,6 +141,8 @@ class WalletBackupAnimator(
|
|||
}
|
||||
}
|
||||
2 -> {
|
||||
if (secondBackupCardAnimated) return
|
||||
secondBackupCardAnimated = true
|
||||
SECOND_BACKUP.alpha(1f)
|
||||
cardsWidget.leapfrogWidget.leap {
|
||||
ORIGIN.alpha(0.4f)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.common.json.MoshiJsonConverter
|
|||
import com.tangem.domain.AddCustomTokenError
|
||||
import com.tangem.domain.DomainWrapped
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.domain.common.extensions.isSupportedInApp
|
||||
import com.tangem.domain.common.extensions.supportedBlockchains
|
||||
import com.tangem.domain.common.extensions.supportedTokens
|
||||
import com.tangem.domain.common.form.CustomTokenValidator
|
||||
|
|
@ -50,7 +51,7 @@ data class AddCustomTokenState(
|
|||
val foundToken: CoinsResponse.Coin? = null,
|
||||
val warnings: Set<AddCustomTokenError.Warning> = emptySet(),
|
||||
val screenState: ScreenState = createInitialScreenState(),
|
||||
val tangemTechServiceManager: AddCustomTokenService? = null
|
||||
val tangemTechServiceManager: AddCustomTokenService? = null,
|
||||
) : StateType {
|
||||
|
||||
inline fun <reified T> getField(id: FieldId): T = form.getField(id) as T
|
||||
|
|
@ -171,7 +172,7 @@ data class AddCustomTokenState(
|
|||
internal fun getDerivationPath(
|
||||
mainNetwork: Blockchain,
|
||||
derivationNetwork: Blockchain,
|
||||
derivationStyle: DerivationStyle?
|
||||
derivationStyle: DerivationStyle?,
|
||||
): com.tangem.common.hdWallet.DerivationPath? {
|
||||
// If we allow user to select derivations, we need to provide different derivations
|
||||
// (Legacy style derivations).
|
||||
|
|
@ -239,9 +240,10 @@ data class AddCustomTokenState(
|
|||
}
|
||||
|
||||
private fun getSupportedDerivations(card: Card): List<Blockchain> {
|
||||
val evmBlockchains = Blockchain.values().filter {
|
||||
card.isTestCard == it.isTestnet() && it.isEvm()
|
||||
}
|
||||
val evmBlockchains = Blockchain.values()
|
||||
.filter { card.isTestCard == it.isTestnet() && it.isEvm() }
|
||||
.filter { it.isSupportedInApp() }
|
||||
|
||||
return (listOf(Blockchain.Unknown) + evmBlockchains).sortByName()
|
||||
}
|
||||
|
||||
|
|
@ -266,14 +268,18 @@ data class AddCustomTokenState(
|
|||
val action = (action as? AddCustomTokenAction) ?: return null
|
||||
|
||||
val state = stateHolder.addCustomTokensState
|
||||
val fieldConverter = FieldToJsonConverter(listOf(
|
||||
ContractAddress,
|
||||
Network,
|
||||
Name,
|
||||
Symbol,
|
||||
Decimals,
|
||||
DerivationPath,
|
||||
), jsonConverter)
|
||||
val fieldConverter =
|
||||
FieldToJsonConverter(
|
||||
listOf(
|
||||
ContractAddress,
|
||||
Network,
|
||||
Name,
|
||||
Symbol,
|
||||
Decimals,
|
||||
DerivationPath,
|
||||
),
|
||||
jsonConverter,
|
||||
)
|
||||
state.visitDataConverter(fieldConverter)
|
||||
val errors = state.formErrors.map {
|
||||
"${it.key}: ${it.value::class.java.simpleName}"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue