summaryrefslogtreecommitdiff
path: root/wallet/src/main/java/net/taler
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2023-08-16 16:03:45 +0200
committerTorsten Grote <t@grobox.de>2023-09-26 18:30:51 +0200
commitb38d99fd60737a4087948bd3e4ee6b18d756c639 (patch)
treeb8f3004fbef4f8ae8ccf9ec6fc06fca1ad743a0c /wallet/src/main/java/net/taler
parentcb6d8362746481b383d559280c8cfadbed082231 (diff)
downloadtaler-android-b38d99fd60737a4087948bd3e4ee6b18d756c639.tar.gz
taler-android-b38d99fd60737a4087948bd3e4ee6b18d756c639.tar.bz2
taler-android-b38d99fd60737a4087948bd3e4ee6b18d756c639.zip
[wallet] Improved templates UX and PoS confirmation codes
Diffstat (limited to 'wallet/src/main/java/net/taler')
-rw-r--r--wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt152
-rw-r--r--wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt1
-rw-r--r--wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt1
4 files changed, 110 insertions, 50 deletions
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 ab6dada..633ab20 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt
@@ -21,16 +21,21 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Button
+import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -43,6 +48,8 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.fragment.app.Fragment
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.AmountParserException
@@ -84,15 +91,22 @@ 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())
}
}
- fun createOrder(params: Map<String, String>) {
- uriString?.let {
- model.paymentManager.preparePayForTemplate(it, params,).invokeOnCompletion {
- findNavController().navigate(R.id.action_global_promptPayment)
+ private fun createOrder(params: Map<String, String>) {
+ uriString ?: return
+ model.paymentManager.preparePayForTemplate(uriString!!, params,).invokeOnCompletion {
+ if (model.paymentManager.payStatus.value is PayStatus.Prepared) {
+ val navOptions = NavOptions.Builder()
+ .setPopUpTo(R.id.nav_main, true)
+ .build()
+ findNavController()
+ .navigate(R.id.action_global_promptPayment, null, navOptions)
}
}
}
@@ -126,61 +140,99 @@ fun PayTemplateComposable(
} else null,
) }
- Column(horizontalAlignment = Alignment.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)) },
- )
- }
+ val payStatus by model.paymentManager.payStatus.asFlow()
+ .collectAsState(initial = PayStatus.None)
- if ("amount" in queryParams) {
- AmountField(
- modifier = Modifier
- .padding(16.dp)
- .fillMaxWidth(),
- amount = amount!!,
- currencies = currencies,
- onAmountChosen = { amount = it },
+ // 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 = Alignment.Center,
+ ) {
+ Text(
+ stringResource(R.string.payment_balance_insufficient),
+ style = MaterialTheme.typography.titleLarge,
+ color = MaterialTheme.colorScheme.error,
)
}
+ } else when (payStatus) {
+ is PayStatus.None -> {
+ Column(horizontalAlignment = Alignment.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)) },
+ )
+ }
- Button(
- modifier = Modifier.padding(16.dp),
- enabled = summary == null || summary!!.isNotBlank(),
- onClick = {
- if (amount != null) {
- val result = model.createAmount(
- amount!!.amountStr,
- amount!!.currency,
+ if ("amount" in queryParams) {
+ AmountField(
+ modifier = Modifier
+ .padding(16.dp)
+ .fillMaxWidth(),
+ amount = amount!!,
+ currencies = currencies,
+ onAmountChosen = { amount = it },
)
- when (result) {
- AmountResult.InsufficientBalance -> {
- fragment.showError(R.string.payment_balance_insufficient)
- }
- AmountResult.InvalidAmount -> {
- fragment.showError(R.string.receive_amount_invalid)
- }
- else -> {
- onSubmit(
- mutableMapOf<String, String>().apply {
- if (summary != null) put("summary", summary!!)
- if (amount != null) put("amount", amount!!.toJSONString())
- }
+ }
+
+ Button(
+ modifier = Modifier.padding(16.dp),
+ enabled = summary == null || summary!!.isNotBlank(),
+ onClick = {
+ if (amount != null) {
+ val result = model.createAmount(
+ amount!!.amountStr,
+ amount!!.currency,
)
+ when (result) {
+ AmountResult.InsufficientBalance -> {
+ fragment.showError(R.string.payment_balance_insufficient)
+ }
+ AmountResult.InvalidAmount -> {
+ fragment.showError(R.string.receive_amount_invalid)
+ }
+ else -> {
+ onSubmit(
+ mutableMapOf<String, String>().apply {
+ if (summary != null) put("summary", summary!!)
+ if (amount != null) put("amount", amount!!.toJSONString())
+ }
+ )
+ }
+ }
}
- }
+ },
+ ) {
+ Text(stringResource(R.string.payment_create_order))
}
- },
- ) {
- Text(stringResource(R.string.payment_create_order))
+ }
+ }
+ is PayStatus.Loading -> {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center,
+ ) { CircularProgressIndicator() }
+ }
+ is PayStatus.AlreadyPaid -> {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center,
+ ) {
+ Text(
+ stringResource(R.string.payment_already_paid),
+ style = MaterialTheme.typography.titleLarge,
+ color = MaterialTheme.colorScheme.error,
+ )
+ }
}
+ else -> {}
}
}
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
index 538f2e1..c98e0b2 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
@@ -104,6 +104,7 @@ class PaymentManager(
}
fun preparePayForTemplate(url: String, params: Map<String, String>) = scope.launch {
+ mPayStatus.value = PayStatus.Loading
api.request("preparePayForTemplate", PreparePayResponse.serializer()) {
put("talerPayTemplateUri", url)
put("templateParams", JSONObject().apply {
diff --git a/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
index e6a65d1..c08bc76 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
@@ -88,6 +88,12 @@ fun TransactionPaymentComposable(
amount = t.amountEffective - t.amountRaw,
amountType = AmountType.Negative,
)
+ if (t.posConfirmation != null) {
+ TransactionInfoComposable(
+ label = stringResource(id = R.string.payment_confirmation_code),
+ info = t.posConfirmation,
+ )
+ }
PurchaseDetails(info = t.info) {
onFulfill(t.info.fulfillmentUrl ?: "")
}
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
index c6be73a..536d433 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -218,6 +218,7 @@ class TransactionPayment(
override val error: TalerErrorInfo? = null,
override val amountRaw: Amount,
override val amountEffective: Amount,
+ val posConfirmation: String? = null,
) : Transaction() {
override val icon = R.drawable.ic_cash_usd_outline
override val detailPageNav = R.id.action_nav_transactions_detail_payment