[#1312] Display SDK error cause in dialog

* [#1312] Display SDK error cause in dialog

- Closes #1312
- Changelog reverter as the previous release hasn’t been deployed yet due to a new bug

* Too long dialog text scrollable
This commit is contained in:
Honza Rychnovský 2024-04-02 08:29:08 +02:00 committed by GitHub
parent a8ad649ef8
commit c8a14f0375
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 154 additions and 50 deletions

View File

@ -9,8 +9,6 @@ directly impact users rather than highlighting other key architectural updates.*
## [Unreleased]
## [0.2.0 (583)] - 2024-03-29
### Added
- Advanced Settings screen that provides more technical options like Export private data, Recovery phrase, or
Choose server has been added
@ -28,6 +26,7 @@ directly impact users rather than highlighting other key architectural updates.*
- Reworked Send screens flow and their look (e.g., Send Failure screen is now a modal dialog instead of a separate
screen)
- The sending and shielding funds logic has been connected to the new Proposal API from the Zcash SDK
- The error dialog contains an error description now. It's useful for tracking down the failure cause.
### Fixed
- Button sizing has been updated to align with the design guidelines and preserve stretching if necessary

View File

@ -57,7 +57,7 @@ fun AppAlertDialog(
onDismissButtonClick: (() -> Unit)? = null,
icon: ImageVector? = null,
title: String? = null,
text: String? = null,
text: @Composable (() -> Unit)? = null,
properties: DialogProperties = DialogProperties()
) {
AlertDialog(
@ -82,9 +82,37 @@ fun AppAlertDialog(
}
},
title = title?.let { { Text(text = title) } },
text = text?.let { { Text(text = text) } },
text = text,
icon = icon?.let { { Icon(imageVector = icon, null) } },
properties = properties,
modifier = modifier,
)
}
@Composable
@Suppress("LongParameterList")
fun AppAlertDialog(
modifier: Modifier = Modifier,
onDismissRequest: (() -> Unit)? = null,
confirmButtonText: String? = null,
onConfirmButtonClick: (() -> Unit)? = null,
dismissButtonText: String? = null,
onDismissButtonClick: (() -> Unit)? = null,
icon: ImageVector? = null,
title: String? = null,
text: String? = null,
properties: DialogProperties = DialogProperties()
) {
AppAlertDialog(
onDismissRequest = onDismissRequest?.let { onDismissRequest } ?: {},
modifier = modifier,
confirmButtonText = confirmButtonText,
title = title,
text = { text?.let { Text(text = text) } },
icon = icon,
properties = properties,
onConfirmButtonClick = onConfirmButtonClick,
dismissButtonText = dismissButtonText,
onDismissButtonClick = onDismissButtonClick
)
}

View File

@ -26,6 +26,7 @@ import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -41,6 +42,7 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -152,9 +154,9 @@ fun Balances(
)
// Show shielding error popup
if (isShowingErrorDialog) {
if (isShowingErrorDialog && shieldState is ShieldState.Failed) {
ShieldingErrorDialog(
shieldState = shieldState,
reason = shieldState.error,
onDone = { setShowErrorDialog(false) }
)
}
@ -163,16 +165,32 @@ fun Balances(
}
@Composable
@Suppress("UNUSED_PARAMETER")
fun ShieldingErrorDialog(
shieldState: ShieldState,
reason: String,
onDone: () -> Unit
) {
// Once we ensure that the [shieldState] contains a localized message, we can leverage it for the UI prompt
// TODO [#1276]: Once we ensure that reason contains a localized message, we can leverage it for the UI prompt
// TODO [#1276]: Consider adding support for a specific exception in AppAlertDialog
// TODO [#1276]: https://github.com/Electric-Coin-Company/zashi-android/issues/1276
AppAlertDialog(
title = stringResource(id = R.string.balances_shielding_dialog_error_title),
text = stringResource(id = R.string.balances_shielding_dialog_error_text),
text = {
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = stringResource(id = R.string.balances_shielding_dialog_error_text))
if (reason.isNotEmpty()) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
Text(
text = reason,
fontStyle = FontStyle.Italic
)
}
}
},
confirmButtonText = stringResource(id = R.string.balances_shielding_dialog_error_btn),
onConfirmButtonClick = onDone
)
@ -351,6 +369,7 @@ fun TransparentBalanceRow(
Modifier
.clip(RoundedCornerShape(ZcashTheme.dimens.smallRippleEffectCorner))
.clickable { onHelpClick() }
.padding(end = ZcashTheme.dimens.spacingXtiny)
) {
BodySmall(text = stringResource(id = R.string.balances_transparent_balance).uppercase())

View File

@ -22,6 +22,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
@ -105,9 +106,9 @@ fun ChooseServer(
)
// Show validation popups
if (isShowingErrorDialog) {
if (isShowingErrorDialog && validationResult is ServerValidation.InValid) {
ValidationErrorDialog(
validationResult = validationResult,
reason = validationResult.reason.message,
onDone = { setShowErrorDialog(false) }
)
} else if (isShowingSuccessDialog) {
@ -346,16 +347,32 @@ fun SaveButton(
}
@Composable
@Suppress("UNUSED_PARAMETER")
fun ValidationErrorDialog(
validationResult: ServerValidation,
reason: String?,
onDone: () -> Unit
) {
// Once we ensure that the [validationResult] contains a localized message, we can leverage it for the UI prompt
// TODO [#1276]: Once we ensure that the reason contains a localized message, we can leverage it for the UI prompt
// TODO [#1276]: Consider adding support for a specific exception in AppAlertDialog
// TODO [#1276]: https://github.com/Electric-Coin-Company/zashi-android/issues/1276
AppAlertDialog(
title = stringResource(id = R.string.choose_server_validation_dialog_error_title),
text = stringResource(id = R.string.choose_server_validation_dialog_error_text),
text = {
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = stringResource(id = R.string.choose_server_validation_dialog_error_text))
if (!reason.isNullOrEmpty()) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
Text(
text = reason,
fontStyle = FontStyle.Italic
)
}
}
},
confirmButtonText = stringResource(id = R.string.choose_server_validation_dialog_error_btn),
onConfirmButtonClick = onDone
)

View File

@ -34,6 +34,7 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
@ -98,19 +99,6 @@ private fun PreviewSendForm() {
}
}
@Composable
@Preview("SendFailure")
private fun PreviewSendFailure() {
ZcashTheme(forceDarkMode = false) {
GradientSurface {
SendFailure(
onDone = {},
reason = "Insufficient balance"
)
}
}
}
// TODO [#1260]: Cover Send screens UI with tests
// TODO [#1260]: https://github.com/Electric-Coin-Company/zashi-android/issues/1260
@ -671,17 +659,46 @@ fun SendFormMemoTextField(
}
@Composable
@Suppress("UNUSED_PARAMETER")
@Preview("SendFailure")
private fun PreviewSendFailure() {
ZcashTheme(forceDarkMode = false) {
GradientSurface {
SendFailure(
onDone = {},
reason = "Insufficient balance"
)
}
}
}
@Composable
private fun SendFailure(
onDone: () -> Unit,
reason: String,
modifier: Modifier = Modifier
) {
// Once we ensure that the [reason] contains a localized message, we can leverage it for the UI prompt
// TODO [#1276]: Once we ensure that the reason contains a localized message, we can leverage it for the UI prompt
// TODO [#1276]: Consider adding support for a specific exception in AppAlertDialog
// TODO [#1276]: https://github.com/Electric-Coin-Company/zashi-android/issues/1276
AppAlertDialog(
title = stringResource(id = R.string.send_dialog_error_title),
text = stringResource(id = R.string.send_dialog_error_text),
text = {
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = stringResource(id = R.string.send_dialog_error_text))
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
Text(
text = reason,
fontStyle = FontStyle.Italic
)
}
},
confirmButtonText = stringResource(id = R.string.send_dialog_error_btn),
onConfirmButtonClick = onDone
onConfirmButtonClick = onDone,
modifier = modifier
)
}

