Updated on 2026-08-14

This commit is contained in:
Tangem 2024-04-06 16:48:02 +08:00
parent afb2536da1
commit 423e125974
18 changed files with 28 additions and 396 deletions

View file

@ -5,7 +5,6 @@ import com.tangem.common.*
import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError
import com.tangem.common.core.UserCodeRequestPolicy
import com.tangem.common.extensions.guard
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.models.Basic
import com.tangem.core.navigation.AppScreen
@ -19,7 +18,6 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.userwallets.UserWalletBuilder
import com.tangem.domain.userwallets.UserWalletIdBuilder
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.legacy.asLockable
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.AnalyticsParam
@ -28,8 +26,6 @@ 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
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
@ -371,49 +367,6 @@ 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() }
?: return CompletionResult.Failure(
error = TangemSdkError.ExceptionError(IllegalStateException("scanResponse is null")),
)
updateUserWalletsListManager(enableUserWalletsSaving = true)
return userWalletsListManager.save(userWallet)
.flatMap {
if (enableAccessCodesSaving) {
saveAccessCodes(scanResponse)
} else {
CompletionResult.Success(Unit)
}
}
.doOnSuccess {
Analytics.send(Settings.AppSettings.SaveWalletSwitcherChanged(AnalyticsParam.OnOffState.On))
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)
@ -431,31 +384,6 @@ 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.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = false)
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Home))
}
.doOnFailure { error ->
Timber.e(error, "Unable to delete saved wallets")
}
}
private suspend fun deleteSavedWalletsAndAccessCodesByNewWay(): CompletionResult<Unit> {
Analytics.send(Settings.AppSettings.SaveWalletSwitcherChanged(AnalyticsParam.OnOffState.Off))
deleteSavedAccessCodes()
@ -493,25 +421,6 @@ class DetailsMiddleware {
Timber.e(error, "Unable to delete saved access codes")
}
}
private suspend fun updateUserWalletsListManager(enableUserWalletsSaving: Boolean) {
val manager = if (enableUserWalletsSaving) {
createBiometricsUserWalletsManager() ?: return
} else {
UserWalletsListManager.provideRuntimeImplementation()
}
store.dispatchWithMain(GlobalAction.UpdateUserWalletsListManager(manager))
}
private fun createBiometricsUserWalletsManager(): UserWalletsListManager? {
val context = foregroundActivityObserver.foregroundActivity?.applicationContext.guard {
Timber.e(IllegalStateException("No activities in foreground"))
return null
}
return UserWalletsListManager.provideBiometricImplementation(context)
}
}
class AccessCodeRecoveryMiddleware {

View file

@ -90,12 +90,7 @@ object OnboardingHelper {
),
)
val toggles = store.inject(DaggerGraphState::userWalletsListManagerFeatureToggles)
if (toggles.isGeneralManagerEnabled) {
store.dispatchWithMain(SaveWalletAction.SaveWalletAfterBackup(hasBackupError))
} else {
store.dispatchWithMain(SaveWalletAction.Save)
}
store.dispatchWithMain(SaveWalletAction.SaveWalletAfterBackup(hasBackupError))
}
// When should not save user wallets but device has biometry and save wallet screen has not been shown,
// then open save wallet screen

View file

