[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-android] branch master updated (7cd48e3 -> 656ab6b)
From: |
gnunet |
Subject: |
[taler-taler-android] branch master updated (7cd48e3 -> 656ab6b) |
Date: |
Thu, 13 Apr 2023 16:34:07 +0200 |
This is an automated email from the git hooks/post-receive script.
torsten-grote pushed a change to branch master
in repository taler-android.
from 7cd48e3 [pos] Don't crash when adding custom product with huge
invalid amount
new 4d37a68 [wallet] Migrated withdrawal and refresh detail to Compose
new 5a9174f [wallet] Migrated payment and refund detail to Compose
new c2b8d13 [wallet] Remove exchangeBaseUrl from Refresh transactions
new 1c6fda4 [wallet] Clean up compose migration of withdrawal and refresh
transactions
new 656ab6b [wallet] Clean up compose migration of payment and refund
transactions
The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../TransactionPaymentComposable.kt} | 100 +++++++++---
.../TransactionRefundComposable.kt} | 73 +++++----
.../wallet/transactions/ActionButtonComposable.kt | 127 +++++++++++++++
.../transactions/TransactionDetailFragment.kt | 63 --------
.../transactions/TransactionLinkComposable.kt | 86 ++++++++++
.../transactions/TransactionPaymentFragment.kt | 53 +++----
.../transactions/TransactionRefreshFragment.kt | 106 +++++++++----
.../transactions/TransactionRefundFragment.kt | 58 +++----
.../transactions/TransactionWithdrawalFragment.kt | 130 ++++++---------
.../net/taler/wallet/transactions/Transactions.kt | 1 -
.../withdraw/TransactionWithdrawalComposable.kt | 147 +++++++++++++++++
.../res/layout/fragment_transaction_payment.xml | 149 -----------------
.../res/layout/fragment_transaction_withdrawal.xml | 176 ---------------------
wallet/src/main/res/navigation/nav_graph.xml | 21 +--
14 files changed, 647 insertions(+), 643 deletions(-)
copy
wallet/src/main/java/net/taler/wallet/{deposit/TransactionDepositComposable.kt
=> payment/TransactionPaymentComposable.kt} (51%)
copy
wallet/src/main/java/net/taler/wallet/{deposit/TransactionDepositComposable.kt
=> refund/TransactionRefundComposable.kt} (58%)
create mode 100644
wallet/src/main/java/net/taler/wallet/transactions/ActionButtonComposable.kt
create mode 100644
wallet/src/main/java/net/taler/wallet/transactions/TransactionLinkComposable.kt
create mode 100644
wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt
delete mode 100644 wallet/src/main/res/layout/fragment_transaction_payment.xml
delete mode 100644
wallet/src/main/res/layout/fragment_transaction_withdrawal.xml
diff --git
a/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt
b/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
similarity index 51%
copy from
wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt
copy to
wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
index 3d59b35..c760bb4 100644
---
a/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt
+++
b/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
@@ -1,6 +1,6 @@
/*
* This file is part of GNU Taler
- * (C) 2022 Taler Systems S.A.
+ * (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
@@ -14,7 +14,7 @@
* GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-package net.taler.wallet.deposit
+package net.taler.wallet.payment
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
@@ -22,36 +22,46 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
+import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import net.taler.common.Amount
+import net.taler.common.ContractMerchant
import net.taler.common.Timestamp
import net.taler.common.toAbsoluteTime
import net.taler.wallet.R
-import net.taler.wallet.backend.TalerErrorCode.EXCHANGE_GENERIC_KYC_REQUIRED
+import net.taler.wallet.backend.TalerErrorCode
import net.taler.wallet.backend.TalerErrorInfo
+import net.taler.wallet.compose.TalerSurface
import net.taler.wallet.transactions.AmountType
import net.taler.wallet.transactions.DeleteTransactionComposable
import net.taler.wallet.transactions.ErrorTransactionButton
-import net.taler.wallet.transactions.ExtendedStatus.Pending
+import net.taler.wallet.transactions.ExtendedStatus
+import net.taler.wallet.transactions.PaymentStatus
import net.taler.wallet.transactions.TransactionAmountComposable
-import net.taler.wallet.transactions.TransactionDeposit
+import net.taler.wallet.transactions.TransactionInfo
+import net.taler.wallet.transactions.TransactionInfoComposable
+import net.taler.wallet.transactions.TransactionLinkComposable
+import net.taler.wallet.transactions.TransactionPayment
@Composable
-fun TransactionDepositComposable(t: TransactionDeposit, devMode: Boolean?,
onDelete: () -> Unit) {
+fun TransactionPaymentComposable(
+ t: TransactionPayment,
+ devMode: Boolean,
+ onFulfill: (url: String) -> Unit,
+ onDelete: () -> Unit,
+) {
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(scrollState),
- horizontalAlignment = Alignment.CenterHorizontally,
+ horizontalAlignment = CenterHorizontally,
) {
val context = LocalContext.current
Text(
@@ -69,35 +79,75 @@ fun TransactionDepositComposable(t: TransactionDeposit,
devMode: Boolean?, onDel
amount = t.amountRaw,
amountType = AmountType.Neutral,
)
- val fee = t.amountEffective - t.amountRaw
- if (!fee.isZero()) {
- TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
- amount = fee,
- amountType = AmountType.Negative,
- )
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.withdraw_fees),
+ amount = t.amountEffective - t.amountRaw,
+ amountType = AmountType.Negative,
+ )
+ PurchaseDetails(info = t.info) {
+ onFulfill(t.info.fulfillmentUrl ?: "")
}
DeleteTransactionComposable(onDelete)
- if (devMode == true && t.error != null) {
+ if (devMode && t.error != null) {
ErrorTransactionButton(error = t.error)
}
}
}
+@Composable
+fun PurchaseDetails(
+ info: TransactionInfo,
+ onClick: () -> Unit,
+) {
+ Column(
+ horizontalAlignment = CenterHorizontally,
+ ) {
+ // Summary and fulfillment message
+ val text = if (info.fulfillmentMessage == null) {
+ info.summary
+ } else {
+ "${info.summary}\n\n${info.fulfillmentMessage}"
+ }
+ if (info.fulfillmentUrl != null) {
+ TransactionLinkComposable(
+ label = stringResource(id = R.string.transaction_order),
+ info = text,
+ ) { onClick() }
+ } else {
+ TransactionInfoComposable(
+ label = stringResource(id = R.string.transaction_order),
+ info = text,
+ )
+ }
+ // Order ID
+ Text(
+ stringResource(id = R.string.transaction_order_id, info.orderId),
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+}
+
@Preview
@Composable
-fun TransactionDepositComposablePreview() {
- val t = TransactionDeposit(
+fun TransactionPaymentComposablePreview() {
+ val t = TransactionPayment(
transactionId = "transactionId",
timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60
* 1000),
- extendedStatus = Pending,
- depositGroupId = "fooBar",
+ extendedStatus = ExtendedStatus.Pending,
+ info = TransactionInfo(
+ orderId = "123",
+ merchant = ContractMerchant(name = "Taler"),
+ summary = "Some Product that was bought and can have quite a long
label",
+ fulfillmentMessage = "This is some fulfillment message",
+ fulfillmentUrl = "https://bank.demo.taler.net/",
+ products = listOf(),
+ ),
+ status = PaymentStatus.Paid,
amountRaw = Amount.fromDouble("TESTKUDOS", 42.1337),
amountEffective = Amount.fromDouble("TESTKUDOS", 42.23),
- targetPaytoUri = "https://exchange.example.org/peer/pull/credit",
- error = TalerErrorInfo(code = EXCHANGE_GENERIC_KYC_REQUIRED),
+ error = TalerErrorInfo(code =
TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED),
)
- Surface {
- TransactionDepositComposable(t, true) {}
+ TalerSurface {
+ TransactionPaymentComposable(t = t, devMode = true, onFulfill = {}) {}
}
}
diff --git
a/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt
b/wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt
similarity index 58%
copy from
wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt
copy to
wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt
index 3d59b35..bb077f1 100644
---
a/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt
+++
b/wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt
@@ -1,6 +1,6 @@
/*
* This file is part of GNU Taler
- * (C) 2022 Taler Systems S.A.
+ * (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
@@ -14,7 +14,7 @@
* GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-package net.taler.wallet.deposit
+package net.taler.wallet.refund
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
@@ -22,36 +22,44 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
+import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import net.taler.common.Amount
+import net.taler.common.ContractMerchant
import net.taler.common.Timestamp
import net.taler.common.toAbsoluteTime
import net.taler.wallet.R
-import net.taler.wallet.backend.TalerErrorCode.EXCHANGE_GENERIC_KYC_REQUIRED
+import net.taler.wallet.backend.TalerErrorCode
import net.taler.wallet.backend.TalerErrorInfo
+import net.taler.wallet.compose.TalerSurface
+import net.taler.wallet.payment.PurchaseDetails
import net.taler.wallet.transactions.AmountType
import net.taler.wallet.transactions.DeleteTransactionComposable
import net.taler.wallet.transactions.ErrorTransactionButton
-import net.taler.wallet.transactions.ExtendedStatus.Pending
+import net.taler.wallet.transactions.ExtendedStatus
import net.taler.wallet.transactions.TransactionAmountComposable
-import net.taler.wallet.transactions.TransactionDeposit
+import net.taler.wallet.transactions.TransactionInfo
+import net.taler.wallet.transactions.TransactionRefund
@Composable
-fun TransactionDepositComposable(t: TransactionDeposit, devMode: Boolean?,
onDelete: () -> Unit) {
+fun TransactionRefundComposable(
+ t: TransactionRefund,
+ devMode: Boolean,
+ onFulfill: (url: String) -> Unit,
+ onDelete: () -> Unit,
+) {
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(scrollState),
- horizontalAlignment = Alignment.CenterHorizontally,
+ horizontalAlignment = CenterHorizontally,
) {
val context = LocalContext.current
Text(
@@ -60,25 +68,25 @@ fun TransactionDepositComposable(t: TransactionDeposit,
devMode: Boolean?, onDel
style = MaterialTheme.typography.bodyLarge,
)
TransactionAmountComposable(
- label = stringResource(id = R.string.transaction_paid),
+ label = stringResource(id = R.string.transaction_refund),
amount = t.amountEffective,
- amountType = AmountType.Negative,
+ amountType = AmountType.Positive,
)
TransactionAmountComposable(
label = stringResource(id = R.string.transaction_order_total),
amount = t.amountRaw,
amountType = AmountType.Neutral,
)
- val fee = t.amountEffective - t.amountRaw
- if (!fee.isZero()) {
- TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
- amount = fee,
- amountType = AmountType.Negative,
- )
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.withdraw_fees),
+ amount = t.amountRaw - t.amountEffective,
+ amountType = AmountType.Negative,
+ )
+ PurchaseDetails(info = t.info) {
+ onFulfill(t.info.fulfillmentUrl ?: "")
}
DeleteTransactionComposable(onDelete)
- if (devMode == true && t.error != null) {
+ if (devMode && t.error != null) {
ErrorTransactionButton(error = t.error)
}
}
@@ -86,18 +94,25 @@ fun TransactionDepositComposable(t: TransactionDeposit,
devMode: Boolean?, onDel
@Preview
@Composable
-fun TransactionDepositComposablePreview() {
- val t = TransactionDeposit(
+fun TransactionRefundComposablePreview() {
+ val t = TransactionRefund(
transactionId = "transactionId",
timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60
* 1000),
- extendedStatus = Pending,
- depositGroupId = "fooBar",
- amountRaw = Amount.fromDouble("TESTKUDOS", 42.1337),
- amountEffective = Amount.fromDouble("TESTKUDOS", 42.23),
- targetPaytoUri = "https://exchange.example.org/peer/pull/credit",
- error = TalerErrorInfo(code = EXCHANGE_GENERIC_KYC_REQUIRED),
+ extendedStatus = ExtendedStatus.Pending,
+ info = TransactionInfo(
+ orderId = "123",
+ merchant = ContractMerchant(name = "Taler"),
+ summary = "Some Product that was bought and can have quite a long
label",
+ fulfillmentMessage = "This is some fulfillment message",
+ fulfillmentUrl = "https://bank.demo.taler.net/",
+ products = listOf(),
+ ),
+ refundedTransactionId = "transactionId",
+ amountRaw = Amount.fromDouble("TESTKUDOS", 42.23),
+ amountEffective = Amount.fromDouble("TESTKUDOS", 42.1337),
+ error = TalerErrorInfo(code =
TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED),
)
- Surface {
- TransactionDepositComposable(t, true) {}
+ TalerSurface {
+ TransactionRefundComposable(t = t, devMode = true, onFulfill = {}) {}
}
}
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/ActionButtonComposable.kt
b/wallet/src/main/java/net/taler/wallet/transactions/ActionButtonComposable.kt
new file mode 100644
index 0000000..d4c12aa
--- /dev/null
+++
b/wallet/src/main/java/net/taler/wallet/transactions/ActionButtonComposable.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.transactions
+
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.AccountBalance
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import net.taler.wallet.R
+import net.taler.wallet.backend.TalerErrorCode
+import net.taler.wallet.transactions.WithdrawalDetails.ManualTransfer
+import net.taler.wallet.transactions.WithdrawalDetails.TalerBankIntegrationApi
+
+interface ActionListener {
+ enum class Type {
+ COMPLETE_KYC,
+ CONFIRM_WITH_BANK,
+ CONFIRM_MANUAL
+ }
+
+ fun onActionButtonClicked(tx: Transaction, type: Type)
+}
+
+@Composable
+fun ActionButton(
+ modifier: Modifier = Modifier,
+ tx: TransactionWithdrawal,
+ listener: ActionListener,
+) {
+ if (tx.error != null) {
+ // There is an error!
+ when (tx.error.code) {
+ TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED -> {
+ KycButton(modifier, tx, listener)
+ }
+ else -> {}
+ }
+ } else if (!tx.confirmed) {
+ // There is a transaction!
+ if (tx.withdrawalDetails is TalerBankIntegrationApi &&
+ tx.withdrawalDetails.bankConfirmationUrl != null
+ ) {
+ // The transaction can be completed with a link!
+ ConfirmBankButton(modifier, tx, listener)
+ } else if (tx.withdrawalDetails is ManualTransfer) {
+ // The transaction must be completed manually!
+ ConfirmManualButton(modifier, tx, listener)
+ }
+ }
+}
+
+@Composable
+private fun KycButton(
+ modifier: Modifier = Modifier,
+ tx: TransactionWithdrawal,
+ listener: ActionListener,
+) {
+ Button(
+ onClick = { listener.onActionButtonClicked(tx,
ActionListener.Type.COMPLETE_KYC) },
+ modifier = modifier,
+ ) {
+ Text(stringResource(R.string.transaction_action_kyc))
+ }
+}
+
+@Composable
+private fun ConfirmBankButton(
+ modifier: Modifier = Modifier,
+ tx: TransactionWithdrawal,
+ listener: ActionListener,
+) {
+ Button(
+ onClick = { listener.onActionButtonClicked(tx,
ActionListener.Type.CONFIRM_WITH_BANK) },
+ modifier = modifier,
+ ) {
+ val label = stringResource(R.string.withdraw_button_confirm_bank)
+ Icon(
+ Icons.Default.AccountBalance,
+ label,
+ modifier = Modifier.size(ButtonDefaults.IconSize)
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text(label)
+ }
+}
+
+@Composable
+private fun ConfirmManualButton(
+ modifier: Modifier = Modifier,
+ tx: TransactionWithdrawal,
+ listener: ActionListener,
+) {
+ Button(
+ onClick = { listener.onActionButtonClicked(tx,
ActionListener.Type.CONFIRM_MANUAL) },
+ modifier = modifier,
+ ) {
+ val label =
stringResource(R.string.withdraw_manual_ready_details_intro)
+ Icon(
+ Icons.Default.AccountBalance,
+ label,
+ modifier = Modifier.size(ButtonDefaults.IconSize)
+ )
+ Spacer(Modifier.size(ButtonDefaults.IconSpacing))
+ Text(label)
+ }
+}
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
index d37728f..678bed2 100644
---
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
+++
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -17,25 +17,16 @@
package net.taler.wallet.transactions
import android.os.Bundle
-import android.text.SpannableString
-import android.text.style.UnderlineSpan
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
-import android.widget.TextView
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import kotlinx.serialization.encodeToString
-import kotlinx.serialization.json.Json
-import net.taler.common.Amount
import net.taler.wallet.MainViewModel
import net.taler.wallet.R
-import net.taler.wallet.compose.copyToClipBoard
-import net.taler.wallet.getAttrColor
-import net.taler.wallet.launchInAppBrowser
abstract class TransactionDetailFragment : Fragment() {
@@ -72,34 +63,6 @@ abstract class TransactionDetailFragment : Fragment() {
}
}
- protected fun bindOrderAndFee(
- orderSummaryView: TextView,
- orderAmountView: TextView,
- orderIdView: TextView,
- feeView: TextView,
- info: TransactionInfo,
- raw: Amount,
- fee: Amount,
- ) {
- orderAmountView.text = raw.toString()
- feeView.text = getString(R.string.amount_negative, fee.toString())
- orderSummaryView.text = if (info.fulfillmentMessage == null) {
- info.summary
- } else {
- "${info.summary}\n\n${info.fulfillmentMessage}"
- }
- if (info.fulfillmentUrl?.startsWith("http", ignoreCase = true) ==
true) {
- val content = SpannableString(info.summary)
- content.setSpan(UnderlineSpan(), 0, info.summary.length, 0)
- orderSummaryView.text = content
-
orderSummaryView.setTextColor(requireContext().getAttrColor(android.R.attr.textColorLink))
- orderSummaryView.setOnClickListener {
- launchInAppBrowser(requireContext(), info.fulfillmentUrl)
- }
- }
- orderIdView.text = getString(R.string.transaction_order_id,
info.orderId)
- }
-
@StringRes
protected open val deleteDialogTitle = R.string.transactions_delete
@@ -128,30 +91,4 @@ abstract class TransactionDetailFragment : Fragment() {
findNavController().popBackStack()
}
- protected fun onShowErrorButtonClicked(t: Transaction) {
- val err = t.error
- require(err != null) { "Transaction had no error." }
-
- @Suppress("OPT_IN_USAGE")
- val json = Json {
- prettyPrint = true
- prettyPrintIndent = " "
- }
- val message = json.encodeToString(err)
- MaterialAlertDialogBuilder(requireContext(),
R.style.MaterialAlertDialog_Material3)
- .setTitle(getString(R.string.nav_error))
- .setMessage(message)
- .setNeutralButton(R.string.close) { dialog, _ ->
- dialog.cancel()
- }
- .setPositiveButton(R.string.copy) { _, _ ->
- copyToClipBoard(
- requireContext(),
- getString(R.string.nav_error),
- message,
- )
- }
- .show()
- }
-
}
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionLinkComposable.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionLinkComposable.kt
new file mode 100644
index 0000000..e8fca0f
--- /dev/null
+++
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionLinkComposable.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.transactions
+
+import android.R
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.text.ClickableText
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment.Companion.CenterHorizontally
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import net.taler.wallet.compose.TalerSurface
+import net.taler.wallet.getAttrColor
+
+@Composable
+// FIXME this assumes that it is used in a column and applies its own padding,
not really re-usable
+fun TransactionLinkComposable(label: String, info: String, onClick: () ->
Unit) {
+ Text(
+ modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp),
+ text = label,
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ val context = LocalContext.current
+ val linkColor = Color(context.getAttrColor(R.attr.textColorLink))
+ val annotatedString = buildAnnotatedString {
+ pushStringAnnotation(tag = "url", annotation = info)
+ withStyle(style = SpanStyle(color = linkColor)) {
+ append(info)
+ }
+ pop()
+ }
+ ClickableText(
+ modifier = Modifier.padding(top = 8.dp, start = 16.dp, end = 16.dp,
bottom = 16.dp),
+ text = annotatedString,
+ style = TextStyle(fontSize = 24.sp, textAlign = TextAlign.Center),
+ ) { offset ->
+ annotatedString.getStringAnnotations(
+ tag = "url",
+ start = offset,
+ end = offset,
+ ).firstOrNull()?.let {
+ onClick()
+ }
+ }
+}
+
+@Preview
+@Composable
+fun TransactionLinkComposablePreview() {
+ TalerSurface {
+ Column(
+ horizontalAlignment = CenterHorizontally,
+ ) {
+ TransactionLinkComposable(
+ label = "This is a label",
+ info = "This is some fulfillment message"
+ ) {}
+ }
+ }
+}
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
index 068a41e..e9eb5b8 100644
---
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
+++
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPaymentFragment.kt
@@ -19,50 +19,33 @@ package net.taler.wallet.transactions
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
-import android.view.View.VISIBLE
import android.view.ViewGroup
-import net.taler.common.toAbsoluteTime
-import net.taler.wallet.databinding.FragmentTransactionPaymentBinding
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.platform.ComposeView
+import net.taler.wallet.compose.TalerSurface
+import net.taler.wallet.launchInAppBrowser
+import net.taler.wallet.payment.TransactionPaymentComposable
class TransactionPaymentFragment : TransactionDetailFragment() {
- private lateinit var ui: FragmentTransactionPaymentBinding
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
- ): View {
- ui = FragmentTransactionPaymentBinding.inflate(inflater, container,
false)
- return ui.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- transactionManager.selectedTransaction.observe(viewLifecycleOwner) { t
->
- if (t !is TransactionPayment) return@observe
- ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
-
- ui.amountPaidWithFeesView.text = t.amountEffective.toString()
- val fee = t.amountEffective - t.amountRaw
- bindOrderAndFee(
- ui.orderSummaryView,
- ui.orderAmountView,
- ui.orderIdView,
- ui.feeView,
- t.info,
- t.amountRaw,
- fee
- )
- ui.deleteButton.setOnClickListener {
- onDeleteButtonClicked(t)
- }
- if (devMode.value == true && t.error != null) {
- ui.showErrorButton.visibility = VISIBLE
- ui.showErrorButton.setOnClickListener {
- onShowErrorButtonClicked(t)
- }
+ ): View = ComposeView(requireContext()).apply {
+ setContent {
+ TalerSurface {
+ val t =
transactionManager.selectedTransaction.observeAsState().value
+ val devMode = devMode.observeAsState().value ?: false
+ if (t is TransactionPayment) TransactionPaymentComposable(t,
devMode,
+ onFulfill = { url ->
+ launchInAppBrowser(requireContext(), url)
+ },
+ onDelete = {
+ onDeleteButtonClicked(t)
+ }
+ )
}
}
}
-
}
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
index 36d3bc7..391eefa 100644
---
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
+++
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
@@ -19,50 +19,94 @@ package net.taler.wallet.transactions
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
-import android.view.View.GONE
-import android.view.View.VISIBLE
import android.view.ViewGroup
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment.Companion.CenterHorizontally
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import net.taler.common.Amount
+import net.taler.common.Timestamp
import net.taler.common.toAbsoluteTime
import net.taler.wallet.R
-import net.taler.wallet.cleanExchange
-import net.taler.wallet.databinding.FragmentTransactionWithdrawalBinding
+import net.taler.wallet.backend.TalerErrorCode
+import net.taler.wallet.backend.TalerErrorInfo
+import net.taler.wallet.compose.TalerSurface
class TransactionRefreshFragment : TransactionDetailFragment() {
- private lateinit var ui: FragmentTransactionWithdrawalBinding
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
- ): View {
- ui = FragmentTransactionWithdrawalBinding.inflate(inflater, container,
false)
- return ui.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- transactionManager.selectedTransaction.observe(viewLifecycleOwner) { t
->
- if (t !is TransactionRefresh) return@observe
- ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
-
- ui.effectiveAmountLabel.visibility = GONE
- ui.effectiveAmountView.visibility = GONE
- ui.confirmWithdrawalButton.visibility = GONE
- ui.chosenAmountLabel.visibility = GONE
- ui.chosenAmountView.visibility = GONE
- val fee = t.amountEffective
- ui.feeView.text = getString(R.string.amount_negative,
fee.toString())
- ui.exchangeView.text = cleanExchange(t.exchangeBaseUrl)
- ui.deleteButton.setOnClickListener {
- onDeleteButtonClicked(t)
- }
- if (devMode.value == true && t.error != null) {
- ui.showErrorButton.visibility = VISIBLE
- ui.showErrorButton.setOnClickListener {
- onShowErrorButtonClicked(t)
+ ): View = ComposeView(requireContext()).apply {
+ setContent {
+ TalerSurface {
+ val t =
transactionManager.selectedTransaction.observeAsState().value
+ val devMode = devMode.observeAsState().value ?: false
+ if (t is TransactionRefresh) TransactionRefreshComposable(t,
devMode) {
+ onDeleteButtonClicked(t)
}
}
}
}
+}
+@Composable
+private fun TransactionRefreshComposable(
+ t: TransactionRefresh,
+ devMode: Boolean,
+ onDelete: () -> Unit,
+) {
+ val scrollState = rememberScrollState()
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .verticalScroll(scrollState),
+ horizontalAlignment = CenterHorizontally,
+ ) {
+ val context = LocalContext.current
+ Text(
+ modifier = Modifier.padding(16.dp),
+ text = t.timestamp.ms.toAbsoluteTime(context).toString(),
+ style = MaterialTheme.typography.bodyLarge,
+ )
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.withdraw_fees),
+ amount = t.amountEffective,
+ amountType = AmountType.Negative,
+ )
+ DeleteTransactionComposable(onDelete)
+ if (devMode && t.error != null) {
+ ErrorTransactionButton(error = t.error)
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun TransactionRefreshComposablePreview() {
+ val t = TransactionRefresh(
+ transactionId = "transactionId",
+ timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60
* 1000),
+ extendedStatus = ExtendedStatus.Pending,
+ amountRaw = Amount.fromDouble("TESTKUDOS", 42.23),
+ amountEffective = Amount.fromDouble("TESTKUDOS", 42.1337),
+ error = TalerErrorInfo(code =
TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED),
+ )
+ Surface {
+ TransactionRefreshComposable(t, true) {}
+ }
}
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
index 9c30609..61c0364 100644
---
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
+++
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefundFragment.kt
@@ -19,55 +19,33 @@ package net.taler.wallet.transactions
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
-import android.view.View.VISIBLE
import android.view.ViewGroup
-import androidx.core.content.ContextCompat.getColor
-import net.taler.common.toAbsoluteTime
-import net.taler.wallet.R
-import net.taler.wallet.databinding.FragmentTransactionPaymentBinding
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.platform.ComposeView
+import net.taler.wallet.compose.TalerSurface
+import net.taler.wallet.launchInAppBrowser
+import net.taler.wallet.refund.TransactionRefundComposable
class TransactionRefundFragment : TransactionDetailFragment() {
- private lateinit var ui: FragmentTransactionPaymentBinding
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
- ): View {
- ui = FragmentTransactionPaymentBinding.inflate(inflater, container,
false)
- return ui.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- transactionManager.selectedTransaction.observe(viewLifecycleOwner) { t
->
- if (t !is TransactionRefund) return@observe
- ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
-
- ui.amountPaidWithFeesLabel.text =
getString(R.string.transaction_refund)
- ui.amountPaidWithFeesView.setTextColor(getColor(requireContext(),
R.color.green))
- ui.amountPaidWithFeesView.text =
- getString(R.string.amount_positive,
t.amountEffective.toString())
- val fee = t.amountRaw - t.amountEffective
- bindOrderAndFee(
- ui.orderSummaryView,
- ui.orderAmountView,
- ui.orderIdView,
- ui.feeView,
- t.info,
- t.amountRaw,
- fee
- )
- ui.deleteButton.setOnClickListener {
- onDeleteButtonClicked(t)
- }
- if (devMode.value == true && t.error != null) {
- ui.showErrorButton.visibility = VISIBLE
- ui.showErrorButton.setOnClickListener {
- onShowErrorButtonClicked(t)
- }
+ ): View = ComposeView(requireContext()).apply {
+ setContent {
+ TalerSurface {
+ val t =
transactionManager.selectedTransaction.observeAsState().value
+ val devMode = devMode.observeAsState().value ?: false
+ if (t is TransactionRefund) TransactionRefundComposable(t,
devMode,
+ onFulfill = { url ->
+ launchInAppBrowser(requireContext(), url)
+ },
+ onDelete = {
+ onDeleteButtonClicked(t)
+ }
+ )
}
}
}
-
}
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
index ad70d2f..7a85522 100644
---
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
+++
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt
@@ -19,70 +19,26 @@ package net.taler.wallet.transactions
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
-import android.view.View.GONE
-import android.view.View.VISIBLE
import android.view.ViewGroup
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
-import net.taler.common.toAbsoluteTime
import net.taler.wallet.MainViewModel
import net.taler.wallet.R
-import net.taler.wallet.cleanExchange
-import net.taler.wallet.databinding.FragmentTransactionWithdrawalBinding
-import net.taler.wallet.handleKyc
+import net.taler.wallet.compose.TalerSurface
import net.taler.wallet.launchInAppBrowser
-import net.taler.wallet.transactions.ExtendedStatus.Pending
import net.taler.wallet.transactions.WithdrawalDetails.ManualTransfer
import net.taler.wallet.transactions.WithdrawalDetails.TalerBankIntegrationApi
+import net.taler.wallet.withdraw.TransactionWithdrawalComposable
import net.taler.wallet.withdraw.createManualTransferRequired
-class TransactionWithdrawalFragment : TransactionDetailFragment() {
+class TransactionWithdrawalFragment : TransactionDetailFragment(),
ActionListener {
private val model: MainViewModel by activityViewModels()
private val withdrawManager by lazy { model.withdrawManager }
- private lateinit var ui: FragmentTransactionWithdrawalBinding
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?,
- ): View {
- ui = FragmentTransactionWithdrawalBinding.inflate(inflater, container,
false)
- return ui.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- transactionManager.selectedTransaction.observe(viewLifecycleOwner) { t
->
- if (t !is TransactionWithdrawal) return@observe
- ui.timeView.text = t.timestamp.ms.toAbsoluteTime(requireContext())
-
- ui.effectiveAmountLabel.text = getString(R.string.withdraw_total)
- ui.effectiveAmountView.text = t.amountEffective.toString()
- setupConfirmWithdrawalButton(t)
- setupActionButton(t)
- ui.chosenAmountLabel.text = getString(R.string.amount_chosen)
- ui.chosenAmountView.text =
- getString(R.string.amount_positive, t.amountRaw.toString())
- val fee = t.amountRaw - t.amountEffective
- ui.feeView.text = getString(R.string.amount_negative,
fee.toString())
- ui.exchangeView.text = cleanExchange(t.exchangeBaseUrl)
- if (t.extendedStatus == Pending) {
- ui.deleteButton.setIconResource(R.drawable.ic_cancel)
- ui.deleteButton.setText(R.string.cancel)
- }
- ui.deleteButton.setOnClickListener {
- onDeleteButtonClicked(t)
- }
- if (devMode.value == true && t.error != null) {
- ui.showErrorButton.visibility = VISIBLE
- ui.showErrorButton.setOnClickListener {
- onShowErrorButtonClicked(t)
- }
- }
- }
- }
-
- private val isPending get() =
transactionManager.selectedTransaction.value?.extendedStatus == Pending
+ private val isPending get() =
transactionManager.selectedTransaction.value?.extendedStatus ==
ExtendedStatus.Pending
override val deleteDialogTitle: Int
get() = if (isPending) R.string.cancel else super.deleteDialogTitle
@@ -92,42 +48,56 @@ class TransactionWithdrawalFragment :
TransactionDetailFragment() {
override val deleteDialogButton: Int
get() = if (isPending) R.string.ok else super.deleteDialogButton
- private fun setupConfirmWithdrawalButton(t: TransactionWithdrawal) {
- if (t.extendedStatus == Pending && !t.confirmed) {
- if (t.withdrawalDetails is TalerBankIntegrationApi &&
- t.withdrawalDetails.bankConfirmationUrl != null
- ) {
- ui.confirmWithdrawalButton.setOnClickListener {
- launchInAppBrowser(requireContext(),
t.withdrawalDetails.bankConfirmationUrl)
- }
- } else if (t.withdrawalDetails is ManualTransfer) {
-
ui.confirmWithdrawalButton.setText(R.string.withdraw_manual_ready_details_intro)
- ui.confirmWithdrawalButton.setOnClickListener {
- val status = createManualTransferRequired(
- amount = t.amountRaw,
- exchangeBaseUrl = t.exchangeBaseUrl,
- // TODO what if there's more than one or no URI?
- uriStr = t.withdrawalDetails.exchangePaytoUris[0],
- transactionId = t.transactionId,
- )
- withdrawManager.viewManualWithdrawal(status)
- findNavController().navigate(
-
R.id.action_nav_transactions_detail_withdrawal_to_nav_exchange_manual_withdrawal_success
- )
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?,
+ ): View = ComposeView(requireContext()).apply {
+ setContent {
+ TalerSurface {
+ val t =
transactionManager.selectedTransaction.observeAsState().value
+ val devMode = devMode.observeAsState().value ?: false
+ if (t is TransactionWithdrawal)
TransactionWithdrawalComposable(
+ t = t,
+ devMode = devMode,
+ actionListener = this@TransactionWithdrawalFragment,
+ ) {
+ onDeleteButtonClicked(t)
}
- } else ui.confirmWithdrawalButton.visibility = GONE
- } else ui.confirmWithdrawalButton.visibility = GONE
+ }
+ }
}
- private fun setupActionButton(t: TransactionWithdrawal) {
- ui.actionButton.visibility = t.handleKyc({ GONE }) { error ->
- ui.actionButton.setText(R.string.transaction_action_kyc)
- error.getStringExtra("kycUrl")?.let { kycUrl ->
- ui.actionButton.setOnClickListener {
+ override fun onActionButtonClicked(tx: Transaction, type:
ActionListener.Type) {
+ when (type) {
+ ActionListener.Type.COMPLETE_KYC -> {
+ tx.error?.getStringExtra("kycUrl")?.let { kycUrl ->
launchInAppBrowser(requireContext(), kycUrl)
}
}
- VISIBLE
+ ActionListener.Type.CONFIRM_WITH_BANK -> {
+ if (tx !is TransactionWithdrawal) return
+ if (tx.withdrawalDetails !is TalerBankIntegrationApi) return
+ tx.withdrawalDetails.bankConfirmationUrl?.let { url ->
+ launchInAppBrowser(requireContext(), url)
+ }
+ }
+ ActionListener.Type.CONFIRM_MANUAL -> {
+ if (tx !is TransactionWithdrawal) return
+ if (tx.withdrawalDetails !is ManualTransfer) return
+ // TODO what if there's more than one or no URI?
+ if (tx.withdrawalDetails.exchangePaytoUris.isEmpty()) return
+ val status = createManualTransferRequired(
+ amount = tx.amountRaw,
+ exchangeBaseUrl = tx.exchangeBaseUrl,
+ uriStr = tx.withdrawalDetails.exchangePaytoUris[0],
+ transactionId = tx.transactionId,
+ )
+ withdrawManager.viewManualWithdrawal(status)
+ findNavController().navigate(
+
R.id.action_nav_transactions_detail_withdrawal_to_nav_exchange_manual_withdrawal_success,
+ )
+ }
}
}
}
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 68d0bc4..a306685 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -264,7 +264,6 @@ class TransactionRefresh(
override val transactionId: String,
override val timestamp: Timestamp,
override val extendedStatus: ExtendedStatus,
- val exchangeBaseUrl: String,
override val error: TalerErrorInfo? = null,
override val amountRaw: Amount,
override val amountEffective: Amount,
diff --git
a/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt
b/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt
new file mode 100644
index 0000000..f1a22d3
--- /dev/null
+++
b/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.withdraw
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+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
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Alignment.Companion.CenterVertically
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import net.taler.common.Amount
+import net.taler.common.Timestamp
+import net.taler.common.toAbsoluteTime
+import net.taler.wallet.R
+import net.taler.wallet.backend.TalerErrorCode
+import net.taler.wallet.backend.TalerErrorInfo
+import net.taler.wallet.cleanExchange
+import net.taler.wallet.transactions.ActionButton
+import net.taler.wallet.transactions.ActionListener
+import net.taler.wallet.transactions.AmountType
+import net.taler.wallet.transactions.DeleteTransactionComposable
+import net.taler.wallet.transactions.ErrorTransactionButton
+import net.taler.wallet.transactions.ExtendedStatus
+import net.taler.wallet.transactions.Transaction
+import net.taler.wallet.transactions.TransactionAmountComposable
+import net.taler.wallet.transactions.TransactionInfoComposable
+import net.taler.wallet.transactions.TransactionWithdrawal
+import net.taler.wallet.transactions.WithdrawalDetails.ManualTransfer
+
+@Composable
+fun TransactionWithdrawalComposable(
+ t: TransactionWithdrawal,
+ devMode: Boolean,
+ actionListener: ActionListener,
+ onDelete: () -> Unit,
+) {
+ val scrollState = rememberScrollState()
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .verticalScroll(scrollState),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ val context = LocalContext.current
+ Text(
+ modifier = Modifier.padding(16.dp),
+ text = t.timestamp.ms.toAbsoluteTime(context).toString(),
+ style = MaterialTheme.typography.bodyLarge,
+ )
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.withdraw_total),
+ amount = t.amountEffective,
+ amountType = AmountType.Positive,
+ )
+ ActionButton(tx = t, listener = actionListener)
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.amount_chosen),
+ amount = t.amountRaw,
+ amountType = AmountType.Neutral,
+ )
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.withdraw_fees),
+ amount = t.amountRaw - t.amountEffective,
+ amountType = AmountType.Negative,
+ )
+ TransactionInfoComposable(
+ label = stringResource(id = R.string.withdraw_exchange),
+ info = cleanExchange(t.exchangeBaseUrl),
+ )
+ if (t.extendedStatus == ExtendedStatus.Pending) {
+ Button(
+ modifier = Modifier.padding(16.dp),
+ colors = ButtonDefaults.buttonColors(containerColor =
MaterialTheme.colorScheme.error),
+ onClick = onDelete,
+ ) {
+ Row(verticalAlignment = CenterVertically) {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_cancel),
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onError,
+ )
+ Text(
+ modifier = Modifier.padding(start = 8.dp),
+ text = stringResource(R.string.cancel),
+ color = MaterialTheme.colorScheme.onError,
+ )
+ }
+ }
+ } else {
+ DeleteTransactionComposable(onDelete)
+ }
+ if (devMode && t.error != null) {
+ ErrorTransactionButton(error = t.error)
+ }
+ }
+}
+
+@Preview
+@Composable
+fun TransactionWithdrawalComposablePreview() {
+ val t = TransactionWithdrawal(
+ transactionId = "transactionId",
+ timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60
* 1000),
+ extendedStatus = ExtendedStatus.Pending,
+ exchangeBaseUrl = "https://exchange.demo.taler.net/",
+ withdrawalDetails = ManualTransfer(exchangePaytoUris = emptyList()),
+ amountRaw = Amount.fromDouble("TESTKUDOS", 42.23),
+ amountEffective = Amount.fromDouble("TESTKUDOS", 42.1337),
+ error = TalerErrorInfo(code =
TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED),
+ )
+ val listener = object : ActionListener {
+ override fun onActionButtonClicked(tx: Transaction, type:
ActionListener.Type) {
+ }
+ }
+ Surface {
+ TransactionWithdrawalComposable(t, true, listener) {}
+ }
+}
diff --git a/wallet/src/main/res/layout/fragment_transaction_payment.xml
b/wallet/src/main/res/layout/fragment_transaction_payment.xml
deleted file mode 100644
index 5b674bd..0000000
--- a/wallet/src/main/res/layout/fragment_transaction_payment.xml
+++ /dev/null
@@ -1,149 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ This file is part of GNU Taler
- ~ (C) 2020 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/>
- -->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fillViewport="true"
- tools:context=".transactions.TransactionDetailFragment">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/timeView"
- style="@style/TransactionLabel.Time"
- app:layout_constraintBottom_toTopOf="@+id/amountPaidWithFeesLabel"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="23 March 2020 23:42pm" />
-
- <TextView
- android:id="@+id/amountPaidWithFeesLabel"
- style="@style/TransactionLabel"
- android:text="@string/transaction_paid"
- app:layout_constraintBottom_toTopOf="@+id/amountPaidWithFeesView"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/timeView" />
-
- <TextView
- android:id="@+id/amountPaidWithFeesView"
- style="@style/TransactionContent"
- android:textColor="?colorError"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/amountPaidWithFeesLabel"
- tools:text="-23.42 TESTKUDOS" />
-
- <TextView
- android:id="@+id/orderAmountLabel"
- style="@style/TransactionLabel"
- android:text="@string/transaction_order_total"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/amountPaidWithFeesView"
/>
-
- <TextView
- android:id="@+id/orderAmountView"
- style="@style/TransactionContent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/orderAmountLabel"
- tools:text="23 TESTKUDOS" />
-
- <TextView
- android:id="@+id/feeLabel"
- style="@style/TransactionLabel"
- android:text="@string/withdraw_fees"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/orderAmountView" />
-
- <TextView
- android:id="@+id/feeView"
- style="@style/TransactionContent"
- android:textColor="?colorError"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/feeLabel"
- tools:text="-0.42 TESTKUDOS" />
-
- <TextView
- android:id="@+id/orderSummaryLabel"
- style="@style/TransactionLabel"
- android:text="@string/transaction_order"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/feeView" />
-
- <TextView
- android:id="@+id/orderSummaryView"
- style="@style/TransactionContent"
- android:textColor="?android:textColorPrimary"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/orderSummaryLabel"
- tools:text="Some Product that was bought and can have quite a long
label" />
-
- <TextView
- android:id="@+id/orderIdView"
- style="@style/TransactionLabel"
- android:layout_marginBottom="16dp"
- android:text="@string/transaction_order_id"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/orderSummaryView" />
-
- <com.google.android.material.button.MaterialButton
- android:id="@+id/deleteButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginVertical="10dp"
- android:text="@string/transactions_delete"
- android:textColor="?colorOnError"
- app:backgroundTint="?colorError"
- app:icon="@drawable/ic_delete"
- app:iconTint="?colorOnError"
- app:layout_constraintBottom_toTopOf="@id/showErrorButton"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/orderIdView" />
-
- <com.google.android.material.button.MaterialButton
- android:id="@+id/showErrorButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginVertical="10dp"
- android:visibility="gone"
- android:text="@string/nav_error"
- app:backgroundTint="?colorError"
- app:icon="@drawable/ic_error"
- android:textColor="?colorOnError"
- app:iconTint="?colorOnError"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/deleteButton"
- tools:visibility="visible" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
-</ScrollView>
diff --git a/wallet/src/main/res/layout/fragment_transaction_withdrawal.xml
b/wallet/src/main/res/layout/fragment_transaction_withdrawal.xml
deleted file mode 100644
index 87530a4..0000000
--- a/wallet/src/main/res/layout/fragment_transaction_withdrawal.xml
+++ /dev/null
@@ -1,176 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ This file is part of GNU Taler
- ~ (C) 2020 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/>
- -->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fillViewport="true"
- tools:context=".transactions.TransactionDetailFragment">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/timeView"
- style="@style/TransactionLabel.Time"
- app:layout_constraintBottom_toTopOf="@+id/effectiveAmountLabel"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="23 March 2020 23:42pm" />
-
- <TextView
- android:id="@+id/effectiveAmountLabel"
- style="@style/TransactionLabel"
- app:layout_constraintBottom_toTopOf="@+id/effectiveAmountView"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/timeView"
- tools:text="@string/withdraw_total" />
-
- <TextView
- android:id="@+id/effectiveAmountView"
- style="@style/TransactionContent"
- android:textColor="@color/green"
- app:layout_constraintBottom_toTopOf="@+id/confirmWithdrawalButton"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/effectiveAmountLabel"
- tools:text="23.42 TESTKUDOS" />
-
- <com.google.android.material.button.MaterialButton
- android:id="@+id/confirmWithdrawalButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:icon="@drawable/ic_account_balance"
- android:text="@string/withdraw_button_confirm_bank"
- android:textColor="?colorOnPrimary"
- app:iconTint="?colorOnPrimary"
- app:drawableTint="?attr/colorOnPrimarySurface"
- app:layout_constraintBottom_toTopOf="@+id/actionButton"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/effectiveAmountView"
- tools:ignore="RtlHardcoded" />
-
- <Button
- android:id="@+id/actionButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginVertical="10dp"
- android:textColor="?colorOnTertiary"
- android:backgroundTint="?colorTertiary"
- android:visibility="gone"
- app:layout_constraintBottom_toTopOf="@id/chosenAmountLabel"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/confirmWithdrawalButton"
- tools:text="@string/transaction_action_kyc"
- tools:visibility="visible" />
-
- <TextView
- android:id="@+id/chosenAmountLabel"
- style="@style/TransactionLabel"
- app:layout_constraintBottom_toTopOf="@+id/chosenAmountView"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/actionButton"
- tools:text="@string/amount_chosen" />
-
- <TextView
- android:id="@+id/chosenAmountView"
- style="@style/TransactionContent"
- app:layout_constraintBottom_toTopOf="@+id/feeLabel"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/chosenAmountLabel"
- tools:text="24 TESTKUDOS" />
-
- <TextView
- android:id="@+id/feeLabel"
- style="@style/TransactionLabel"
- android:text="@string/withdraw_fees"
- app:layout_constraintBottom_toTopOf="@+id/feeView"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/chosenAmountView" />
-
- <TextView
- android:id="@+id/feeView"
- style="@style/TransactionContent"
- android:textColor="?colorError"
- app:layout_constraintBottom_toTopOf="@+id/exchangeLabel"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/feeLabel"
- tools:text="-0.38 TESTKUDOS" />
-
- <TextView
- android:id="@+id/exchangeLabel"
- style="@style/TransactionLabel"
- android:text="@string/withdraw_exchange"
- app:layout_constraintBottom_toTopOf="@+id/exchangeView"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/feeView" />
-
- <TextView
- android:id="@+id/exchangeView"
- style="@style/TransactionContent"
- app:layout_constraintBottom_toTopOf="@+id/deleteButton"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/exchangeLabel"
- tools:text="exchange.demo.taler.net" />
-
- <com.google.android.material.button.MaterialButton
- android:id="@+id/deleteButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginVertical="10dp"
- android:text="@string/transactions_delete"
- app:backgroundTint="?colorError"
- app:icon="@drawable/ic_delete"
- android:textColor="?colorOnError"
- app:iconTint="?colorOnError"
- app:layout_constraintBottom_toTopOf="@id/showErrorButton"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/exchangeView" />
-
- <com.google.android.material.button.MaterialButton
- android:id="@+id/showErrorButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginVertical="10dp"
- android:visibility="gone"
- android:text="@string/nav_error"
- app:backgroundTint="?colorError"
- app:icon="@drawable/ic_error"
- android:textColor="?colorOnError"
- app:iconTint="?colorOnError"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/deleteButton"
- tools:visibility="visible" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
-</ScrollView>
diff --git a/wallet/src/main/res/navigation/nav_graph.xml
b/wallet/src/main/res/navigation/nav_graph.xml
index 6508539..966afac 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -227,8 +227,7 @@
<fragment
android:id="@+id/nav_transactions_detail_withdrawal"
android:name="net.taler.wallet.transactions.TransactionWithdrawalFragment"
- android:label="@string/transactions_detail_title"
- tools:layout="@layout/fragment_transaction_withdrawal">
+ android:label="@string/transactions_detail_title">
<action
android:id="@+id/action_nav_transactions_detail_withdrawal_to_nav_exchange_manual_withdrawal_success"
app:destination="@id/nav_exchange_manual_withdrawal_success" />
@@ -237,38 +236,32 @@
<fragment
android:id="@+id/nav_transactions_detail_payment"
android:name="net.taler.wallet.transactions.TransactionPaymentFragment"
- android:label="@string/transactions_detail_title"
- tools:layout="@layout/fragment_transaction_payment" />
+ android:label="@string/transactions_detail_title" />
<fragment
android:id="@+id/nav_transactions_detail_refund"
android:name="net.taler.wallet.transactions.TransactionRefundFragment"
- android:label="@string/transactions_detail_title"
- tools:layout="@layout/fragment_transaction_payment" />
+ android:label="@string/transactions_detail_title" />
<fragment
android:id="@+id/nav_transactions_detail_refresh"
android:name="net.taler.wallet.transactions.TransactionRefreshFragment"
- android:label="@string/transactions_detail_title"
- tools:layout="@layout/fragment_transaction_withdrawal" />
+ android:label="@string/transactions_detail_title" />
<fragment
android:id="@+id/nav_transactions_detail_deposit"
android:name="net.taler.wallet.transactions.TransactionDepositFragment"
- android:label="@string/transactions_detail_title"
- tools:layout="@layout/fragment_transaction_withdrawal" />
+ android:label="@string/transactions_detail_title" />
<fragment
android:id="@+id/nav_transactions_detail_tip"
android:name="net.taler.wallet.transactions.TransactionTipFragment"
- android:label="@string/transactions_detail_title"
- tools:layout="@layout/fragment_transaction_withdrawal" />
+ android:label="@string/transactions_detail_title" />
<fragment
android:id="@+id/nav_transactions_detail_peer"
android:name="net.taler.wallet.transactions.TransactionPeerFragment"
- android:label="@string/transactions_detail_title"
- tools:layout="@layout/fragment_transaction_payment" />
+ android:label="@string/transactions_detail_title" />
<fragment
android:id="@+id/alreadyAccepted"
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-android] branch master updated (7cd48e3 -> 656ab6b),
gnunet <=
- [taler-taler-android] 01/05: [wallet] Migrated withdrawal and refresh detail to Compose, gnunet, 2023/04/13
- [taler-taler-android] 05/05: [wallet] Clean up compose migration of payment and refund transactions, gnunet, 2023/04/13
- [taler-taler-android] 03/05: [wallet] Remove exchangeBaseUrl from Refresh transactions, gnunet, 2023/04/13
- [taler-taler-android] 04/05: [wallet] Clean up compose migration of withdrawal and refresh transactions, gnunet, 2023/04/13
- [taler-taler-android] 02/05: [wallet] Migrated payment and refund detail to Compose, gnunet, 2023/04/13