View File

@ -22,6 +22,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -29,6 +30,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@ -58,19 +60,6 @@ import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.runBlocking
@Composable
@Preview("SendConfirmationFailure")
private fun PreviewSendConfirmationFailure() {
ZcashTheme(forceDarkMode = false) {
GradientSurface {
SendFailure(
onDone = {},
reason = "Failed due to network error"
)
}
}
}
@Composable
@Preview("SendConfirmation")
private fun PreviewSendConfirmation() {
@ -371,16 +360,45 @@ fun SendConfirmationActionButtons(
}
@Composable
@Suppress("UNUSED_PARAMETER")
@Preview("SendConfirmationFailure")
private fun PreviewSendConfirmationFailure() {
ZcashTheme(forceDarkMode = false) {
GradientSurface {
SendFailure(
onDone = {},
reason = "Failed due to network error"
)
}
}
}
@Composable
private fun SendFailure(
onDone: () -> Unit,
reason: String?,
) {
// Once we ensure that the [reason] contains a localized message, we can leverage it for the UI prompt
// TODO [#1276]: Once we ensure that the reason contains a localized message, we can leverage it for the UI prompt
// TODO [#1276]: Consider adding support for a specific exception in AppAlertDialog
// TODO [#1276]: https://github.com/Electric-Coin-Company/zashi-android/issues/1276
AppAlertDialog(
title = stringResource(id = R.string.send_confirmation_dialog_error_title),
text = stringResource(id = R.string.send_confirmation_dialog_error_text),
text = {
Column(
Modifier.verticalScroll(rememberScrollState())
) {
Text(text = stringResource(id = R.string.send_confirmation_dialog_error_text))
if (!reason.isNullOrEmpty()) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
Text(
text = reason,
fontStyle = FontStyle.Italic
)
}
}
},
confirmButtonText = stringResource(id = R.string.send_confirmation_dialog_error_btn),
onConfirmButtonClick = onDone
)

View File

@ -35,7 +35,13 @@ class CreateTransactionsViewModel(application: Application) : AndroidViewModel(a
// The first transaction submission failed - user might just be able to re-submit the transaction
// proposal. Simple error pop up is fine then
SubmitResult.SimpleTrxFailure(
(submitResults[0] as TransactionSubmitResult.Failure).description ?: ""
errorDescription =
buildString {
val result = (submitResults[0] as TransactionSubmitResult.Failure)
appendLine("Error code: ${result.code}")
appendLine("Is gRPC error: ${result.grpcError}")
appendLine(result.description ?: "")
}
)
} else {
// Any subsequent transaction submission failed - user needs to resolve this manually. Multiple