diff options
author | Torsten Grote <t@grobox.de> | 2023-08-18 10:36:04 +0200 |
---|---|---|
committer | Torsten Grote <t@grobox.de> | 2023-09-26 18:30:51 +0200 |
commit | aa1be463c2a79d673f1dd2dd31538649a1cfb83c (patch) | |
tree | a510fb0868d635f329c1f5f031fa237bae7695a6 /wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt | |
parent | b38d99fd60737a4087948bd3e4ee6b18d756c639 (diff) | |
download | taler-android-aa1be463c2a79d673f1dd2dd31538649a1cfb83c.tar.gz taler-android-aa1be463c2a79d673f1dd2dd31538649a1cfb83c.tar.bz2 taler-android-aa1be463c2a79d673f1dd2dd31538649a1cfb83c.zip |
[wallet] first cleanup of payment template work
the PayTemplateComposable still needs refactoring
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt')
-rw-r--r-- | wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt | 228 |
1 files changed, 228 insertions, 0 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 new file mode 100644 index 0000000..3279c71 --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt @@ -0,0 +1,228 @@ +/* + * This file is part of GNU Taler + * (C) 2023 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +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 +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 +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Alignment.Companion.Center +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.fragment.app.Fragment +import androidx.lifecycle.asFlow +import net.taler.common.Amount +import net.taler.common.AmountParserException +import net.taler.common.showError +import net.taler.wallet.AmountResult +import net.taler.wallet.MainViewModel +import net.taler.wallet.R +import net.taler.wallet.deposit.CurrencyDropdown + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun PayTemplateComposable( + uri: Uri, + currencies: List<String>, + fragment: Fragment, + model: MainViewModel, + onSubmit: (Map<String, String>) -> Unit, +) { + val queryParams = uri.queryParameterNames + + var summary by remember { mutableStateOf( + if ("summary" in queryParams) + uri.getQueryParameter("summary") else null, + ) } + + var amount by remember { mutableStateOf( + 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]) + else -> throw AmountParserException("Invalid Amount Format") + } + } else null, + ) } + + val payStatus by model.paymentManager.payStatus.asFlow() + .collectAsState(initial = PayStatus.None) + + // 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, + ) + } + } 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)) }, + ) + } + + 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 = 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)) + } + } + } + is PayStatus.Loading -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Center, + ) { CircularProgressIndicator() } + } + is PayStatus.AlreadyPaid -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Center, + ) { + Text( + stringResource(R.string.payment_already_paid), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.error, + ) + } + } + else -> {} + } +} + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +private fun AmountField( + modifier: Modifier = Modifier, + currencies: List<String>, + amount: Amount, + onAmountChosen: (Amount) -> Unit, +) { + Row( + modifier = modifier, + ) { + val amountText = if (amount.value == 0L) "" else amount.value.toString() + val currency = currencies.find { amount.currency == it } ?: currencies[0] + OutlinedTextField( + modifier = Modifier + .padding(end = 16.dp) + .weight(1f), + value = amountText, + placeholder = { Text("0") }, + onValueChange = { input -> + if (input.isNotBlank()) { + onAmountChosen(Amount.fromString(currency, input)) + } else { + onAmountChosen(Amount.zero(currency)) + } + }, + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Decimal), + singleLine = true, + label = { Text(stringResource(R.string.send_amount)) }, + ) + CurrencyDropdown( + modifier = Modifier.weight(1f), + initialCurrency = currency, + currencies = currencies, + onCurrencyChanged = { c -> + onAmountChosen(Amount.fromString(c, amount.amountStr)) + }, + ) + } +} + +// TODO cleanup composable +//@Preview +//@Composable +//fun PayTemplateComposablePreview() { +// TalerSurface { +// PayTemplateComposable(Uri.EMPTY, listOf("KUDOS")) +// } +//} |