diff --git a/app/src/main/java/com/tangem/tap/common/extensions/BackupService.kt b/app/src/main/java/com/tangem/tap/common/extensions/BackupService.kt index 90610b1620..abe1863c6d 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/BackupService.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/BackupService.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/common/extensions/WebView.kt b/app/src/main/java/com/tangem/tap/common/extensions/WebView.kt index ebe938a1ec..7aa93b2bb1 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/WebView.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/WebView.kt @@ -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() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt index bd346b13a6..ff550afa05 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt @@ -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, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt index 53947f62e9..1de39fa063 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt @@ -25,7 +25,7 @@ class DetailsViewModel(private val store: Store) { 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 diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index 5f77bee19f..5a4e3d2ca2 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -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) } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingSaltPayHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingSaltPayHelper.kt index 512dfcc173..209fc789eb 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingSaltPayHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingSaltPayHelper.kt @@ -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 { 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) { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt index 728e86280e..f3ff070f97 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt @@ -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() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index ebdae723ea..4e34f48b54 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -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)) } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt index e90b69a31a..8cca79e9dd 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt @@ -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 -> { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index ea6bec2c95..90c9d33f06 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -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 } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt index 3621bbcfa4..d57205ce46 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt @@ -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) diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt index 2ecd595e8e..28b821f2ab 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt @@ -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 = emptySet(), val screenState: ScreenState = createInitialScreenState(), - val tangemTechServiceManager: AddCustomTokenService? = null + val tangemTechServiceManager: AddCustomTokenService? = null, ) : StateType { inline fun 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 { - 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}"