@ -562,7 +562,6 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
)
},
)
store.dispatchOnMain(GlobalAction.UpdateUserWalletsListManager(userWalletsListManager))
}
val notActivatedCardIds = gatherCardIds(backupState, card).mapNotNull {

View file

@ -11,13 +11,11 @@ internal sealed interface SaveWalletAction : Action {
val backupCardsIds: Set<String>?,
) : SaveWalletAction
data object Save : SaveWalletAction {
data object AllowToUseBiometrics : SaveWalletAction {
data object Success : SaveWalletAction
data class Error(val error: TangemError) : SaveWalletAction
}
data object AllowToUseBiometrics : SaveWalletAction
data object Dismiss : SaveWalletAction
data object CloseError : SaveWalletAction

View file

@ -7,8 +7,6 @@ import com.tangem.core.analytics.Analytics
import com.tangem.core.navigation.AppScreen
import com.tangem.core.navigation.NavigationAction
import com.tangem.domain.userwallets.UserWalletBuilder
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.legacy.isLockable
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.AnalyticsParam
@ -19,8 +17,6 @@ import com.tangem.tap.common.extensions.dispatchWithMain
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.extensions.onUserWalletSelected
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
@ -47,15 +43,14 @@ 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.Dismiss -> dismiss(state)
is SaveWalletAction.SaveWalletAfterBackup -> saveWalletAfterBackup(state, action.hasBackupError)
is SaveWalletAction.Save.Success,
is SaveWalletAction.AllowToUseBiometrics.Success,
is SaveWalletAction.AllowToUseBiometrics.Error,
is SaveWalletAction.ProvideBackupInfo,
is SaveWalletAction.CloseError,
is SaveWalletAction.Save.Error,
is SaveWalletAction.EnrollBiometrics,
is SaveWalletAction.EnrollBiometrics.Cancel,
-> Unit
@ -91,83 +86,6 @@ internal class SaveWalletMiddleware {
store.dispatchOnMain(NavigationAction.OpenBiometricsSettings)
}
private fun saveWalletIfBiometricsEnrolled(state: SaveWalletState) {
if (tangemSdkManager.needEnrollBiometrics) {
store.dispatchOnMain(SaveWalletAction.EnrollBiometrics)
} else {
saveWallet(state)
}
}
/**
* or from [SaveWalletState.backupInfo] if provided from
* [com.tangem.tap.features.onboarding.OnboardingHelper.trySaveWalletAndNavigateToWalletScreen]
*
* If saved user's wallet was selected then pop back to [AppScreen.Wallet]
* or navigate to [AppScreen.WalletSelector] otherwise
*
* TODO: Update that logic after onboarding and backup features refactoring
* */
private fun saveWallet(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
val featureToggles = store.inject(DaggerGraphState::userWalletsListManagerFeatureToggles)
if (!featureToggles.isGeneralManagerEnabled) {
provideLockableUserWalletsListManagerIfNot()
}
val isFirstSavedWallet = !userWalletsListManager.hasUserWallets
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
// receive useless updates.
// See: OnboardingHelper.trySaveWalletAndNavigateToWalletScreen()
if (isFirstSavedWallet) {
userWalletsListManager.save(userWallet, canOverride = true)
} else {
CompletionResult.Success(Unit)
}
}
.doOnFailure { error ->
store.dispatchWithMain(SaveWalletAction.Save.Error(error))
}
.doOnSuccess {
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
// Enable saving access codes only if this is the first time user save the wallet
if (isFirstSavedWallet) {
store.inject(DaggerGraphState::settingsRepository).setShouldSaveAccessCodes(value = true)
store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
isBiometricsRequestPolicy = userWallet.hasAccessCode,
)
}
store.dispatchOnMain(SaveWalletAction.Save.Success)
store.navigateToWallet()
}
}.saveIn(saveWalletJobHolder)
}
private fun allowToUseBiometrics(state: SaveWalletState) {
if (tangemSdkManager.needEnrollBiometrics) {
store.dispatchOnMain(SaveWalletAction.EnrollBiometrics)
@ -189,7 +107,9 @@ internal class SaveWalletMiddleware {
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {
val error = IllegalStateException("No selected user wallet")
Timber.e(error, "Unable to save user wallet")
store.dispatchWithMain(SaveWalletAction.Save.Error(TangemSdkError.ExceptionError(error)))
store.dispatchWithMain(
SaveWalletAction.AllowToUseBiometrics.Error(TangemSdkError.ExceptionError(error)),
)
return@launch
}
@ -206,24 +126,10 @@ internal class SaveWalletMiddleware {
isBiometricsRequestPolicy = userWallet.hasAccessCode,
)
store.dispatchWithMain(SaveWalletAction.Save.Success)
store.dispatchWithMain(SaveWalletAction.AllowToUseBiometrics.Success)
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet))
}
private suspend fun provideLockableUserWalletsListManagerIfNot() {
if (store.state.globalState.userWalletsListManager?.isLockable == true) return
val context = foregroundActivityObserver.foregroundActivity?.applicationContext.guard {
val error = IllegalStateException("No activities in foreground")
Timber.e(error)
store.dispatchWithMain(SaveWalletAction.Save.Error(TangemSdkError.ExceptionError(error)))
return
}
val manager = UserWalletsListManager.provideBiometricImplementation(context)
store.dispatchWithMain(GlobalAction.UpdateUserWalletsListManager(manager))
}
private fun dismiss(state: SaveWalletState) {
if (state.backupInfo != null) {
// TODO: Remove after onboarding refactoring

View file

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

View file

@ -5,7 +5,6 @@ import androidx.lifecycle.viewModelScope
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.settings.SetSaveWalletScreenShownUseCase
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
@ -24,7 +23,6 @@ import javax.inject.Inject
@HiltViewModel
internal class SaveWalletViewModel @Inject constructor(
private val userWalletsListManagerFeatureToggles: UserWalletsListManagerFeatureToggles,
private val analyticsEventHandler: AnalyticsEventHandler,
private val setSaveWalletScreenShownUseCase: SetSaveWalletScreenShownUseCase,
dispatchers: AppCoroutineDispatcherProvider,
@ -43,12 +41,7 @@ internal class SaveWalletViewModel @Inject constructor(
fun saveWallet() {
analyticsEventHandler.send(WalletScreenAnalyticsEvent.MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.On))
if (userWalletsListManagerFeatureToggles.isGeneralManagerEnabled) {
store.dispatch(SaveWalletAction.AllowToUseBiometrics)
} else {
store.dispatch(SaveWalletAction.Save)
}
store.dispatch(SaveWalletAction.AllowToUseBiometrics)
}
fun cancelOrClose() {