summaryrefslogtreecommitdiff
path: root/wallet/src/main/java/net/taler/wallet/transactions
diff options
context:
space:
mode:
authorTorsten Grote <t@grobox.de>2020-05-12 15:26:44 -0300
committerTorsten Grote <t@grobox.de>2020-05-15 14:26:41 -0300
commite74f39ee86f32b4e0324405af1f0c7be061fb372 (patch)
tree484a9e2f6ad3d8d6c9662ff5f41c6f254d218b30 /wallet/src/main/java/net/taler/wallet/transactions
parent4a6630d1d147ae35358272dc5222964831c234ab (diff)
downloadtaler-android-e74f39ee86f32b4e0324405af1f0c7be061fb372.tar.gz
taler-android-e74f39ee86f32b4e0324405af1f0c7be061fb372.tar.bz2
taler-android-e74f39ee86f32b4e0324405af1f0c7be061fb372.zip
[wallet] separate history and transactions UI
The history with its JSON payload is only shown in dev mode while the transactions are prepared to move to the new API.
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/transactions')
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/JsonDialogFragment.kt57
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/ReserveTransaction.kt59
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/Transaction.kt497
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt38
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt17
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt72
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt16
7 files changed, 74 insertions, 682 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/JsonDialogFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/JsonDialogFragment.kt
deleted file mode 100644
index 2337059..0000000
--- a/wallet/src/main/java/net/taler/wallet/transactions/JsonDialogFragment.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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/>
- */
-
-package net.taler.wallet.transactions
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.view.ViewGroup.LayoutParams.MATCH_PARENT
-import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
-import androidx.fragment.app.DialogFragment
-import kotlinx.android.synthetic.main.fragment_json.*
-import net.taler.wallet.R
-
-class JsonDialogFragment : DialogFragment() {
-
- companion object {
- fun new(json: String): JsonDialogFragment {
- return JsonDialogFragment().apply {
- arguments = Bundle().apply { putString("json", json) }
- }
- }
- }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- return inflater.inflate(R.layout.fragment_json, container, false)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- val json = requireArguments().getString("json")
- jsonView.text = json
- }
-
- override fun onStart() {
- super.onStart()
- dialog?.window?.setLayout(MATCH_PARENT, WRAP_CONTENT)
- }
-
-}
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/ReserveTransaction.kt b/wallet/src/main/java/net/taler/wallet/transactions/ReserveTransaction.kt
deleted file mode 100644
index e497e9a..0000000
--- a/wallet/src/main/java/net/taler/wallet/transactions/ReserveTransaction.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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/>
- */
-
-package net.taler.wallet.transactions
-
-import com.fasterxml.jackson.annotation.JsonProperty
-import com.fasterxml.jackson.annotation.JsonSubTypes
-import com.fasterxml.jackson.annotation.JsonTypeInfo
-import com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY
-import com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME
-import com.fasterxml.jackson.annotation.JsonTypeName
-import net.taler.common.Timestamp
-
-
-@JsonTypeInfo(
- use = NAME,
- include = PROPERTY,
- property = "type"
-)
-@JsonSubTypes(
- JsonSubTypes.Type(value = ReserveDepositTransaction::class, name = "DEPOSIT")
-)
-abstract class ReserveTransaction
-
-
-@JsonTypeName("DEPOSIT")
-class ReserveDepositTransaction(
- /**
- * Amount withdrawn.
- */
- val amount: String,
- /**
- * Sender account payto://-URL
- */
- @JsonProperty("sender_account_url")
- val senderAccountUrl: String,
- /**
- * Transfer details uniquely identifying the transfer.
- */
- @JsonProperty("wire_reference")
- val wireReference: String,
- /**
- * Timestamp of the incoming wire transfer.
- */
- val timestamp: Timestamp
-) : ReserveTransaction()
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transaction.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transaction.kt
deleted file mode 100644
index 34942d0..0000000
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transaction.kt
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * 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/>
- */
-
-package net.taler.wallet.transactions
-
-import androidx.annotation.DrawableRes
-import androidx.annotation.LayoutRes
-import com.fasterxml.jackson.annotation.JsonInclude
-import com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY
-import com.fasterxml.jackson.annotation.JsonProperty
-import com.fasterxml.jackson.annotation.JsonSubTypes
-import com.fasterxml.jackson.annotation.JsonSubTypes.Type
-import com.fasterxml.jackson.annotation.JsonTypeInfo
-import com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY
-import com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME
-import com.fasterxml.jackson.annotation.JsonTypeName
-import net.taler.common.Amount
-import net.taler.common.Timestamp
-import net.taler.wallet.R
-import net.taler.wallet.cleanExchange
-import org.json.JSONObject
-
-enum class ReserveType {
- /**
- * Manually created.
- */
- @JsonProperty("manual")
- MANUAL,
-
- /**
- * Withdrawn from a bank that has "tight" Taler integration
- */
- @JsonProperty("taler-bank-withdraw")
- @Suppress("unused")
- TALER_BANK_WITHDRAW,
-}
-
-@JsonInclude(NON_EMPTY)
-class ReserveCreationDetail(val type: ReserveType, val bankUrl: String?)
-
-enum class RefreshReason {
- @JsonProperty("manual")
- @Suppress("unused")
- MANUAL,
-
- @JsonProperty("pay")
- PAY,
-
- @JsonProperty("refund")
- @Suppress("unused")
- REFUND,
-
- @JsonProperty("abort-pay")
- @Suppress("unused")
- ABORT_PAY,
-
- @JsonProperty("recoup")
- @Suppress("unused")
- RECOUP,
-
- @JsonProperty("backup-restored")
- @Suppress("unused")
- BACKUP_RESTORED
-}
-
-@JsonInclude(NON_EMPTY)
-class ReserveShortInfo(
- /**
- * The exchange that the reserve will be at.
- */
- val exchangeBaseUrl: String,
- /**
- * Key to query more details
- */
- val reservePub: String,
- /**
- * Detail about how the reserve has been created.
- */
- val reserveCreationDetail: ReserveCreationDetail
-)
-
-sealed class AmountType {
- object Positive : AmountType()
- object Negative : AmountType()
- object Neutral : AmountType()
-}
-
-class DisplayAmount(
- val amount: Amount,
- val type: AmountType
-)
-
-typealias Transactions = ArrayList<Transaction>
-
-@JsonTypeInfo(
- use = NAME,
- include = PROPERTY,
- property = "type",
- defaultImpl = UnknownTransaction::class
-)
-/** missing:
-AuditorComplaintSent = "auditor-complained-sent",
-AuditorComplaintProcessed = "auditor-complaint-processed",
-AuditorTrustAdded = "auditor-trust-added",
-AuditorTrustRemoved = "auditor-trust-removed",
-ExchangeTermsAccepted = "exchange-terms-accepted",
-ExchangePolicyChanged = "exchange-policy-changed",
-ExchangeTrustAdded = "exchange-trust-added",
-ExchangeTrustRemoved = "exchange-trust-removed",
-FundsDepositedToSelf = "funds-deposited-to-self",
-FundsRecouped = "funds-recouped",
-ReserveCreated = "reserve-created",
- */
-@JsonSubTypes(
- Type(value = ExchangeAddedEvent::class, name = "exchange-added"),
- Type(value = ExchangeUpdatedEvent::class, name = "exchange-updated"),
- Type(value = ReserveBalanceUpdatedTransaction::class, name = "reserve-balance-updated"),
- Type(value = WithdrawTransaction::class, name = "withdrawn"),
- Type(value = OrderAcceptedTransaction::class, name = "order-accepted"),
- Type(value = OrderRefusedTransaction::class, name = "order-refused"),
- Type(value = OrderRedirectedTransaction::class, name = "order-redirected"),
- Type(value = PaymentTransaction::class, name = "payment-sent"),
- Type(value = PaymentAbortedTransaction::class, name = "payment-aborted"),
- Type(value = TipAcceptedTransaction::class, name = "tip-accepted"),
- Type(value = TipDeclinedTransaction::class, name = "tip-declined"),
- Type(value = RefundTransaction::class, name = "refund"),
- Type(value = RefreshTransaction::class, name = "refreshed")
-)
-abstract class Transaction(
- val timestamp: Timestamp,
- val eventId: String,
- @get:LayoutRes
- open val detailPageLayout: Int = 0,
- @get:DrawableRes
- open val icon: Int = R.drawable.ic_account_balance,
- open val showToUser: Boolean = false
-) {
- abstract val title: String?
- open lateinit var json: JSONObject
- open val displayAmount: DisplayAmount? = null
- open fun isCurrency(currency: String): Boolean = true
-}
-
-
-class UnknownTransaction(timestamp: Timestamp, eventId: String) : Transaction(timestamp, eventId) {
- override val title: String? = null
-}
-
-@JsonTypeName("exchange-added")
-class ExchangeAddedEvent(
- timestamp: Timestamp,
- eventId: String,
- val exchangeBaseUrl: String,
- val builtIn: Boolean
-) : Transaction(timestamp, eventId) {
- override val title = cleanExchange(exchangeBaseUrl)
-}
-
-@JsonTypeName("exchange-updated")
-class ExchangeUpdatedEvent(
- timestamp: Timestamp,
- eventId: String,
- val exchangeBaseUrl: String
-) : Transaction(timestamp, eventId) {
- override val title = cleanExchange(exchangeBaseUrl)
-}
-
-
-@JsonTypeName("reserve-balance-updated")
-class ReserveBalanceUpdatedTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Condensed information about the reserve.
- */
- val reserveShortInfo: ReserveShortInfo,
- /**
- * Amount currently left in the reserve.
- */
- val reserveBalance: Amount,
- /**
- * Amount we expected to be in the reserve at that time,
- * considering ongoing withdrawals from that reserve.
- */
- val reserveAwaitedAmount: Amount,
- /**
- * Amount that hasn't been withdrawn yet.
- */
- val reserveUnclaimedAmount: Amount
-) : Transaction(timestamp, eventId) {
- override val title: String? = null
- override val displayAmount = DisplayAmount(reserveBalance, AmountType.Neutral)
- override fun isCurrency(currency: String) = reserveBalance.currency == currency
-}
-
-@JsonTypeName("withdrawn")
-class WithdrawTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Exchange that was withdrawn from.
- */
- val exchangeBaseUrl: String,
- /**
- * Unique identifier for the withdrawal session, can be used to
- * query more detailed information from the wallet.
- */
- val withdrawalGroupId: String,
- val withdrawalSource: WithdrawalSource,
- /**
- * Amount that has been subtracted from the reserve's balance
- * for this withdrawal.
- */
- val amountWithdrawnRaw: Amount,
- /**
- * Amount that actually was added to the wallet's balance.
- */
- val amountWithdrawnEffective: Amount
-) : Transaction(timestamp, eventId) {
- override val detailPageLayout = R.layout.fragment_event_withdraw
- override val title = cleanExchange(exchangeBaseUrl)
- override val icon = R.drawable.transaction_withdrawal
- override val showToUser = true
- override val displayAmount = DisplayAmount(amountWithdrawnEffective, AmountType.Positive)
- override fun isCurrency(currency: String) = amountWithdrawnRaw.currency == currency
-}
-
-@JsonTypeName("order-accepted")
-class OrderAcceptedTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Condensed info about the order.
- */
- val orderShortInfo: OrderShortInfo
-) : Transaction(timestamp, eventId) {
- override val icon = R.drawable.ic_add_circle
- override val title: String? = null
- override fun isCurrency(currency: String) = orderShortInfo.amount.currency == currency
-}
-
-@JsonTypeName("order-refused")
-class OrderRefusedTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Condensed info about the order.
- */
- val orderShortInfo: OrderShortInfo
-) : Transaction(timestamp, eventId) {
- override val icon = R.drawable.ic_cancel
- override val title: String? = null
- override fun isCurrency(currency: String) = orderShortInfo.amount.currency == currency
-}
-
-@JsonTypeName("payment-sent")
-class PaymentTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Condensed info about the order that we already paid for.
- */
- val orderShortInfo: OrderShortInfo,
- /**
- * Set to true if the payment has been previously sent
- * to the merchant successfully, possibly with a different session ID.
- */
- val replay: Boolean,
- /**
- * Number of coins that were involved in the payment.
- */
- val numCoins: Int,
- /**
- * Amount that was paid, including deposit and wire fees.
- */
- val amountPaidWithFees: Amount,
- /**
- * Session ID that the payment was (re-)submitted under.
- */
- val sessionId: String?
-) : Transaction(timestamp, eventId) {
- override val detailPageLayout = R.layout.fragment_event_paid
- override val title = orderShortInfo.summary
- override val icon = R.drawable.ic_cash_usd_outline
- override val showToUser = true
- override val displayAmount = DisplayAmount(amountPaidWithFees, AmountType.Negative)
- override fun isCurrency(currency: String) = orderShortInfo.amount.currency == currency
-}
-
-@JsonTypeName("payment-aborted")
-class PaymentAbortedTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Condensed info about the order that we already paid for.
- */
- val orderShortInfo: OrderShortInfo,
- /**
- * Amount that was lost due to refund and refreshing fees.
- */
- val amountLost: Amount
-) : Transaction(timestamp, eventId) {
- override val title = orderShortInfo.summary
- override val icon = R.drawable.transaction_payment_aborted
- override val showToUser = true
- override val displayAmount = DisplayAmount(amountLost, AmountType.Negative)
- override fun isCurrency(currency: String) = orderShortInfo.amount.currency == currency
-}
-
-@JsonTypeName("refreshed")
-class RefreshTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Amount that is now available again because it has
- * been refreshed.
- */
- val amountRefreshedEffective: Amount,
- /**
- * Amount that we spent for refreshing.
- */
- val amountRefreshedRaw: Amount,
- /**
- * Why was the refreshing done?
- */
- val refreshReason: RefreshReason,
- val numInputCoins: Int,
- val numRefreshedInputCoins: Int,
- val numOutputCoins: Int,
- /**
- * Identifier for a refresh group, contains one or
- * more refresh session IDs.
- */
- val refreshGroupId: String
-) : Transaction(timestamp, eventId) {
- override val icon = R.drawable.transaction_refresh
- override val title: String? = null
- override val showToUser = !(amountRefreshedRaw - amountRefreshedEffective).isZero()
- override val displayAmount: DisplayAmount?
- get() {
- return if (showToUser) DisplayAmount(
- amountRefreshedRaw - amountRefreshedEffective,
- AmountType.Negative
- )
- else null
- }
-
- override fun isCurrency(currency: String) = amountRefreshedRaw.currency == currency
-}
-
-@JsonTypeName("order-redirected")
-class OrderRedirectedTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Condensed info about the new order that contains a
- * product (identified by the fulfillment URL) that we've already paid for.
- */
- val newOrderShortInfo: OrderShortInfo,
- /**
- * Condensed info about the order that we already paid for.
- */
- val alreadyPaidOrderShortInfo: OrderShortInfo
-) : Transaction(timestamp, eventId) {
- override val icon = R.drawable.ic_directions
- override val title = newOrderShortInfo.summary
- override fun isCurrency(currency: String) = newOrderShortInfo.amount.currency == currency
-}
-
-@JsonTypeName("tip-accepted")
-class TipAcceptedTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Unique identifier for the tip to query more information.
- */
- val tipId: String,
- /**
- * Raw amount of the tip, without extra fees that apply.
- */
- val tipRaw: Amount
-) : Transaction(timestamp, eventId) {
- override val icon = R.drawable.transaction_tip_accepted
- override val title: String? = null
- override val showToUser = true
- override val displayAmount = DisplayAmount(tipRaw, AmountType.Positive)
- override fun isCurrency(currency: String) = tipRaw.currency == currency
-}
-
-@JsonTypeName("tip-declined")
-class TipDeclinedTransaction(
- timestamp: Timestamp,
- eventId: String,
- /**
- * Unique identifier for the tip to query more information.
- */
- val tipId: String,
- /**
- * Raw amount of the tip, without extra fees that apply.
- */
- val tipAmount: Amount
-) : Transaction(timestamp, eventId) {
- override val icon = R.drawable.transaction_tip_declined
- override val title: String? = null
- override val showToUser = true
- override val displayAmount = DisplayAmount(tipAmount, AmountType.Neutral)
- override fun isCurrency(currency: String) = tipAmount.currency == currency
-}
-
-@JsonTypeName("refund")
-class RefundTransaction(
- timestamp: Timestamp,
- eventId: String,
- val orderShortInfo: OrderShortInfo,
- /**
- * Unique identifier for this refund.
- * (Identifies multiple refund permissions that were obtained at once.)
- */
- val refundGroupId: String,
- /**
- * Part of the refund that couldn't be applied because
- * the refund permissions were expired.
- */
- val amountRefundedInvalid: Amount,
- /**
- * Amount that has been refunded by the merchant.
- */
- val amountRefundedRaw: Amount,
- /**
- * Amount will be added to the wallet's balance after fees and refreshing.
- */
- val amountRefundedEffective: Amount
-) : Transaction(timestamp, eventId) {
- override val icon = R.drawable.transaction_refund
- override val title = orderShortInfo.summary
- override val detailPageLayout = R.layout.fragment_event_paid
- override val showToUser = true
- override val displayAmount = DisplayAmount(amountRefundedEffective, AmountType.Positive)
- override fun isCurrency(currency: String) = amountRefundedRaw.currency == currency
-}
-
-@JsonTypeInfo(
- use = NAME,
- include = PROPERTY,
- property = "type"
-)
-@JsonSubTypes(
- Type(value = WithdrawalSourceReserve::class, name = "reserve")
-)
-abstract class WithdrawalSource
-
-@Suppress("unused")
-@JsonTypeName("tip")
-class WithdrawalSourceTip(
- val tipId: String
-) : WithdrawalSource()
-
-@JsonTypeName("reserve")
-class WithdrawalSourceReserve(
- val reservePub: String
-) : WithdrawalSource()
-
-data class OrderShortInfo(
- /**
- * Wallet-internal identifier of the proposal.
- */
- val proposalId: String,
- /**
- * Order ID, uniquely identifies the order within a merchant instance.
- */
- val orderId: String,
- /**
- * Base URL of the merchant.
- */
- val merchantBaseUrl: String,
- /**
- * Amount that must be paid for the contract.
- */
- val amount: Amount,
- /**
- * Summary of the proposal, given by the merchant.
- */
- val summary: String
-)
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
index 440d07f..5aca896 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
@@ -34,13 +34,23 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
import net.taler.common.exhaustive
import net.taler.common.toRelativeTime
import net.taler.wallet.R
+import net.taler.wallet.history.AmountType
+import net.taler.wallet.history.DisplayAmount
+import net.taler.wallet.history.History
+import net.taler.wallet.history.HistoryEvent
+import net.taler.wallet.history.OrderAcceptedHistoryEvent
+import net.taler.wallet.history.OrderRefusedHistoryEvent
+import net.taler.wallet.history.RefreshHistoryEvent
+import net.taler.wallet.history.RefreshReason
+import net.taler.wallet.history.ReserveBalanceUpdatedHistoryEvent
+import net.taler.wallet.history.TipAcceptedHistoryEvent
+import net.taler.wallet.history.TipDeclinedHistoryEvent
import net.taler.wallet.transactions.TransactionAdapter.TransactionViewHolder
internal class TransactionAdapter(
- private val devMode: Boolean,
- private val listener: OnEventClickListener,
- private var transactions: Transactions = Transactions()
+ private val listener: OnTransactionClickListener,
+ private var transactions: History = History()
) : Adapter<TransactionViewHolder>() {
lateinit var tracker: SelectionTracker<String>
@@ -52,7 +62,7 @@ internal class TransactionAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder {
val view = LayoutInflater.from(parent.context)
- .inflate(R.layout.list_item_transaction, parent, false)
+ .inflate(R.layout.list_item_history, parent, false)
return TransactionViewHolder(view)
}
@@ -63,7 +73,7 @@ internal class TransactionAdapter(
holder.bind(transaction, tracker.isSelected(transaction.eventId))
}
- fun update(updatedTransactions: Transactions) {
+ fun update(updatedTransactions: History) {
this.transactions = updatedTransactions
this.notifyDataSetChanged()
}
@@ -84,8 +94,8 @@ internal class TransactionAdapter(
private val selectableForeground = v.foreground
private val amountColor = amount.currentTextColor
- open fun bind(transaction: Transaction, selected: Boolean) {
- if (devMode || transaction.detailPageLayout != 0) {
+ open fun bind(transaction: HistoryEvent, selected: Boolean) {
+ if (transaction.detailPageLayout != 0) {
v.foreground = selectableForeground
v.setOnClickListener { listener.onTransactionClicked(transaction) }
} else {
@@ -97,12 +107,12 @@ internal class TransactionAdapter(
title.text = if (transaction.title == null) {
when (transaction) {
- is RefreshTransaction -> getRefreshTitle(transaction)
- is OrderAcceptedTransaction -> context.getString(R.string.transaction_order_accepted)
- is OrderRefusedTransaction -> context.getString(R.string.transaction_order_refused)
- is TipAcceptedTransaction -> context.getString(R.string.transaction_tip_accepted)
- is TipDeclinedTransaction -> context.getString(R.string.transaction_tip_declined)
- is ReserveBalanceUpdatedTransaction -> context.getString(R.string.transaction_reserve_balance_updated)
+ is RefreshHistoryEvent -> getRefreshTitle(transaction)
+ is OrderAcceptedHistoryEvent -> context.getString(R.string.transaction_order_accepted)
+ is OrderRefusedHistoryEvent -> context.getString(R.string.transaction_order_refused)
+ is TipAcceptedHistoryEvent -> context.getString(R.string.transaction_tip_accepted)
+ is TipDeclinedHistoryEvent -> context.getString(R.string.transaction_tip_declined)
+ is ReserveBalanceUpdatedHistoryEvent -> context.getString(R.string.transaction_reserve_balance_updated)
else -> transaction::class.java.simpleName
}
} else transaction.title
@@ -137,7 +147,7 @@ internal class TransactionAdapter(
}
}
- private fun getRefreshTitle(transaction: RefreshTransaction): String {
+ private fun getRefreshTitle(transaction: RefreshHistoryEvent): String {
val res = when (transaction.refreshReason) {
RefreshReason.MANUAL -> R.string.transaction_refresh_reason_manual
RefreshReason.PAY -> R.string.transaction_refresh_reason_pay
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 909a7bf..bb70b5c 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -37,6 +37,11 @@ import net.taler.common.toAbsoluteTime
import net.taler.wallet.MainViewModel
import net.taler.wallet.R
import net.taler.wallet.cleanExchange
+import net.taler.wallet.history.JsonDialogFragment
+import net.taler.wallet.history.OrderShortInfo
+import net.taler.wallet.history.PaymentHistoryEvent
+import net.taler.wallet.history.RefundHistoryEvent
+import net.taler.wallet.history.WithdrawHistoryEvent
class TransactionDetailFragment : Fragment() {
@@ -65,9 +70,9 @@ class TransactionDetailFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
timeView.text = event.timestamp.ms.toAbsoluteTime(requireContext())
when (val e = event) {
- is WithdrawTransaction -> bind(e)
- is PaymentTransaction -> bind(e)
- is RefundTransaction -> bind(e)
+ is WithdrawHistoryEvent -> bind(e)
+ is PaymentHistoryEvent -> bind(e)
+ is RefundHistoryEvent -> bind(e)
else -> Toast.makeText(
requireContext(),
"event ${e.javaClass} not implement",
@@ -90,7 +95,7 @@ class TransactionDetailFragment : Fragment() {
}
}
- private fun bind(event: WithdrawTransaction) {
+ private fun bind(event: WithdrawHistoryEvent) {
effectiveAmountLabel.text = getString(R.string.withdraw_total)
effectiveAmountView.text = event.amountWithdrawnEffective.toString()
chosenAmountLabel.text = getString(R.string.amount_chosen)
@@ -101,13 +106,13 @@ class TransactionDetailFragment : Fragment() {
exchangeView.text = cleanExchange(event.exchangeBaseUrl)
}
- private fun bind(event: PaymentTransaction) {
+ private fun bind(event: PaymentHistoryEvent) {
amountPaidWithFeesView.text = event.amountPaidWithFees.toString()
val fee = event.amountPaidWithFees - event.orderShortInfo.amount
bindOrderAndFee(event.orderShortInfo, fee)
}
- private fun bind(event: RefundTransaction) {
+ private fun bind(event: RefundHistoryEvent) {
amountPaidWithFeesLabel.text = getString(R.string.transaction_refund)
amountPaidWithFeesView.setTextColor(getColor(requireContext(), R.color.green))
amountPaidWithFeesView.text =
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
index 549b2a8..850a3bb 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
@@ -18,70 +18,62 @@ package net.taler.wallet.transactions
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.asLiveData
-import androidx.lifecycle.switchMap
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.onCompletion
-import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import net.taler.wallet.backend.WalletBackendApi
+import net.taler.wallet.history.History
+import net.taler.wallet.history.HistoryEvent
+import org.json.JSONObject
sealed class TransactionsResult {
object Error : TransactionsResult()
- class Success(val transactions: Transactions) : TransactionsResult()
+ class Success(val transactions: History) : TransactionsResult()
}
-@Suppress("EXPERIMENTAL_API_USAGE")
class TransactionManager(
private val walletBackendApi: WalletBackendApi,
+ private val scope: CoroutineScope,
private val mapper: ObjectMapper
) {
private val mProgress = MutableLiveData<Boolean>()
val progress: LiveData<Boolean> = mProgress
- val showAll = MutableLiveData<Boolean>()
-
var selectedCurrency: String? = null
- var selectedEvent: Transaction? = null
+ var selectedEvent: HistoryEvent? = null
- val transactions: LiveData<TransactionsResult> = showAll.switchMap { showAll ->
- loadTransactions(showAll)
- .onStart { mProgress.postValue(true) }
- .onCompletion { mProgress.postValue(false) }
- .asLiveData(Dispatchers.IO)
- }
+ private val mTransactions = MutableLiveData<TransactionsResult>()
+ val transactions: LiveData<TransactionsResult> = mTransactions
- private fun loadTransactions(showAll: Boolean) = callbackFlow {
+ fun loadTransactions() {
+ mProgress.postValue(true)
walletBackendApi.sendRequest("getHistory", null) { isError, result ->
- launch(Dispatchers.Default) {
- if (isError) {
- offer(TransactionsResult.Error)
- close()
- return@launch
- }
- val transactions = Transactions()
- val json = result.getJSONArray("history")
- val currency = selectedCurrency
- for (i in 0 until json.length()) {
- val event: Transaction = mapper.readValue(json.getString(i))
- event.json = json.getJSONObject(i)
- if (currency == null || event.isCurrency(currency)) {
- transactions.add(event)
- }
- }
- transactions.reverse() // show latest first
- val filtered =
- if (showAll) transactions else transactions.filter { it.showToUser } as Transactions
- offer(TransactionsResult.Success(filtered))
- close()
+ scope.launch(Dispatchers.Default) {
+ onTransactionsLoaded(isError, result)
+ }
+ }
+ }
+
+ private fun onTransactionsLoaded(isError: Boolean, result: JSONObject) {
+ if (isError) {
+ mTransactions.postValue(TransactionsResult.Error)
+ return
+ }
+ val transactions = History()
+ val json = result.getJSONArray("history")
+ val currency = selectedCurrency
+ for (i in 0 until json.length()) {
+ val event: HistoryEvent = mapper.readValue(json.getString(i))
+ if (event.showToUser && (currency == null || event.isCurrency(currency))) {
+ transactions.add(event)
}
}
- awaitClose()
+ transactions.reverse() // show latest first
+ mProgress.postValue(false)
+ mTransactions.postValue(TransactionsResult.Success(transactions))
}
}
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
index e7adaf1..2b5337f 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -42,17 +42,18 @@ import net.taler.common.fadeIn
import net.taler.common.fadeOut
import net.taler.wallet.MainViewModel
import net.taler.wallet.R
+import net.taler.wallet.history.HistoryEvent
-interface OnEventClickListener {
- fun onTransactionClicked(transaction: Transaction)
+interface OnTransactionClickListener {
+ fun onTransactionClicked(transaction: HistoryEvent)
}
-class TransactionsFragment : Fragment(), OnEventClickListener, ActionMode.Callback {
+class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode.Callback {
private val model: MainViewModel by activityViewModels()
private val transactionManager by lazy { model.transactionManager }
- private val transactionAdapter by lazy { TransactionAdapter(model.devMode.value == true, this) }
+ private val transactionAdapter by lazy { TransactionAdapter(this) }
private val currency by lazy { transactionManager.selectedCurrency!! }
private var tracker: SelectionTracker<String>? = null
private var actionMode: ActionMode? = null
@@ -109,7 +110,7 @@ class TransactionsFragment : Fragment(), OnEventClickListener, ActionMode.Callba
})
// kicks off initial load, needs to be adapted if showAll state is ever saved
- if (savedInstanceState == null) transactionManager.showAll.value = model.devMode.value
+ if (savedInstanceState == null) transactionManager.loadTransactions()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
@@ -137,14 +138,11 @@ class TransactionsFragment : Fragment(), OnEventClickListener, ActionMode.Callba
}
}
- override fun onTransactionClicked(transaction: Transaction) {
+ override fun onTransactionClicked(transaction: HistoryEvent) {
if (actionMode != null) return // don't react on clicks while in action mode
if (transaction.detailPageLayout != 0) {
transactionManager.selectedEvent = transaction
findNavController().navigate(R.id.action_nav_transaction_detail)
- } else if (model.devMode.value == true) {
- JsonDialogFragment.new(transaction.json.toString(2))
- .show(parentFragmentManager, null)
}
}