commit 79f3a999da50e87687132d057d7c635285f4c4ae
parent 167d0d8ac6ed2bfe01151de45336cc1e45102080
Author: Iván Ávalos <avalos@disroot.org>
Date: Wed, 29 May 2024 11:40:01 -0600
[wallet] Fix template defaults logic and currency options + auto focus for summary
bug 0008854
Diffstat:
4 files changed, 59 insertions(+), 31 deletions(-)
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt
@@ -46,13 +46,21 @@ fun PayTemplateComposable(
if (currencies.isEmpty()) {
PayTemplateError(stringResource(R.string.payment_balance_insufficient))
} else when (val p = payStatus) {
- is PayStatus.Checked -> PayTemplateOrderComposable(
- currencies = currencies,
- templateDetails = p.details,
- onCreateAmount = onCreateAmount,
- onError = onError,
- onSubmit = onSubmit,
- )
+ is PayStatus.Checked -> {
+ val usableCurrencies = currencies.intersect(p.supportedCurrencies.toSet()).toList()
+ if (usableCurrencies.isEmpty()) {
+ // If user doesn't have any supported currency, they can't pay either
+ PayTemplateError(stringResource(R.string.payment_balance_insufficient))
+ } else {
+ PayTemplateOrderComposable(
+ usableCurrencies = usableCurrencies,
+ templateDetails = p.details,
+ onCreateAmount = onCreateAmount,
+ onError = onError,
+ onSubmit = onSubmit,
+ )
+ }
+ }
is PayStatus.None, is PayStatus.Loading -> PayTemplateLoading()
is PayStatus.AlreadyPaid -> PayTemplateError(stringResource(R.string.payment_already_paid))
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateDetails.kt b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateDetails.kt
@@ -64,12 +64,6 @@ data class TemplateContractDetailsDefaults(
val minimumAge: Int? = null,
)
-fun TemplateContractDetailsDefaults?.isNullOrEmpty() =
- this == null || (summary == null
- && currency == null
- && amount == null
- && minimumAge == null)
-
@Serializable
class WalletTemplateDetails(
/**
@@ -105,11 +99,15 @@ class WalletTemplateDetails(
?: editableDefaults?.currency
?: templateContract.currency
- fun isSummaryEditable() = editableDefaults?.summary != null
+ fun isSummaryEditable() = templateContract.summary == null
+
+ fun isAmountEditable() = templateContract.amount == null
- fun isAmountEditable() = editableDefaults?.amount != null
+ fun isCurrencyEditable() = requiredCurrency == null && templateContract.currency == null
- fun isCurrencyEditable() = requiredCurrency == null && editableDefaults?.currency != null
+ fun isTemplateEditable() = isSummaryEditable()
+ || isAmountEditable()
+ || isCurrencyEditable()
// NOTE: it is important to nullify non-editable values!
fun toTemplateParams() = TemplateParams(
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt
@@ -79,7 +79,7 @@ class PayTemplateFragment : Fragment() {
showError(payStatus.error)
}
- is PayStatus.Checked -> if (payStatus.details.editableDefaults.isNullOrEmpty()) {
+ is PayStatus.Checked -> if (!payStatus.details.isTemplateEditable()) {
createOrder(payStatus.details.toTemplateParams())
}
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateOrderComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateOrderComposable.kt
@@ -24,12 +24,18 @@ import androidx.compose.material3.Button
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment.Companion.End
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -41,9 +47,10 @@ import net.taler.wallet.compose.AmountInputField
import net.taler.wallet.compose.TalerSurface
import net.taler.wallet.deposit.CurrencyDropdown
+@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun PayTemplateOrderComposable(
- currencies: List<String>, // assumed to have size > 0
+ usableCurrencies: List<String>, // non-empty intersection between the stored currencies and the ones supported by the merchant
templateDetails: WalletTemplateDetails,
onCreateAmount: (String, String) -> AmountResult,
onError: (msgRes: Int) -> Unit,
@@ -53,32 +60,40 @@ fun PayTemplateOrderComposable(
val defaultAmount = templateDetails.defaultAmount
val defaultCurrency = templateDetails.defaultCurrency
- var summary by remember { mutableStateOf(defaultSummary) }
- var currency by remember { mutableStateOf(defaultCurrency ?: currencies[0]) }
+ val summaryFocusRequester = remember { FocusRequester() }
+ val keyboardController = LocalSoftwareKeyboardController.current
+
+ var summary by remember { mutableStateOf(defaultSummary ?: "") }
+ var currency by remember { mutableStateOf(defaultCurrency ?: usableCurrencies[0]) }
var amount by remember { mutableStateOf(defaultAmount?.amountStr ?: "0") }
Column(horizontalAlignment = End) {
- if (defaultSummary != null) OutlinedTextField(
+ OutlinedTextField(
modifier = Modifier
.padding(horizontal = 16.dp)
- .fillMaxWidth(),
- value = summary ?: "",
- isError = summary.isNullOrBlank(),
+ .fillMaxWidth()
+ .focusRequester(summaryFocusRequester)
+ .onFocusChanged {
+ if (it.isFocused) {
+ keyboardController?.show()
+ }
+ },
+ value = summary,
+ isError = templateDetails.isSummaryEditable() && summary.isBlank(),
onValueChange = { summary = it },
singleLine = true,
readOnly = !templateDetails.isSummaryEditable(),
label = { Text(stringResource(R.string.withdraw_manual_ready_subject)) },
)
- if (defaultAmount != null || defaultCurrency != null) AmountField(
+ AmountField(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
amount = amount,
currency = currency,
- currencies = currencies,
- // TODO: uncomment when merchant supports multi-currency
- // readOnlyCurrency = !templateDetails.isCurrencyEditable(),
+ currencies = usableCurrencies,
+ readOnlyCurrency = !templateDetails.isCurrencyEditable(),
readOnlyAmount = !templateDetails.isAmountEditable(),
onAmountChosen = { a, c ->
amount = a
@@ -104,6 +119,13 @@ fun PayTemplateOrderComposable(
Text(stringResource(R.string.payment_create_order))
}
}
+
+ LaunchedEffect(Unit) {
+ if (templateDetails.isSummaryEditable()
+ && templateDetails.defaultSummary == null) {
+ summaryFocusRequester.requestFocus()
+ }
+ }
}
@Composable
@@ -156,7 +178,7 @@ fun PayTemplateDefaultPreview() {
TalerSurface {
PayTemplateOrderComposable(
templateDetails = defaultTemplateDetails,
- currencies = listOf("KUDOS", "ARS"),
+ usableCurrencies = listOf("KUDOS", "ARS"),
onCreateAmount = { text, currency ->
AmountResult.Success(amount = Amount.fromString(currency, text))
},
@@ -172,7 +194,7 @@ fun PayTemplateFixedAmountPreview() {
TalerSurface {
PayTemplateOrderComposable(
templateDetails = defaultTemplateDetails,
- currencies = listOf("KUDOS", "ARS"),
+ usableCurrencies = listOf("KUDOS", "ARS"),
onCreateAmount = { text, currency ->
AmountResult.Success(amount = Amount.fromString(currency, text))
},
@@ -188,7 +210,7 @@ fun PayTemplateBlankSubjectPreview() {
TalerSurface {
PayTemplateOrderComposable(
templateDetails = defaultTemplateDetails,
- currencies = listOf("KUDOS", "ARS"),
+ usableCurrencies = listOf("KUDOS", "ARS"),
onCreateAmount = { text, currency ->
AmountResult.Success(amount = Amount.fromString(currency, text))
},