diff options
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt')
-rw-r--r-- | wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt | 219 |
1 files changed, 12 insertions, 207 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 633ab20..080d319 100644 --- a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateFragment.kt @@ -21,65 +21,35 @@ 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 -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView -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.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 -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 -import net.taler.wallet.deposit.CurrencyDropdown -class PayTemplateFragment: Fragment() { +class PayTemplateFragment : Fragment() { + private val model: MainViewModel by activityViewModels() - private var uriString: String? = null - private var uri: Uri? = null + private lateinit var uriString: String + private lateinit var uri: Uri override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ): View { uriString = arguments?.getString("uri") ?: error("no amount passed") uri = Uri.parse(uriString) - val currencies = model.getCurrencies() return ComposeView(requireContext()).apply { setContent { TalerSurface { PayTemplateComposable( - uri = uri!!, - currencies = currencies, + uri = uri, + currencies = model.getCurrencies(), fragment = this@PayTemplateFragment, model = model, onSubmit = { createOrder(it) }, @@ -93,186 +63,21 @@ class PayTemplateFragment: Fragment() { 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) { + if (uri.queryParameterNames?.isEmpty() == true) { createOrder(emptyMap()) } } private fun createOrder(params: Map<String, String>) { - uriString ?: return - model.paymentManager.preparePayForTemplate(uriString!!, params,).invokeOnCompletion { + model.paymentManager.preparePayForTemplate(uriString, params).invokeOnCompletion { + // TODO maybe better to observe/collect payStatus instead of invokeOnCompletion + // and then only reacting to one of the possible payStatus values 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) + findNavController().navigate(R.id.action_global_promptPayment, null, navOptions) } } } } - -@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 = 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)) }, - ) - } - - 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 = 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 -> {} - } -} - -@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)) - }, - ) - } -}
\ No newline at end of file |