summaryrefslogtreecommitdiff
path: root/wallet/src/main/java/net/taler
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2023-08-29 11:45:00 -0600
committerTorsten Grote <t@grobox.de>2023-09-26 18:30:52 +0200
commit68a3c7ca5c615c35e3066780b909d2acb9eb3c8a (patch)
treedafee6b6cf8815e06dd9ca9fc8265a5a6bf03296 /wallet/src/main/java/net/taler
parent0fee8e1a1bd018dfb4625389159f38cf1d5b4f9b (diff)
downloadtaler-android-68a3c7ca5c615c35e3066780b909d2acb9eb3c8a.tar.gz
taler-android-68a3c7ca5c615c35e3066780b909d2acb9eb3c8a.tar.bz2
taler-android-68a3c7ca5c615c35e3066780b909d2acb9eb3c8a.zip
[wallet] Additional refactoring of pay templates
Diffstat (limited to 'wallet/src/main/java/net/taler')
-rw-r--r--wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt216
-rw-r--r--wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt22
2 files changed, 119 insertions, 119 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
index c8c3ba0..a5812c0 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt
@@ -16,7 +16,6 @@
package net.taler.wallet.payment
-import android.net.Uri
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -43,146 +42,130 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import net.taler.common.Amount
-import net.taler.common.AmountParserException
import net.taler.wallet.AmountResult
import net.taler.wallet.R
import net.taler.wallet.compose.TalerSurface
import net.taler.wallet.deposit.CurrencyDropdown
-@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PayTemplateComposable(
- uri: Uri,
+ summary: String?,
+ amountResult: AmountResult?,
currencies: List<String>,
payStatus: PayStatus,
onCreateAmount: (String, String) -> AmountResult,
onSubmit: (Map<String, String>) -> Unit,
onError: (resId: Int) -> Unit,
) {
- val queryParams = uri.queryParameterNames
-
- var summary by remember {
- mutableStateOf(
- // TODO pass this in as a parameter instead
- if ("summary" in queryParams) uri.getQueryParameter("summary") else null
- )
- }
- var amount by remember {
- mutableStateOf(
- // TODO don't do amount parsing in composable, but pass it in as a parameter
- if ("amount" in queryParams) {
- val amount = uri.getQueryParameter("amount")!!
- val parts = amount.split(':')
- when (parts.size) {
- 1 -> Amount.fromString(parts[0], "0")
- 2 -> Amount.fromString(parts[0], parts[1])
- // FIXME This will crash the app, we should show a proper error instead.
- else -> throw AmountParserException("Invalid Amount Format")
- }
- } else {
- null
+ // If wallet is empty, there's no way the user can pay something
+ if (amountResult is AmountResult.InvalidAmount) {
+ PayTemplateError(stringResource(R.string.receive_amount_invalid))
+ } else if (payStatus is PayStatus.InsufficientBalance || currencies.isEmpty()) {
+ PayTemplateError(stringResource(R.string.payment_balance_insufficient))
+ } else when (payStatus) {
+ is PayStatus.None -> PayTemplateDefault(
+ currencies = currencies,
+ summary = summary,
+ amount = amountResult?.let { (it as AmountResult.Success).amount },
+ onCreateAmount = onCreateAmount,
+ onError = onError,
+ onSubmit = { s, a ->
+ onSubmit(mutableMapOf<String, String>().apply {
+ s?.let { put("summary", it) }
+ a?.let { put("amount", it.toJSONString()) }
+ })
}
)
+ is PayStatus.Loading -> PayTemplateLoading()
+ is PayStatus.AlreadyPaid -> PayTemplateError(stringResource(R.string.payment_already_paid))
+
+ // TODO we should handle the other cases or explain why we don't handle them
+ else -> {}
}
+}
- // TODO we could think about splitting this up into separate composables
- // If wallet is empty, there's no way the user can pay something
- if (payStatus is PayStatus.InsufficientBalance || currencies.isEmpty()) {
- Box(
- modifier = Modifier.fillMaxSize(),
- contentAlignment = Center,
- ) {
- Text(
- text = stringResource(R.string.payment_balance_insufficient),
- style = MaterialTheme.typography.titleLarge,
- color = MaterialTheme.colorScheme.error,
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun PayTemplateDefault(
+ currencies: List<String>,
+ summary: String? = null,
+ amount: Amount? = null,
+ onCreateAmount: (String, String) -> AmountResult,
+ onError: (msgRes: Int) -> Unit,
+ onSubmit: (summary: String?, amount: Amount?) -> Unit,
+) {
+ var localSummary by remember { mutableStateOf(summary) }
+ var localAmount by remember { mutableStateOf(amount) }
+
+ Column(horizontalAlignment = End) {
+ localSummary?.let { summary ->
+ OutlinedTextField(
+ modifier = Modifier
+ .padding(horizontal = 16.dp)
+ .fillMaxWidth(),
+ value = summary,
+ isError = summary.isBlank(),
+ onValueChange = { localSummary = it },
+ singleLine = true,
+ label = { Text(stringResource(R.string.withdraw_manual_ready_subject)) },
)
}
- } else when (payStatus) {
- is PayStatus.None -> {
- Column(horizontalAlignment = End) {
- if ("summary" in queryParams) {
- OutlinedTextField(
- modifier = Modifier
- .padding(horizontal = 16.dp)
- .fillMaxWidth(),
- value = summary!!,
- isError = summary!!.isBlank(),
- onValueChange = { summary = it },
- singleLine = true,
- label = { Text(stringResource(R.string.withdraw_manual_ready_subject)) },
- )
- }
-
- if ("amount" in queryParams) {
- AmountField(
- modifier = Modifier
- .padding(16.dp)
- .fillMaxWidth(),
- amount = amount!!,
- currencies = currencies,
- onAmountChosen = { amount = it },
- )
- }
-
- Button(
- modifier = Modifier.padding(16.dp),
- enabled = summary == null || summary!!.isNotBlank(),
- onClick = {
- if (amount != null) {
- val result = onCreateAmount(
- amount!!.amountStr,
- amount!!.currency,
- )
- when (result) {
- AmountResult.InsufficientBalance -> {
- onError(R.string.payment_balance_insufficient)
- }
- AmountResult.InvalidAmount -> {
- onError(R.string.receive_amount_invalid)
- }
-
- else -> {
- onSubmit(
- mutableMapOf<String, String>().apply {
- summary?.let { put("summary", it) }
- amount?.let { put("amount", it.toJSONString()) }
- }
- )
- }
- }
- }
- },
- ) {
- Text(stringResource(R.string.payment_create_order))
- }
- }
+ localAmount?.let { amount ->
+ AmountField(
+ modifier = Modifier
+ .padding(16.dp)
+ .fillMaxWidth(),
+ amount = amount,
+ currencies = currencies,
+ onAmountChosen = { localAmount = it },
+ )
}
- is PayStatus.Loading -> {
- Box(
- modifier = Modifier.fillMaxSize(),
- contentAlignment = Center,
- ) { CircularProgressIndicator() }
+ Button(
+ modifier = Modifier.padding(16.dp),
+ enabled = localSummary == null || localSummary!!.isNotBlank(),
+ onClick = {
+ localAmount?.let { amount ->
+ val result = onCreateAmount(
+ amount.amountStr,
+ amount.currency,
+ )
+ when (result) {
+ AmountResult.InsufficientBalance -> onError(R.string.payment_balance_insufficient)
+ AmountResult.InvalidAmount -> onError(R.string.receive_amount_invalid)
+ else -> onSubmit(summary, amount)
+ }
+ }
+ },
+ ) {
+ Text(stringResource(R.string.payment_create_order))
}
+ }
+}
- is PayStatus.AlreadyPaid -> {
- Box(
- modifier = Modifier.fillMaxSize(),
- contentAlignment = Center,
- ) {
- Text(
- stringResource(R.string.payment_already_paid),
- style = MaterialTheme.typography.titleLarge,
- color = MaterialTheme.colorScheme.error,
- )
- }
- }
+@Composable
+fun PayTemplateError(message: String) {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Center,
+ ) {
+ Text(
+ text = message,
+ style = MaterialTheme.typography.titleLarge,
+ color = MaterialTheme.colorScheme.error,
+ )
+ }
+}
- // TODO we should handle the other cases or explain why we don't handle them
- else -> {}
+@Composable
+fun PayTemplateLoading() {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Center,
+ ) {
+ CircularProgressIndicator()
}
}
@@ -233,7 +216,8 @@ private fun AmountField(
fun PayTemplateComposablePreview() {
TalerSurface {
PayTemplateComposable(
- uri = Uri.parse("taler://pay-template/demo.backend.taler.net/test?amount=KUDOS&summary="),
+ summary = "Donation",
+ amountResult = AmountResult.Success(Amount("ARS", 20L, 0)),
currencies = listOf("KUDOS", "ARS"),
// TODO create previews for other states
payStatus = PayStatus.None,
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt
index 1812db0..93fe48c 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt
@@ -29,7 +29,9 @@ import androidx.fragment.app.activityViewModels
import androidx.lifecycle.asFlow
import androidx.navigation.NavOptions
import androidx.navigation.fragment.findNavController
+import net.taler.common.Amount
import net.taler.common.showError
+import net.taler.wallet.AmountResult
import net.taler.wallet.MainViewModel
import net.taler.wallet.R
import net.taler.wallet.compose.TalerSurface
@@ -49,6 +51,21 @@ class PayTemplateFragment : Fragment() {
uriString = arguments?.getString("uri") ?: error("no amount passed")
uri = Uri.parse(uriString)
+ val queryParams = uri.queryParameterNames
+
+ val summary = if ("summary" in queryParams)
+ uri.getQueryParameter("summary")!! else null
+
+ val amountResult = if ("amount" in queryParams) {
+ val amount = uri.getQueryParameter("amount")!!
+ val parts = amount.split(':')
+ when (parts.size) {
+ 1 -> AmountResult.Success(Amount.fromString(parts[0], "0"))
+ 2 -> AmountResult.Success(Amount.fromString(parts[0], parts[1]))
+ else -> AmountResult.InvalidAmount
+ }
+ } else null
+
return ComposeView(requireContext()).apply {
setContent {
val payStatus by model.paymentManager.payStatus
@@ -56,8 +73,9 @@ class PayTemplateFragment : Fragment() {
.collectAsState(initial = PayStatus.None)
TalerSurface {
PayTemplateComposable(
- uri = uri,
currencies = model.getCurrencies(),
+ summary = summary,
+ amountResult = amountResult,
payStatus = payStatus,
onCreateAmount = { text, currency ->
model.createAmount(text, currency)
@@ -72,8 +90,6 @@ class PayTemplateFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- // TODO: this is not ideal, if the template is fixed, the
- // user shouldn't even have to go through this fragment.
if (uri.queryParameterNames?.isEmpty() == true) {
createOrder(emptyMap())
}