diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransitionsComposable.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransitionsComposable.kt index f654604f..e0045197 100644 --- a/wallet/src/main/java/net/taler/wallet/transactions/TransitionsComposable.kt +++ b/wallet/src/main/java/net/taler/wallet/transactions/TransitionsComposable.kt @@ -18,6 +18,7 @@ package net.taler.wallet.transactions import androidx.compose.foundation.layout.Arrangement.Center import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row @@ -27,6 +28,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -42,11 +44,15 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.serialization.json.Json import net.taler.lib.android.copyToClipBoard import net.taler.wallet.R +import net.taler.wallet.backend.TalerErrorInfo +import net.taler.wallet.compose.Banner import net.taler.wallet.transactions.TransactionAction.* @OptIn(ExperimentalLayoutApi::class) @@ -99,9 +105,19 @@ fun TransitionsComposable( }) } + // Developer mode has the raw JSON (ErrorTransactionButton); everybody + // else gets told that the wallet is stuck on an error and why. + val error = t.error + if (error != null && !devMode) { + TransactionErrorBanner(error) + } + FlowRow(horizontalArrangement = Center) { t.txActions.forEach { - if (it in arrayOf(Resume, Suspend, Retry)) { + if (it == Retry && error != null) { + // a failing transaction can be retried by anybody + TransitionComposable(it, onTransition) + } else if (it in arrayOf(Resume, Suspend, Retry)) { if (devMode) TransitionComposable(it, onTransition) } else { TransitionComposable(it, onTransition) @@ -117,6 +133,42 @@ fun TransitionsComposable( } } +@Composable +fun TransactionErrorBanner(error: TalerErrorInfo) { + Banner( + modifier = Modifier.padding(top = 16.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.errorContainer, + contentColor = MaterialTheme.colorScheme.onErrorContainer, + ), + ) { + Column(Modifier.fillMaxWidth()) { + Text( + text = stringResource(R.string.transaction_error_title), + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth(), + ) + Text( + text = error.userFacingMsg.ifEmpty { + stringResource(R.string.error_code_only, error.rawCode) + }, + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + ) + Text( + text = stringResource(R.string.transaction_error_retry_hint), + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + ) + } + } +} + @Composable fun TransitionComposable(t: TransactionAction, onClick: (t: TransactionAction) -> Unit) { var showConfirmDialog by remember { mutableStateOf(false) } diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml index 89750709..8ac36512 100644 --- a/wallet/src/main/res/values/strings.xml +++ b/wallet/src/main/res/values/strings.xml @@ -210,6 +210,8 @@ GNU Taler is immune to many types of fraud such as credit card data theft, phish This transaction has failed or been abandoned This transaction is finalizing This transaction is pending + The wallet reported a problem + The wallet will retry automatically. You can also retry now. Waiting for authorization in the bank This transaction would exceed a limit set by the payment service. To increase the limit, follow the instructions linked below. You need to prove having control over the bank account for the deposit. To continue, follow the instructions linked below.