Delete wallet hotfix (#1663)

* Delete wallet hotfix

* Documentation update

* Navigation hotfix

* Documentation update

* Changelog update

* Wallet restore navigation update

* Wallet deletion navigation navigation update

---------

Co-authored-by: Honza <rychnovsky.honza@gmail.com>
This commit is contained in:
Milan 2024-11-11 09:16:03 +01:00 committed by GitHub
parent 078f7b88df
commit 72e3eca548
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 59 additions and 49 deletions

View File

@ -11,7 +11,9 @@ and this application adheres to [Semantic Versioning](https://semver.org/spec/v2
- The Flexa SDK has been adopted to enable payments using the embedded Flexa UI - The Flexa SDK has been adopted to enable payments using the embedded Flexa UI
### Fixed ### Fixed
- Address book toast now correctly shows on send screen when adding both new and known addresses to text field - Address book toast now correctly shows on send screen when adding both new and known addresses to text field
- The application now correctly navigates to the homepage after deleting the current wallet and creating a new or
recovering an older one
## [1.2.1 (760)] - 2024-10-22 ## [1.2.1 (760)] - 2024-10-22

View File

@ -15,6 +15,8 @@ directly impact users rather than highlighting other key architectural updates.*
### Fixed ### Fixed
- Address book toast now correctly shows on send screen when adding both new and known addresses to text field - Address book toast now correctly shows on send screen when adding both new and known addresses to text field
- The application now correctly navigates to the homepage after deleting the current wallet and creating a new or
recovering an older one
## [1.2.1 (760)] - 2024-10-22 ## [1.2.1 (760)] - 2024-10-22

View File

@ -224,6 +224,10 @@ internal fun MainActivity.Navigation() {
goBack = { goBack = {
setDeleteWalletAuthentication(false) setDeleteWalletAuthentication(false)
navController.popBackStackJustOnce(DELETE_WALLET) navController.popBackStackJustOnce(DELETE_WALLET)
},
onConfirm = {
setDeleteWalletAuthentication(false)
navController.popBackStackJustOnce(DELETE_WALLET)
} }
) )
} }

View File

@ -1,9 +1,12 @@
package co.electriccoin.zcash.ui.common.usecase package co.electriccoin.zcash.ui.common.usecase
import cash.z.ecc.android.sdk.SdkSynchronizer
import co.electriccoin.zcash.ui.common.repository.WalletRepository import co.electriccoin.zcash.ui.common.repository.WalletRepository
class GetSynchronizerUseCase( class GetSynchronizerUseCase(
private val walletRepository: WalletRepository private val walletRepository: WalletRepository
) { ) {
suspend operator fun invoke() = walletRepository.getSynchronizer() suspend operator fun invoke() = walletRepository.getSynchronizer()
suspend fun getSdkSynchronizer() = walletRepository.getSynchronizer() as? SdkSynchronizer
} }

View File

