taler-android

Android apps for GNU Taler (wallet, PoS, cashier)
Log | Files | Refs | README | LICENSE

commit 3fa0612fae6cbd92701d04cd84ac60fccbac016e
parent 4b5de099fc60676472eed59e70d015321087600c
Author: Iván Ávalos <avalos@disroot.org>
Date:   Thu,  6 Jun 2024 10:56:58 -0600

[wallet] Add QR code scan button to send/receive screens

bug 0008902

Diffstat:
Mwallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt | 63++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mwallet/src/main/java/net/taler/wallet/SendFundsFragment.kt | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 114 insertions(+), 20 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt b/wallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt @@ -25,12 +25,20 @@ import android.widget.Toast.LENGTH_LONG import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccountBalance +import androidx.compose.material.icons.filled.AccountBalanceWallet +import androidx.compose.material.icons.filled.QrCodeScanner import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -43,6 +51,7 @@ 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.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.os.bundleOf @@ -76,6 +85,7 @@ class ReceiveFundsFragment : Fragment() { balanceManager.getSpecForScopeInfo(scopeInfo), this@ReceiveFundsFragment::onManualWithdraw, this@ReceiveFundsFragment::onPeerPull, + this@ReceiveFundsFragment::onScanQr, ) } } @@ -113,6 +123,10 @@ class ReceiveFundsFragment : Fragment() { peerManager.checkPeerPullCredit(amount) findNavController().navigate(R.id.action_receiveFunds_to_nav_peer_pull, bundle) } + + private fun onScanQr() { + model.scanCode() + } } @Composable @@ -121,6 +135,7 @@ private fun ReceiveFundsIntro( spec: CurrencySpecification?, onManualWithdraw: (Amount) -> Unit, onPeerPull: (Amount) -> Unit, + onScanQr: () -> Unit, ) { val scrollState = rememberScrollState() Column( @@ -163,31 +178,61 @@ private fun ReceiveFundsIntro( text = stringResource(R.string.receive_intro), style = MaterialTheme.typography.titleLarge, ) - Row(modifier = Modifier.padding(16.dp)) { + Column(modifier = Modifier.padding(16.dp)) { Button( - modifier = Modifier - .padding(end = 16.dp) - .height(IntrinsicSize.Max) - .weight(1f), + modifier = Modifier.fillMaxWidth(), onClick = { val amount = getAmount(currency, text) if (amount == null || amount.isZero()) isError = true else onManualWithdraw(amount) }) { + Icon( + Icons.Default.AccountBalance, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text(text = stringResource(R.string.receive_withdraw)) } + Button( - modifier = Modifier - .weight(1f) - .height(IntrinsicSize.Max), + modifier = Modifier.fillMaxWidth(), onClick = { val amount = getAmount(currency, text) if (amount == null || amount.isZero()) isError = true else onPeerPull(amount) }, ) { + Icon( + Icons.Default.AccountBalanceWallet, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text(text = stringResource(R.string.receive_peer)) } + + Text( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + text = stringResource(id = R.string.or), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyLarge, + ) + + Button( + modifier = Modifier.fillMaxWidth(), + onClick = { onScanQr() }, + ) { + Icon( + Icons.Default.QrCodeScanner, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(Modifier.size(ButtonDefaults.IconSpacing)) + Text(text = stringResource(R.string.button_scan_qr_code_label)) + } } } } @@ -196,6 +241,6 @@ private fun ReceiveFundsIntro( @Composable fun PreviewReceiveFundsIntro() { Surface { - ReceiveFundsIntro("TESTKUDOS", null, {}) {} + ReceiveFundsIntro("TESTKUDOS", null, {}, {}) {} } } diff --git a/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt b/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt @@ -21,14 +21,21 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccountBalance +import androidx.compose.material.icons.filled.AccountBalanceWallet +import androidx.compose.material.icons.filled.CurrencyBitcoin +import androidx.compose.material.icons.filled.QrCodeScanner import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -41,6 +48,7 @@ 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.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.os.bundleOf @@ -72,6 +80,7 @@ class SendFundsFragment : Fragment() { hasSufficientBalance = model::hasSufficientBalance, onDeposit = this@SendFundsFragment::onDeposit, onPeerPush = this@SendFundsFragment::onPeerPush, + onScanQr = this@SendFundsFragment::onScanQr, ) } } @@ -92,6 +101,10 @@ class SendFundsFragment : Fragment() { peerManager.checkPeerPushDebit(amount) findNavController().navigate(R.id.action_sendFunds_to_nav_peer_push, bundle) } + + private fun onScanQr() { + model.scanCode() + } } @Composable @@ -101,6 +114,7 @@ private fun SendFundsIntro( hasSufficientBalance: (Amount) -> Boolean, onDeposit: (Amount) -> Unit, onPeerPush: (Amount) -> Unit, + onScanQr: () -> Unit, ) { val scrollState = rememberScrollState() Column( @@ -148,41 +162,76 @@ private fun SendFundsIntro( text = stringResource(R.string.send_intro), style = MaterialTheme.typography.titleLarge, ) - Row(modifier = Modifier.padding(16.dp)) { + Column(modifier = Modifier.padding(16.dp)) { fun onClickButton(block: (Amount) -> Unit) { val amount = getAmount(currency, text) if (amount == null || amount.isZero()) isError = true else if (!hasSufficientBalance(amount)) insufficientBalance = true else block(amount) } + Button( - modifier = Modifier - .padding(end = 16.dp) - .height(IntrinsicSize.Max) - .weight(1f), + modifier = Modifier.fillMaxWidth(), onClick = { onClickButton { amount -> onDeposit(amount) } }) { + Icon( + if (currency == CURRENCY_BTC) { + Icons.Default.CurrencyBitcoin + } else { + Icons.Default.AccountBalance + }, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text(text = if (currency == CURRENCY_BTC) { stringResource(R.string.send_deposit_bitcoin) } else { stringResource(R.string.send_deposit) }) } + Button( - modifier = Modifier - .height(IntrinsicSize.Max) - .weight(1f), + modifier = Modifier.fillMaxWidth(), onClick = { onClickButton { amount -> onPeerPush(amount) } }, ) { + Icon( + Icons.Default.AccountBalanceWallet, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(Modifier.size(ButtonDefaults.IconSpacing)) Text(text = if (currency == CURRENCY_BTC) { stringResource(R.string.send_peer_bitcoin) } else { stringResource(R.string.send_peer) }) } + + Text( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + text = stringResource(id = R.string.or), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyLarge, + ) + + Button( + modifier = Modifier.fillMaxWidth(), + onClick = { onScanQr() }, + ) { + Icon( + Icons.Default.QrCodeScanner, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(Modifier.size(ButtonDefaults.IconSpacing)) + Text(text = stringResource(R.string.button_scan_qr_code_label)) + } } } } @@ -191,6 +240,6 @@ private fun SendFundsIntro( @Composable fun PreviewSendFundsIntro() { Surface { - SendFundsIntro("TESTKUDOS", null, { true }, {}) {} + SendFundsIntro("TESTKUDOS", null, { true }, {}, {}) {} } }