Updated on 2026-08-14

This commit is contained in:
Tangem 2024-02-20 21:14:45 +07:00
parent c6578fcad5
commit 6e642be3ca
19 changed files with 478 additions and 50 deletions

View file

@ -24,10 +24,7 @@ import com.tangem.domain.wallets.legacy.isLockedSync
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Settings
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.dispatchWithMain
import com.tangem.tap.common.extensions.onUserWalletSelected
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
@ -292,7 +289,8 @@ class DetailsMiddleware {
private fun toggleSaveWallets(state: DetailsState, enable: Boolean) = scope.launch {
// Nothing to change
val walletsRepository = store.state.daggerGraphState.get(DaggerGraphState::walletsRepository)
val walletsRepository = store.inject(DaggerGraphState::walletsRepository)
if (walletsRepository.shouldSaveUserWalletsSync() == enable) {
store.dispatchWithMain(DetailsAction.AppSettings.SwitchPrivacySetting.Success)
return@launch
@ -360,6 +358,19 @@ class DetailsMiddleware {
private suspend fun saveCurrentWallet(
scanResponse: ScanResponse?,
enableAccessCodesSaving: Boolean,
): CompletionResult<Unit> {
val featureToggles = store.inject(DaggerGraphState::userWalletsListManagerFeatureToggles)
return if (featureToggles.isGeneralManagerEnabled) {
saveCurrentWalletByNewWay(scanResponse, enableAccessCodesSaving)
} else {
saveCurrentWalletByOldWay(scanResponse, enableAccessCodesSaving)
}
}
private suspend fun saveCurrentWalletByOldWay(
scanResponse: ScanResponse?,
enableAccessCodesSaving: Boolean,
): CompletionResult<Unit> {
val userWallet = userWalletsListManager.selectedUserWalletSync
?: scanResponse?.let { UserWalletBuilder(it).build() }
@ -381,8 +392,26 @@ class DetailsMiddleware {
Analytics.send(Settings.AppSettings.SaveWalletSwitcherChanged(AnalyticsParam.OnOffState.On))
preferencesStorage.shouldShowSaveUserWalletScreen = false
store.state.daggerGraphState.get(DaggerGraphState::walletsRepository)
.saveShouldSaveUserWallets(item = true)
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
}
.doOnFailure { error ->
Timber.e(error, "Unable to save user wallet")
}
}
private suspend fun saveCurrentWalletByNewWay(
scanResponse: ScanResponse?,
enableAccessCodesSaving: Boolean,
): CompletionResult<Unit> {
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
return if (enableAccessCodesSaving) {
saveAccessCodes(scanResponse)
} else {
CompletionResult.Success(Unit)
}
.doOnSuccess {
Analytics.send(Settings.AppSettings.SaveWalletSwitcherChanged(AnalyticsParam.OnOffState.On))
}
.doOnFailure { error ->
Timber.e(error, "Unable to save user wallet")
@ -390,13 +419,22 @@ class DetailsMiddleware {
}
private suspend fun deleteSavedWalletsAndAccessCodes(): CompletionResult<Unit> {
val featureToggles = store.inject(DaggerGraphState::userWalletsListManagerFeatureToggles)
return if (featureToggles.isGeneralManagerEnabled) {
deleteSavedWalletsAndAccessCodesByNewWay()
} else {
deleteSavedWalletsAndAccessCodesByOldWay()
}
}
private suspend fun deleteSavedWalletsAndAccessCodesByOldWay(): CompletionResult<Unit> {
return userWalletsListManager.clear()
.doOnSuccess {
Analytics.send(Settings.AppSettings.SaveWalletSwitcherChanged(AnalyticsParam.OnOffState.Off))
deleteSavedAccessCodes()
updateUserWalletsListManager(enableUserWalletsSaving = false)
store.state.daggerGraphState.get(DaggerGraphState::walletsRepository)
.saveShouldSaveUserWallets(item = false)
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = false)
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Home))
}
@ -405,6 +443,17 @@ class DetailsMiddleware {
}
}
private suspend fun deleteSavedWalletsAndAccessCodesByNewWay(): CompletionResult<Unit> {
Analytics.send(Settings.AppSettings.SaveWalletSwitcherChanged(AnalyticsParam.OnOffState.Off))
deleteSavedAccessCodes()
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = false)
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Home))
return CompletionResult.Success(Unit)
}
private fun saveAccessCodes(scanResponse: ScanResponse?): CompletionResult<Unit> {
Analytics.send(Settings.AppSettings.SaveAccessCodeSwitcherChanged(AnalyticsParam.OnOffState.On))

View file

@ -16,6 +16,8 @@ internal sealed interface SaveWalletAction : Action {
data class Error(val error: TangemError) : SaveWalletAction
}
object AllowToUseBiometrics : SaveWalletAction
object Dismiss : SaveWalletAction
object CloseError : SaveWalletAction

View file

@ -18,6 +18,7 @@ import com.tangem.tap.common.analytics.events.MainScreen
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.dispatchWithMain
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
@ -42,6 +43,7 @@ internal class SaveWalletMiddleware {
private fun handleAction(action: SaveWalletAction, state: SaveWalletState) {
when (action) {
is SaveWalletAction.Save -> saveWalletIfBiometricsEnrolled(state)
is SaveWalletAction.AllowToUseBiometrics -> allowToUseBiometrics(state)
is SaveWalletAction.EnrollBiometrics.Enroll -> enrollBiometrics()
is SaveWalletAction.SaveWalletWasShown -> saveWalletWasShown()
is SaveWalletAction.Dismiss -> dismiss(state)
@ -96,11 +98,16 @@ internal class SaveWalletMiddleware {
.build()
?: return@launch
provideLockableUserWalletsListManagerIfNot()
val featureToggles = store.inject(DaggerGraphState::userWalletsListManagerFeatureToggles)
if (featureToggles.isGeneralManagerEnabled) {
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
} else {
provideLockableUserWalletsListManagerIfNot()
}
val isFirstSavedWallet = !userWalletsListManager.hasUserWallets
saveAccessCodeIfNeeded(state.backupInfo?.accessCode, userWallet.cardsInWallet)
saveAccessCodeIfNeeded(accessCode = state.backupInfo?.accessCode, cardsInWallet = userWallet.cardsInWallet)
.flatMap {
// Save wallet only at first time (SaveWalletBottomSheet).
// Otherwise (Example, add new wallet in Details) userWalletsListManager.wallets subscribers will
@ -116,16 +123,14 @@ internal class SaveWalletMiddleware {
store.dispatchWithMain(SaveWalletAction.Save.Error(error))
}
.doOnSuccess {
store.state.daggerGraphState.get(DaggerGraphState::walletsRepository)
.saveShouldSaveUserWallets(item = true)
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
// Enable saving access codes only if this is the first time user save the wallet
if (isFirstSavedWallet) {
preferencesStorage.shouldSaveAccessCodes = true
store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository)
.setAccessCodeRequestPolicy(
isBiometricsRequestPolicy = userWallet.hasAccessCode,
)
store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
isBiometricsRequestPolicy = userWallet.hasAccessCode,
)
}
store.dispatchOnMain(SaveWalletAction.Save.Success)
@ -141,6 +146,46 @@ internal class SaveWalletMiddleware {
}
}
private fun allowToUseBiometrics(state: SaveWalletState) {
val scanResponse = state.backupInfo?.scanResponse
?: store.state.globalState.scanResponse
?: return
if (state.backupInfo != null) {
// TODO: Remove after onboarding refactoring
Analytics.send(Onboarding.EnableBiometrics(AnalyticsParam.OnOffState.On))
} else {
Analytics.send(MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.On))
}
scope.launch {
val userWallet = userWalletsListManager.selectedUserWalletSync
?: UserWalletBuilder(scanResponse)
.backupCardsIds(state.backupInfo?.backupCardsIds)
.build()
?: return@launch
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
saveAccessCodeIfNeeded(accessCode = state.backupInfo?.accessCode, cardsInWallet = userWallet.cardsInWallet)
.flatMap {
userWalletsListManager.save(userWallet, canOverride = true)
}
.doOnFailure { error ->
store.dispatchWithMain(SaveWalletAction.Save.Error(error))
}
.doOnSuccess {
preferencesStorage.shouldSaveAccessCodes = true
store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
isBiometricsRequestPolicy = userWallet.hasAccessCode,
)
store.dispatchOnMain(SaveWalletAction.Save.Success)
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet))
}
}
}
private suspend fun provideLockableUserWalletsListManagerIfNot() {
if (store.state.globalState.userWalletsListManager?.isLockable == true) return

View file

@ -21,9 +21,9 @@ internal object SaveWalletReducer {
backupCardsIds = action.backupCardsIds,
),
)
is SaveWalletAction.Save -> state.copy(
isSaveInProgress = true,
)
is SaveWalletAction.Save,
is SaveWalletAction.AllowToUseBiometrics,
-> state.copy(isSaveInProgress = true)
is SaveWalletAction.Save.Error -> state.copy(
error = action.error,
isSaveInProgress = false,

View file

@ -3,6 +3,7 @@ package com.tangem.tap.features.saveWallet.ui
import androidx.lifecycle.ViewModel
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.wallets.legacy.UserWalletsListManagerFeatureToggles
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.features.details.ui.cardsettings.TextReference
@ -19,6 +20,7 @@ import javax.inject.Inject
@HiltViewModel
internal class SaveWalletViewModel @Inject constructor(
private val userWalletsListManagerFeatureToggles: UserWalletsListManagerFeatureToggles,
private val analyticsEventHandler: AnalyticsEventHandler,
) : ViewModel(), StoreSubscriber<SaveWalletState> {
private val stateInternal = MutableStateFlow(SaveWalletScreenState())
@ -31,7 +33,12 @@ internal class SaveWalletViewModel @Inject constructor(
fun saveWallet() {
analyticsEventHandler.send(WalletScreenAnalyticsEvent.MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.On))
store.dispatch(SaveWalletAction.Save)
if (userWalletsListManagerFeatureToggles.isGeneralManagerEnabled) {
store.dispatch(SaveWalletAction.AllowToUseBiometrics)
} else {
store.dispatch(SaveWalletAction.Save)
}
}
fun cancelOrClose() {