[#1305] Connect shielding Multi-Trx-Submit-Error

- Closes #1305
This commit is contained in:
Honza Rychnovský 2024-03-28 10:54:51 +01:00 committed by GitHub
parent 8b58233648
commit 809820c1f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 143 additions and 59 deletions

View File

@ -1,13 +1,16 @@
package co.electriccoin.zcash.ui package co.electriccoin.zcash.ui
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.lifecycle.SavedStateHandle
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.NavOptionsBuilder import androidx.navigation.NavOptionsBuilder
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import cash.z.ecc.android.sdk.model.ZecSend
import co.electriccoin.zcash.ui.NavigationArguments.MULTIPLE_SUBMISSION_CLEAR_FORM import co.electriccoin.zcash.ui.NavigationArguments.MULTIPLE_SUBMISSION_CLEAR_FORM
import co.electriccoin.zcash.ui.NavigationArguments.SEND_CONFIRM_AMOUNT import co.electriccoin.zcash.ui.NavigationArguments.SEND_CONFIRM_AMOUNT
import co.electriccoin.zcash.ui.NavigationArguments.SEND_CONFIRM_INITIAL_STAGE
import co.electriccoin.zcash.ui.NavigationArguments.SEND_CONFIRM_MEMO import co.electriccoin.zcash.ui.NavigationArguments.SEND_CONFIRM_MEMO
import co.electriccoin.zcash.ui.NavigationArguments.SEND_CONFIRM_PROPOSAL import co.electriccoin.zcash.ui.NavigationArguments.SEND_CONFIRM_PROPOSAL
import co.electriccoin.zcash.ui.NavigationArguments.SEND_CONFIRM_RECIPIENT_ADDRESS import co.electriccoin.zcash.ui.NavigationArguments.SEND_CONFIRM_RECIPIENT_ADDRESS
@ -42,6 +45,7 @@ import co.electriccoin.zcash.ui.screen.send.ext.toSerializableAddress
import co.electriccoin.zcash.ui.screen.send.model.SendArguments import co.electriccoin.zcash.ui.screen.send.model.SendArguments
import co.electriccoin.zcash.ui.screen.sendconfirmation.WrapSendConfirmation import co.electriccoin.zcash.ui.screen.sendconfirmation.WrapSendConfirmation
import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SendConfirmationArguments import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SendConfirmationArguments
import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SendConfirmationStage
import co.electriccoin.zcash.ui.screen.settings.WrapSettings import co.electriccoin.zcash.ui.screen.settings.WrapSettings
import co.electriccoin.zcash.ui.screen.support.WrapSupport import co.electriccoin.zcash.ui.screen.support.WrapSupport
import co.electriccoin.zcash.ui.screen.update.WrapCheckForUpdate import co.electriccoin.zcash.ui.screen.update.WrapCheckForUpdate
@ -75,18 +79,19 @@ internal fun MainActivity.Navigation() {
}, },
goSendConfirmation = { zecSend -> goSendConfirmation = { zecSend ->
navController.currentBackStackEntry?.savedStateHandle?.let { handle -> navController.currentBackStackEntry?.savedStateHandle?.let { handle ->
handle[SEND_CONFIRM_RECIPIENT_ADDRESS] = fillInHandleForConfirmation(handle, zecSend, SendConfirmationStage.Confirmation)
Json.encodeToString(
serializer = SerializableAddress.serializer(),
value = zecSend.destination.toSerializableAddress()
)
handle[SEND_CONFIRM_AMOUNT] = zecSend.amount.value
handle[SEND_CONFIRM_MEMO] = zecSend.memo.value
handle[SEND_CONFIRM_PROPOSAL] = zecSend.proposal?.toByteArray()
} }
navController.navigateJustOnce(SEND_CONFIRMATION) navController.navigateJustOnce(SEND_CONFIRMATION)
}, },
goSettings = { navController.navigateJustOnce(SETTINGS) }, goSettings = { navController.navigateJustOnce(SETTINGS) },
goMultiTrxSubmissionFailure = {
// Ultimately we could approach reworking the MultipleTrxFailure screen into a separate
// navigation endpoint
navController.currentBackStackEntry?.savedStateHandle?.let { handle ->
fillInHandleForConfirmation(handle, null, SendConfirmationStage.MultipleTrxFailure)
}
navController.navigateJustOnce(SEND_CONFIRMATION)
},
sendArguments = sendArguments =
SendArguments( SendArguments(
recipientAddress = recipientAddress =
@ -195,21 +200,31 @@ internal fun MainActivity.Navigation() {
navController.popBackStackJustOnce(SEND_CONFIRMATION) navController.popBackStackJustOnce(SEND_CONFIRMATION)
}, },
goHome = { navController.navigateJustOnce(HOME) }, goHome = { navController.navigateJustOnce(HOME) },
arguments = arguments = SendConfirmationArguments.fromSavedStateHandle(backStackEntry.savedStateHandle)
SendConfirmationArguments.fromSavedStateHandle(backStackEntry.savedStateHandle).also {
// Remove SendConfirmation screen arguments passed from the Send screen if some exist
// after we use them
backStackEntry.savedStateHandle.remove<String>(SEND_CONFIRM_RECIPIENT_ADDRESS)
backStackEntry.savedStateHandle.remove<Long>(SEND_CONFIRM_AMOUNT)
backStackEntry.savedStateHandle.remove<String>(SEND_CONFIRM_MEMO)
backStackEntry.savedStateHandle.remove<ByteArray>(SEND_CONFIRM_PROPOSAL)
}
) )
} }
} }
} }
} }
private fun fillInHandleForConfirmation(
handle: SavedStateHandle,
zecSend: ZecSend?,
initialStage: SendConfirmationStage
) {
if (zecSend != null) {
handle[SEND_CONFIRM_RECIPIENT_ADDRESS] =
Json.encodeToString(
serializer = SerializableAddress.serializer(),
value = zecSend.destination.toSerializableAddress()
)
handle[SEND_CONFIRM_AMOUNT] = zecSend.amount.value
handle[SEND_CONFIRM_MEMO] = zecSend.memo.value
handle[SEND_CONFIRM_PROPOSAL] = zecSend.proposal?.toByteArray()
}
handle[SEND_CONFIRM_INITIAL_STAGE] = initialStage.toStringName()
}
private fun NavHostController.navigateJustOnce( private fun NavHostController.navigateJustOnce(
route: String, route: String,
navOptionsBuilder: (NavOptionsBuilder.() -> Unit)? = null navOptionsBuilder: (NavOptionsBuilder.() -> Unit)? = null
@ -245,6 +260,7 @@ object NavigationArguments {
const val SEND_CONFIRM_AMOUNT = "send_confirm_amount" const val SEND_CONFIRM_AMOUNT = "send_confirm_amount"
const val SEND_CONFIRM_MEMO = "send_confirm_memo" const val SEND_CONFIRM_MEMO = "send_confirm_memo"
const val SEND_CONFIRM_PROPOSAL = "send_confirm_proposal" const val SEND_CONFIRM_PROPOSAL = "send_confirm_proposal"
const val SEND_CONFIRM_INITIAL_STAGE = "send_confirm_initial_stage"
const val MULTIPLE_SUBMISSION_CLEAR_FORM = "multiple_submission_clear_form" const val MULTIPLE_SUBMISSION_CLEAR_FORM = "multiple_submission_clear_form"
} }

View File

@ -9,6 +9,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
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.model.UnifiedSpendingKey import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
@ -21,6 +22,8 @@ import co.electriccoin.zcash.ui.configuration.RemoteConfig
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
import co.electriccoin.zcash.ui.screen.balances.model.ShieldState import co.electriccoin.zcash.ui.screen.balances.model.ShieldState
import co.electriccoin.zcash.ui.screen.balances.view.Balances import co.electriccoin.zcash.ui.screen.balances.view.Balances
import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SubmitResult
import co.electriccoin.zcash.ui.screen.sendconfirmation.viewmodel.CreateTransactionsViewModel
import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel
import co.electriccoin.zcash.ui.screen.update.AppUpdateCheckerImp import co.electriccoin.zcash.ui.screen.update.AppUpdateCheckerImp
import co.electriccoin.zcash.ui.screen.update.model.UpdateState import co.electriccoin.zcash.ui.screen.update.model.UpdateState
@ -32,9 +35,12 @@ import org.jetbrains.annotations.VisibleForTesting
internal fun WrapBalances( internal fun WrapBalances(
activity: ComponentActivity, activity: ComponentActivity,
goSettings: () -> Unit, goSettings: () -> Unit,
goMultiTrxSubmissionFailure: () -> Unit,
) { ) {
val walletViewModel by activity.viewModels<WalletViewModel>() val walletViewModel by activity.viewModels<WalletViewModel>()
val createTransactionsViewModel by activity.viewModels<CreateTransactionsViewModel>()
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value
@ -51,8 +57,10 @@ internal fun WrapBalances(
val settingsViewModel by activity.viewModels<SettingsViewModel>() val settingsViewModel by activity.viewModels<SettingsViewModel>()
WrapBalances( WrapBalances(
goSettings = goSettings,
checkUpdateViewModel = checkUpdateViewModel, checkUpdateViewModel = checkUpdateViewModel,
createTransactionsViewModel = createTransactionsViewModel,
goSettings = goSettings,
goMultiTrxSubmissionFailure = goMultiTrxSubmissionFailure,
spendingKey = spendingKey, spendingKey = spendingKey,
settingsViewModel = settingsViewModel, settingsViewModel = settingsViewModel,
synchronizer = synchronizer, synchronizer = synchronizer,
@ -66,8 +74,10 @@ const val DEFAULT_SHIELDING_THRESHOLD = 100000L
@VisibleForTesting @VisibleForTesting
@Suppress("LongParameterList", "LongMethod") @Suppress("LongParameterList", "LongMethod")
internal fun WrapBalances( internal fun WrapBalances(
goSettings: () -> Unit,
checkUpdateViewModel: CheckUpdateViewModel, checkUpdateViewModel: CheckUpdateViewModel,
createTransactionsViewModel: CreateTransactionsViewModel,
goSettings: () -> Unit,
goMultiTrxSubmissionFailure: () -> Unit,
settingsViewModel: SettingsViewModel, settingsViewModel: SettingsViewModel,
spendingKey: UnifiedSpendingKey?, spendingKey: UnifiedSpendingKey?,
synchronizer: Synchronizer?, synchronizer: Synchronizer?,
@ -98,14 +108,14 @@ internal fun WrapBalances(
val (isShowingErrorDialog, setShowErrorDialog) = rememberSaveable { mutableStateOf(false) } val (isShowingErrorDialog, setShowErrorDialog) = rememberSaveable { mutableStateOf(false) }
suspend fun showShieldingError(error: Throwable?) { suspend fun showShieldingError(errorMessage: String?) {
Twig.error { "Shielding proposal failed with: $error" } Twig.error { "Shielding proposal failed with: $errorMessage" }
// Adding the extra delay before notifying UI for a better UX // Adding the extra delay before notifying UI for a better UX
@Suppress("MagicNumber") @Suppress("MagicNumber")
delay(1500) delay(1500)
setShieldState(ShieldState.Failed(error?.message ?: "")) setShieldState(ShieldState.Failed(errorMessage ?: ""))
setShowErrorDialog(true) setShowErrorDialog(true)
} }
@ -143,26 +153,35 @@ internal fun WrapBalances(
if (newProposal == null) { if (newProposal == null) {
showShieldingError(null) showShieldingError(null)
} else { } else {
// TODO [#1294]: Add Send.Multiple-Trx-Failed screen val result =
// TODO [#1294]: Note that the following processing is not entirely correct and will be createTransactionsViewModel.runCreateTransactions(
// reworked synchronizer = synchronizer,
// TODO [#1294]: https://github.com/Electric-Coin-Company/zashi-android/issues/1294 spendingKey = spendingKey,
runCatching { proposal = newProposal
synchronizer.createProposedTransactions( )
proposal = newProposal, when (result) {
usk = spendingKey SubmitResult.Success -> {
).collect { Twig.info { "Shielding transaction done successfully" }
Twig.info { "Printing only for now. Will be reworked. Result: $it" } setShieldState(ShieldState.None)
// Triggering transaction history refresh to be notified about the newly created
// transaction asap
(synchronizer as SdkSynchronizer).refreshTransactions()
// We could consider notifying UI with a change to emphasize the shielding action
// was successful, or we could switch the selected tab to Account
}
is SubmitResult.SimpleTrxFailure -> {
Twig.warn { "Shielding transaction failed" }
showShieldingError(result.errorDescription)
}
is SubmitResult.MultipleTrxFailure -> {
Twig.warn { "Shielding failed with multi-transactions-submission-error handling" }
goMultiTrxSubmissionFailure()
} }
}.onSuccess {
Twig.debug { "Shielding transaction event" }
setShieldState(ShieldState.None)
}.onFailure {
showShieldingError(it)
} }
} }
}.onFailure { }.onFailure {
showShieldingError(it) showShieldingError(it.message)
} }
} }
}, },

View File

@ -29,6 +29,7 @@ internal fun MainActivity.WrapHome(
onPageChange: (HomeScreenIndex) -> Unit, onPageChange: (HomeScreenIndex) -> Unit,
goBack: () -> Unit, goBack: () -> Unit,
goSettings: () -> Unit, goSettings: () -> Unit,
goMultiTrxSubmissionFailure: () -> Unit,
goScan: () -> Unit, goScan: () -> Unit,
goSendConfirmation: (ZecSend) -> Unit, goSendConfirmation: (ZecSend) -> Unit,
sendArguments: SendArguments sendArguments: SendArguments
@ -40,6 +41,7 @@ internal fun MainActivity.WrapHome(
goScan = goScan, goScan = goScan,
goSendConfirmation = goSendConfirmation, goSendConfirmation = goSendConfirmation,
goSettings = goSettings, goSettings = goSettings,
goMultiTrxSubmissionFailure = goMultiTrxSubmissionFailure,
sendArguments = sendArguments sendArguments = sendArguments
) )
} }
@ -50,6 +52,7 @@ internal fun WrapHome(
activity: ComponentActivity, activity: ComponentActivity,
goBack: () -> Unit, goBack: () -> Unit,
goSettings: () -> Unit, goSettings: () -> Unit,
goMultiTrxSubmissionFailure: () -> Unit,
goScan: () -> Unit, goScan: () -> Unit,
goSendConfirmation: (ZecSend) -> Unit, goSendConfirmation: (ZecSend) -> Unit,
onPageChange: (HomeScreenIndex) -> Unit, onPageChange: (HomeScreenIndex) -> Unit,
@ -127,7 +130,8 @@ internal fun WrapHome(
screenContent = { screenContent = {
WrapBalances( WrapBalances(
activity = activity, activity = activity,
goSettings = goSettings goSettings = goSettings,
goMultiTrxSubmissionFailure = goMultiTrxSubmissionFailure
) )
} }
) )

View File

@ -33,7 +33,7 @@ import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SendConfirmationAr
import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SendConfirmationStage import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SendConfirmationStage
import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SubmitResult import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SubmitResult
import co.electriccoin.zcash.ui.screen.sendconfirmation.view.SendConfirmation import co.electriccoin.zcash.ui.screen.sendconfirmation.view.SendConfirmation
import co.electriccoin.zcash.ui.screen.sendconfirmation.viewmodel.SendConfirmationViewModel import co.electriccoin.zcash.ui.screen.sendconfirmation.viewmodel.CreateTransactionsViewModel
import co.electriccoin.zcash.ui.screen.support.model.SupportInfo import co.electriccoin.zcash.ui.screen.support.model.SupportInfo
import co.electriccoin.zcash.ui.screen.support.model.SupportInfoType import co.electriccoin.zcash.ui.screen.support.model.SupportInfoType
import co.electriccoin.zcash.ui.screen.support.viewmodel.SupportViewModel import co.electriccoin.zcash.ui.screen.support.viewmodel.SupportViewModel
@ -50,7 +50,7 @@ internal fun MainActivity.WrapSendConfirmation(
) { ) {
val walletViewModel by viewModels<WalletViewModel>() val walletViewModel by viewModels<WalletViewModel>()
val sendViewModel by viewModels<SendConfirmationViewModel>() val createTransactionsViewModel by viewModels<CreateTransactionsViewModel>()
val viewModel by viewModels<SupportViewModel>() val viewModel by viewModels<SupportViewModel>()
@ -65,7 +65,7 @@ internal fun MainActivity.WrapSendConfirmation(
arguments = arguments, arguments = arguments,
goBack = goBack, goBack = goBack,
goHome = goHome, goHome = goHome,
sendViewModel = sendViewModel, createTransactionsViewModel = createTransactionsViewModel,
spendingKey = spendingKey, spendingKey = spendingKey,
supportMessage = supportMessage, supportMessage = supportMessage,
synchronizer = synchronizer, synchronizer = synchronizer,
@ -80,7 +80,7 @@ internal fun WrapSendConfirmation(
arguments: SendConfirmationArguments, arguments: SendConfirmationArguments,
goBack: (clearForm: Boolean) -> Unit, goBack: (clearForm: Boolean) -> Unit,
goHome: () -> Unit, goHome: () -> Unit,
sendViewModel: SendConfirmationViewModel, createTransactionsViewModel: CreateTransactionsViewModel,
spendingKey: UnifiedSpendingKey?, spendingKey: UnifiedSpendingKey?,
supportMessage: SupportInfo?, supportMessage: SupportInfo?,
synchronizer: Synchronizer?, synchronizer: Synchronizer?,
@ -89,17 +89,22 @@ internal fun WrapSendConfirmation(
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val zecSend by rememberSaveable(stateSaver = ZecSend.Saver) { mutableStateOf(arguments.toZecSend()) } val zecSend by rememberSaveable(stateSaver = ZecSend.Saver) {
mutableStateOf(
// Because of the [zecSend] has the same Saver as on the Send screen, we do not expect this to be ever null if (arguments.hasValidZecSend()) {
checkNotNull(zecSend) arguments.toZecSend()
} else {
null
}
)
}
val (stage, setStage) = val (stage, setStage) =
rememberSaveable(stateSaver = SendConfirmationStage.Saver) { rememberSaveable(stateSaver = SendConfirmationStage.Saver) {
mutableStateOf(SendConfirmationStage.Confirmation) mutableStateOf(arguments.initialStage ?: SendConfirmationStage.Confirmation)
} }
val submissionResults = sendViewModel.submissions.collectAsState().value.toImmutableList() val submissionResults = createTransactionsViewModel.submissions.collectAsState().value.toImmutableList()
val onBackAction = { val onBackAction = {
when (stage) { when (stage) {
@ -124,7 +129,7 @@ internal fun WrapSendConfirmation(
SendConfirmation( SendConfirmation(
stage = stage, stage = stage,
onStageChange = setStage, onStageChange = setStage,
zecSend = zecSend!!, zecSend = zecSend,
submissionResults = submissionResults, submissionResults = submissionResults,
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
onBack = onBackAction, onBack = onBackAction,
@ -167,7 +172,7 @@ internal fun WrapSendConfirmation(
checkNotNull(newZecSend.proposal) checkNotNull(newZecSend.proposal)
val result = val result =
sendViewModel.runSending( createTransactionsViewModel.runCreateTransactions(
synchronizer = synchronizer, synchronizer = synchronizer,
spendingKey = spendingKey, spendingKey = spendingKey,
proposal = newZecSend.proposal!! proposal = newZecSend.proposal!!

View File

@ -14,6 +14,7 @@ data class SendConfirmationArguments(
val amount: Long?, val amount: Long?,
val memo: String?, val memo: String?,
val proposal: ByteArray?, val proposal: ByteArray?,
val initialStage: SendConfirmationStage?,
) { ) {
companion object { companion object {
internal fun fromSavedStateHandle(savedStateHandle: SavedStateHandle) = internal fun fromSavedStateHandle(savedStateHandle: SavedStateHandle) =
@ -25,9 +26,23 @@ data class SendConfirmationArguments(
amount = savedStateHandle.get<Long>(NavigationArguments.SEND_CONFIRM_AMOUNT), amount = savedStateHandle.get<Long>(NavigationArguments.SEND_CONFIRM_AMOUNT),
memo = savedStateHandle.get<String>(NavigationArguments.SEND_CONFIRM_MEMO), memo = savedStateHandle.get<String>(NavigationArguments.SEND_CONFIRM_MEMO),
proposal = savedStateHandle.get<ByteArray>(NavigationArguments.SEND_CONFIRM_PROPOSAL), proposal = savedStateHandle.get<ByteArray>(NavigationArguments.SEND_CONFIRM_PROPOSAL),
) initialStage =
SendConfirmationStage
.fromStringName(savedStateHandle.get<String>(NavigationArguments.SEND_CONFIRM_INITIAL_STAGE))
).also {
// Remove SendConfirmation screen arguments passed from the other screens if some exist
savedStateHandle.remove<String>(NavigationArguments.SEND_CONFIRM_RECIPIENT_ADDRESS)
savedStateHandle.remove<Long>(NavigationArguments.SEND_CONFIRM_AMOUNT)
savedStateHandle.remove<String>(NavigationArguments.SEND_CONFIRM_MEMO)
savedStateHandle.remove<ByteArray>(NavigationArguments.SEND_CONFIRM_PROPOSAL)
savedStateHandle.remove<String>(NavigationArguments.SEND_CONFIRM_INITIAL_STAGE)
}
} }
internal fun hasValidZecSend() =
this.address != null &&
this.amount != null
internal fun toZecSend() = internal fun toZecSend() =
ZecSend( ZecSend(
destination = address?.toWalletAddress() ?: error("Address null"), destination = address?.toWalletAddress() ?: error("Address null"),

View File

@ -7,12 +7,22 @@ sealed class SendConfirmationStage {
data object Sending : SendConfirmationStage() data object Sending : SendConfirmationStage()
data class Failure(val error: String) : SendConfirmationStage() data class Failure(val error: String?) : SendConfirmationStage()
data object MultipleTrxFailure : SendConfirmationStage() data object MultipleTrxFailure : SendConfirmationStage()
data object MultipleTrxFailureReported : SendConfirmationStage() data object MultipleTrxFailureReported : SendConfirmationStage()
fun toStringName(): String {
return when (this) {
Confirmation -> TYPE_CONFIRMATION
is Failure -> TYPE_FAILURE
MultipleTrxFailure -> TYPE_MULTIPLE_TRX_FAILURE
MultipleTrxFailureReported -> TYPE_MULTIPLE_TRX_FAILURE_REPORTED
Sending -> TYPE_SENDING
}
}
companion object { companion object {
private const val TYPE_CONFIRMATION = "confirmation" // $NON-NLS private const val TYPE_CONFIRMATION = "confirmation" // $NON-NLS
private const val TYPE_SENDING = "sending" // $NON-NLS private const val TYPE_SENDING = "sending" // $NON-NLS
@ -52,7 +62,7 @@ sealed class SendConfirmationStage {
Sending -> saverMap[KEY_TYPE] = TYPE_SENDING Sending -> saverMap[KEY_TYPE] = TYPE_SENDING
is Failure -> { is Failure -> {
saverMap[KEY_TYPE] = TYPE_FAILURE saverMap[KEY_TYPE] = TYPE_FAILURE
saverMap[KEY_ERROR] = this.error saverMap[KEY_ERROR] = this.error ?: ""
} }
is MultipleTrxFailure -> saverMap[KEY_TYPE] = TYPE_MULTIPLE_TRX_FAILURE is MultipleTrxFailure -> saverMap[KEY_TYPE] = TYPE_MULTIPLE_TRX_FAILURE
is MultipleTrxFailureReported -> saverMap[KEY_TYPE] = TYPE_MULTIPLE_TRX_FAILURE_REPORTED is MultipleTrxFailureReported -> saverMap[KEY_TYPE] = TYPE_MULTIPLE_TRX_FAILURE_REPORTED
@ -60,5 +70,17 @@ sealed class SendConfirmationStage {
return saverMap return saverMap
} }
fun fromStringName(stringName: String?): SendConfirmationStage {
return when (stringName) {
TYPE_CONFIRMATION -> Confirmation
TYPE_SENDING -> Sending
// Add the String error parameter storing and retrieving
TYPE_FAILURE -> Failure(null)
TYPE_MULTIPLE_TRX_FAILURE -> MultipleTrxFailure
TYPE_MULTIPLE_TRX_FAILURE_REPORTED -> MultipleTrxFailureReported
else -> Confirmation
}
}
} }
} }

View File

@ -134,7 +134,7 @@ fun SendConfirmation(
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
stage: SendConfirmationStage, stage: SendConfirmationStage,
submissionResults: ImmutableList<TransactionSubmitResult>, submissionResults: ImmutableList<TransactionSubmitResult>,
zecSend: ZecSend, zecSend: ZecSend?,
) { ) {
Scaffold( Scaffold(
topBar = { SendConfirmationTopAppBar(onBack, stage) }, topBar = { SendConfirmationTopAppBar(onBack, stage) },
@ -197,11 +197,14 @@ private fun SendConfirmationMainContent(
onStageChange: (SendConfirmationStage) -> Unit, onStageChange: (SendConfirmationStage) -> Unit,
stage: SendConfirmationStage, stage: SendConfirmationStage,
submissionResults: ImmutableList<TransactionSubmitResult>, submissionResults: ImmutableList<TransactionSubmitResult>,
zecSend: ZecSend, zecSend: ZecSend?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
when (stage) { when (stage) {
SendConfirmationStage.Confirmation, SendConfirmationStage.Sending, is SendConfirmationStage.Failure -> { SendConfirmationStage.Confirmation, SendConfirmationStage.Sending, is SendConfirmationStage.Failure -> {
if (zecSend == null) {
error("Unexpected ZecSend value: $zecSend")
}
SendConfirmationContent( SendConfirmationContent(
zecSend = zecSend, zecSend = zecSend,
onBack = onBack, onBack = onBack,
@ -371,7 +374,7 @@ fun SendConfirmationActionButtons(
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
private fun SendFailure( private fun SendFailure(
onDone: () -> Unit, onDone: () -> Unit,
reason: String, reason: String?,
) { ) {
// Once we ensure that the [reason] contains a localized message, we can leverage it for the UI prompt // Once we ensure that the [reason] contains a localized message, we can leverage it for the UI prompt

View File

@ -10,12 +10,12 @@ import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SubmitResult import co.electriccoin.zcash.ui.screen.sendconfirmation.model.SubmitResult
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
class SendConfirmationViewModel(application: Application) : AndroidViewModel(application) { class CreateTransactionsViewModel(application: Application) : AndroidViewModel(application) {
// Technically this value will not survive process dead, but will survive all possible configuration changes // Technically this value will not survive process dead, but will survive all possible configuration changes
// Possible solution would be storing the value within [SavedStateHandle] // Possible solution would be storing the value within [SavedStateHandle]
val submissions: MutableStateFlow<List<TransactionSubmitResult>> = MutableStateFlow(emptyList()) val submissions: MutableStateFlow<List<TransactionSubmitResult>> = MutableStateFlow(emptyList())
suspend fun runSending( suspend fun runCreateTransactions(
synchronizer: Synchronizer, synchronizer: Synchronizer,
spendingKey: UnifiedSpendingKey, spendingKey: UnifiedSpendingKey,
proposal: Proposal proposal: Proposal