@ -1,11 +1,8 @@
package co.electriccoin.zcash.ui.common.viewmodel package co.electriccoin.zcash.ui.common.viewmodel
import android.app.Activity
import android.app.Application import android.app.Application
import android.content.Intent
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import cash.z.ecc.android.sdk.SdkSynchronizer
import cash.z.ecc.android.sdk.Synchronizer import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.WalletCoordinator import cash.z.ecc.android.sdk.WalletCoordinator
import cash.z.ecc.android.sdk.WalletInitMode import cash.z.ecc.android.sdk.WalletInitMode
@ -21,7 +18,6 @@ import co.electriccoin.zcash.preference.EncryptedPreferenceProvider
import co.electriccoin.zcash.preference.StandardPreferenceProvider import co.electriccoin.zcash.preference.StandardPreferenceProvider
import co.electriccoin.zcash.spackle.Twig import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.BuildConfig import co.electriccoin.zcash.ui.BuildConfig
import co.electriccoin.zcash.ui.MainActivity
import co.electriccoin.zcash.ui.common.model.OnboardingState import co.electriccoin.zcash.ui.common.model.OnboardingState
import co.electriccoin.zcash.ui.common.model.WalletRestoringState import co.electriccoin.zcash.ui.common.model.WalletRestoringState
import co.electriccoin.zcash.ui.common.model.WalletSnapshot import co.electriccoin.zcash.ui.common.model.WalletSnapshot
@ -30,6 +26,7 @@ import co.electriccoin.zcash.ui.common.repository.BalanceRepository
import co.electriccoin.zcash.ui.common.repository.ExchangeRateRepository import co.electriccoin.zcash.ui.common.repository.ExchangeRateRepository
import co.electriccoin.zcash.ui.common.repository.WalletRepository import co.electriccoin.zcash.ui.common.repository.WalletRepository
import co.electriccoin.zcash.ui.common.usecase.DeleteAddressBookUseCase import co.electriccoin.zcash.ui.common.usecase.DeleteAddressBookUseCase
import co.electriccoin.zcash.ui.common.usecase.GetSynchronizerUseCase
import co.electriccoin.zcash.ui.common.usecase.IsFlexaAvailableUseCase import co.electriccoin.zcash.ui.common.usecase.IsFlexaAvailableUseCase
import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
import co.electriccoin.zcash.ui.screen.account.ext.TransactionOverviewExt import co.electriccoin.zcash.ui.screen.account.ext.TransactionOverviewExt
@ -48,9 +45,9 @@ import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.coroutines.resume import kotlin.coroutines.resume
@ -71,7 +68,8 @@ class WalletViewModel(
private val standardPreferenceProvider: StandardPreferenceProvider, private val standardPreferenceProvider: StandardPreferenceProvider,
private val getAvailableServers: GetDefaultServersProvider, private val getAvailableServers: GetDefaultServersProvider,
private val deleteAddressBookUseCase: DeleteAddressBookUseCase, private val deleteAddressBookUseCase: DeleteAddressBookUseCase,
private val isFlexaAvailable: IsFlexaAvailableUseCase private val isFlexaAvailable: IsFlexaAvailableUseCase,
private val getSynchronizer: GetSynchronizerUseCase
) : AndroidViewModel(application) { ) : AndroidViewModel(application) {
val navigationCommand = exchangeRateRepository.navigationCommand val navigationCommand = exchangeRateRepository.navigationCommand
@ -240,40 +238,34 @@ class WalletViewModel(
} }
} }
fun deleteWalletFlow(activity: Activity): Flow<Boolean> = fun deleteWallet(
callbackFlow { onError: () -> Unit,
Twig.info { "Delete wallet: Requested" } onSuccess: () -> Unit
disconnectFlexa() ) = viewModelScope.launch(Dispatchers.Main) {
val synchronizer = synchronizer.value Twig.info { "Delete wallet: Requested" }
if (null != synchronizer) { disconnectFlexa()
(synchronizer as SdkSynchronizer).closeFlow().collect {
Twig.info { "Delete wallet: SDK closed" }
walletCoordinator.deleteSdkDataFlow().collect { isSdkErased -> getSynchronizer.getSdkSynchronizer()?.closeFlow()?.first()
Twig.info { "Delete wallet: Erase SDK result: $isSdkErased" } Twig.info { "Delete wallet: SDK closed" }
if (!isSdkErased) { val isSdkErased = walletCoordinator.deleteSdkDataFlow().first()
trySend(false) Twig.info { "Delete wallet: Erase SDK result: $isSdkErased" }
}
clearAppStateFlow().collect { isAppErased -> if (!isSdkErased) {
Twig.info { "Delete wallet: Erase App result: $isAppErased" } Twig.error { "Wallet deletion failed" }
if (!isAppErased) { onError()
trySend(false) return@launch
} else { }
trySend(true)
activity.run { val isAppErased = clearAppStateFlow().first()
finish() Twig.info { "Delete wallet: Erase App result: $isAppErased" }
startActivity(Intent(this, MainActivity::class.java)) if (isAppErased) {
} Twig.info { "Wallet deleted successfully" }
} onSuccess()
} } else {
} Twig.error { "Wallet deletion failed" }
} onError()
} }
awaitClose { }
// Nothing to close
}
}.flowOn(Dispatchers.Main)
private suspend fun disconnectFlexa() = private suspend fun disconnectFlexa() =
suspendCoroutine { cont -> suspendCoroutine { cont ->

View File

@ -1,6 +1,7 @@
package co.electriccoin.zcash.ui.screen.deletewallet package co.electriccoin.zcash.ui.screen.deletewallet
import android.app.Activity import android.app.Activity
import android.content.Intent
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -8,7 +9,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.MainActivity import co.electriccoin.zcash.ui.MainActivity
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
@ -17,7 +17,10 @@ import co.electriccoin.zcash.ui.screen.deletewallet.view.DeleteWallet
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Composable @Composable
internal fun MainActivity.WrapDeleteWallet(goBack: () -> Unit) { internal fun MainActivity.WrapDeleteWallet(
goBack: () -> Unit,
onConfirm: () -> Unit,
) {
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
@ -27,6 +30,7 @@ internal fun MainActivity.WrapDeleteWallet(goBack: () -> Unit) {
goBack = goBack, goBack = goBack,
topAppBarSubTitleState = walletState, topAppBarSubTitleState = walletState,
walletViewModel = walletViewModel, walletViewModel = walletViewModel,
onConfirm = onConfirm
) )
} }
@ -34,6 +38,7 @@ internal fun MainActivity.WrapDeleteWallet(goBack: () -> Unit) {
internal fun WrapDeleteWallet( internal fun WrapDeleteWallet(
activity: Activity, activity: Activity,
goBack: () -> Unit, goBack: () -> Unit,
onConfirm: () -> Unit,
topAppBarSubTitleState: TopAppBarSubTitleState, topAppBarSubTitleState: TopAppBarSubTitleState,
walletViewModel: WalletViewModel, walletViewModel: WalletViewModel,
) { ) {
@ -49,19 +54,20 @@ internal fun WrapDeleteWallet(
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
onBack = goBack, onBack = goBack,
onConfirm = { onConfirm = {
scope.launch { walletViewModel.deleteWallet(
walletViewModel.deleteWalletFlow(activity).collect { isWalletDeleted -> onSuccess = {
if (isWalletDeleted) { onConfirm()
Twig.info { "Wallet deleted successfully" } activity.finish()
// The app flows move to the Onboarding screens reactively activity.startActivity(Intent(activity, MainActivity::class.java))
} else { },
Twig.error { "Wallet deletion failed" } onError = {
scope.launch {
snackbarHostState.showSnackbar( snackbarHostState.showSnackbar(
message = activity.getString(R.string.delete_wallet_failed) message = activity.getString(R.string.delete_wallet_failed)
) )
} }
} }
} )
}, },
topAppBarSubTitleState = topAppBarSubTitleState, topAppBarSubTitleState = topAppBarSubTitleState,
) )

View File

@ -53,6 +53,7 @@ fun WrapRestore() {
SeedPhrase(restoreViewModel.userWordList.current.value), SeedPhrase(restoreViewModel.userWordList.current.value),
restoreViewModel.userBirthdayHeight.value restoreViewModel.userBirthdayHeight.value
) )
onboardingViewModel.setIsImporting(false)
} }
) )
} }