summaryrefslogtreecommitdiff
path: root/wallet/src/main/java/net/taler/wallet/transactions
diff options
context:
space:
mode:
authorTorsten Grote <t@grobox.de>2020-04-15 13:49:25 -0300
committerTorsten Grote <t@grobox.de>2020-04-15 13:49:25 -0300
commitea2abcac101645e429cab734c726e3b6a744dae9 (patch)
treeed70393d7889b10446d5dbe1f402835e2dab1e2c /wallet/src/main/java/net/taler/wallet/transactions
parentea3250845fb266a2ecd5ebeba561bc99101bf3de (diff)
downloadtaler-android-ea2abcac101645e429cab734c726e3b6a744dae9.tar.gz
taler-android-ea2abcac101645e429cab734c726e3b6a744dae9.tar.bz2
taler-android-ea2abcac101645e429cab734c726e3b6a744dae9.zip
[wallet] show simplified transactions per currency
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/transactions')
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/Transaction.kt82
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt168
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt2
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt11
5 files changed, 129 insertions, 140 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transaction.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transaction.kt
index 5fcabe7..c0142d5 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transaction.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transaction.kt
@@ -18,7 +18,6 @@ package net.taler.wallet.transactions
import androidx.annotation.DrawableRes
import androidx.annotation.LayoutRes
-import androidx.annotation.StringRes
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY
@@ -32,6 +31,7 @@ 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 {
@@ -93,6 +93,17 @@ class ReserveShortInfo(
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(
@@ -137,21 +148,20 @@ ReserveCreated = "reserve-created",
abstract class Transaction(
val timestamp: Timestamp,
@get:LayoutRes
- open val layout: Int = R.layout.transaction_row,
- @get:LayoutRes
open val detailPageLayout: Int = 0,
- @get:StringRes
- open val title: 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) : Transaction(timestamp) {
- override val title = R.string.transaction_unknown
+ override val title: String? = null
}
@JsonTypeName("exchange-added")
@@ -160,7 +170,7 @@ class ExchangeAddedEvent(
val exchangeBaseUrl: String,
val builtIn: Boolean
) : Transaction(timestamp) {
- override val title = R.string.history_event_exchange_added
+ override val title = cleanExchange(exchangeBaseUrl)
}
@JsonTypeName("exchange-updated")
@@ -168,7 +178,7 @@ class ExchangeUpdatedEvent(
timestamp: Timestamp,
val exchangeBaseUrl: String
) : Transaction(timestamp) {
- override val title = R.string.history_event_exchange_updated
+ override val title = cleanExchange(exchangeBaseUrl)
}
@@ -193,7 +203,9 @@ class ReserveBalanceUpdatedTransaction(
*/
val reserveUnclaimedAmount: Amount
) : Transaction(timestamp) {
- override val title = R.string.transaction_reserve_balance_updated
+ override val title: String? = null
+ override val displayAmount = DisplayAmount(reserveBalance, AmountType.Neutral)
+ override fun isCurrency(currency: String) = reserveBalance.currency == currency
}
@JsonTypeName("withdrawn")
@@ -219,11 +231,12 @@ class WithdrawTransaction(
*/
val amountWithdrawnEffective: Amount
) : Transaction(timestamp) {
- override val layout = R.layout.transaction_in
override val detailPageLayout = R.layout.fragment_event_withdraw
- override val title = R.string.transaction_withdrawal
+ 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")
@@ -235,7 +248,8 @@ class OrderAcceptedTransaction(
val orderShortInfo: OrderShortInfo
) : Transaction(timestamp) {
override val icon = R.drawable.ic_add_circle
- override val title = R.string.transaction_order_accepted
+ override val title: String? = null
+ override fun isCurrency(currency: String) = orderShortInfo.amount.currency == currency
}
@JsonTypeName("order-refused")
@@ -247,7 +261,8 @@ class OrderRefusedTransaction(
val orderShortInfo: OrderShortInfo
) : Transaction(timestamp) {
override val icon = R.drawable.ic_cancel
- override val title = R.string.transaction_order_refused
+ override val title: String? = null
+ override fun isCurrency(currency: String) = orderShortInfo.amount.currency == currency
}
@JsonTypeName("payment-sent")
@@ -275,11 +290,12 @@ class PaymentTransaction(
*/
val sessionId: String?
) : Transaction(timestamp) {
- override val layout = R.layout.transaction_out
override val detailPageLayout = R.layout.fragment_event_paid
- override val title = R.string.transaction_payment
+ 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")
@@ -294,10 +310,11 @@ class PaymentAbortedTransaction(
*/
val amountLost: Amount
) : Transaction(timestamp) {
- override val layout = R.layout.transaction_out
- override val title = R.string.transaction_payment_aborted
+ 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")
@@ -325,10 +342,19 @@ class RefreshTransaction(
*/
val refreshGroupId: String
) : Transaction(timestamp) {
- override val layout = R.layout.transaction_out
override val icon = R.drawable.transaction_refresh
- override val title = R.string.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")
@@ -345,7 +371,8 @@ class OrderRedirectedTransaction(
val alreadyPaidOrderShortInfo: OrderShortInfo
) : Transaction(timestamp) {
override val icon = R.drawable.ic_directions
- override val title = R.string.transaction_order_redirected
+ override val title = newOrderShortInfo.summary
+ override fun isCurrency(currency: String) = newOrderShortInfo.amount.currency == currency
}
@JsonTypeName("tip-accepted")
@@ -361,9 +388,10 @@ class TipAcceptedTransaction(
val tipRaw: Amount
) : Transaction(timestamp) {
override val icon = R.drawable.transaction_tip_accepted
- override val title = R.string.transaction_tip_accepted
- override val layout = R.layout.transaction_in
+ 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")
@@ -379,9 +407,10 @@ class TipDeclinedTransaction(
val tipAmount: Amount
) : Transaction(timestamp) {
override val icon = R.drawable.transaction_tip_declined
- override val title = R.string.transaction_tip_declined
- override val layout = R.layout.transaction_in
+ 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")
@@ -408,10 +437,11 @@ class RefundTransaction(
val amountRefundedEffective: Amount
) : Transaction(timestamp) {
override val icon = R.drawable.transaction_refund
- override val title = R.string.transaction_refund
- override val layout = R.layout.transaction_in
+ 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(
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 beebcda..809f6a9 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
@@ -17,18 +17,19 @@
package net.taler.wallet.transactions
import android.content.Context
-import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.LayoutInflater
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.CallSuper
import androidx.recyclerview.widget.RecyclerView.Adapter
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.cleanExchange
import net.taler.wallet.transactions.TransactionAdapter.TransactionViewHolder
@@ -42,15 +43,10 @@ internal class TransactionAdapter(
setHasStableIds(false)
}
- override fun getItemViewType(position: Int): Int = transactions[position].layout
-
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder {
- val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
- return when (viewType) {
- R.layout.transaction_in -> TransactionInViewHolder(view)
- R.layout.transaction_out -> TransactionOutViewHolder(view)
- else -> GenericTransactionViewHolder(view)
- }
+ val view = LayoutInflater.from(parent.context)
+ .inflate(R.layout.list_item_transaction, parent, false)
+ return TransactionViewHolder(view)
}
override fun getItemCount(): Int = transactions.size
@@ -65,122 +61,73 @@ internal class TransactionAdapter(
this.notifyDataSetChanged()
}
- internal abstract inner class TransactionViewHolder(private val v: View) : ViewHolder(v) {
+ internal open inner class TransactionViewHolder(private val v: View) : ViewHolder(v) {
protected val context: Context = v.context
+
private val icon: ImageView = v.findViewById(R.id.icon)
protected val title: TextView = v.findViewById(R.id.title)
private val time: TextView = v.findViewById(R.id.time)
+ private val amount: TextView = v.findViewById(R.id.amount)
+
private val selectableBackground = v.background
+ private val amountColor = amount.currentTextColor
@CallSuper
- open fun bind(event: Transaction) {
- if (devMode || event.detailPageLayout != 0) {
+ open fun bind(transaction: Transaction) {
+ if (devMode || transaction.detailPageLayout != 0) {
v.background = selectableBackground
- v.setOnClickListener { listener.onEventClicked(event) }
+ v.setOnClickListener { listener.onEventClicked(transaction) }
} else {
v.background = null
v.setOnClickListener(null)
}
- icon.setImageResource(event.icon)
- if (event.title == 0) title.text = event::class.java.simpleName
- else title.setText(event.title)
- time.text = event.timestamp.ms.toRelativeTime(context)
- }
-
- }
-
- internal inner class GenericTransactionViewHolder(v: View) : TransactionViewHolder(v) {
-
- private val info: TextView = v.findViewById(R.id.info)
-
- override fun bind(transaction: Transaction) {
- super.bind(transaction)
- info.text = when (transaction) {
- is ExchangeAddedEvent -> cleanExchange(transaction.exchangeBaseUrl)
- is ExchangeUpdatedEvent -> cleanExchange(transaction.exchangeBaseUrl)
- is ReserveBalanceUpdatedTransaction -> transaction.reserveBalance.toString()
- is PaymentTransaction -> transaction.orderShortInfo.summary
- is OrderAcceptedTransaction -> transaction.orderShortInfo.summary
- is OrderRefusedTransaction -> transaction.orderShortInfo.summary
- is OrderRedirectedTransaction -> transaction.newOrderShortInfo.summary
- else -> ""
- }
+ icon.setImageResource(transaction.icon)
+
+ 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)
+ else -> transaction::class.java.simpleName
+ }
+ } else transaction.title
+
+ time.text = transaction.timestamp.ms.toRelativeTime(context)
+ bindAmount(transaction.displayAmount)
}
- }
-
- internal inner class TransactionInViewHolder(v: View) : TransactionViewHolder(v) {
-
- private val summary: TextView = v.findViewById(R.id.summary)
- private val amountWithdrawn: TextView = v.findViewById(R.id.amountWithdrawn)
- private val paintFlags = amountWithdrawn.paintFlags
-
- override fun bind(event: Transaction) {
- super.bind(event)
- when (event) {
- is WithdrawTransaction -> bind(event)
- is RefundTransaction -> bind(event)
- is TipAcceptedTransaction -> bind(event)
- is TipDeclinedTransaction -> bind(event)
- }
- }
-
- private fun bind(event: WithdrawTransaction) {
- summary.text = cleanExchange(event.exchangeBaseUrl)
- amountWithdrawn.text =
- context.getString(R.string.amount_positive, event.amountWithdrawnEffective)
- amountWithdrawn.paintFlags = paintFlags
- }
-
- private fun bind(event: RefundTransaction) {
- summary.text = event.orderShortInfo.summary
- amountWithdrawn.text =
- context.getString(R.string.amount_positive, event.amountRefundedEffective)
- amountWithdrawn.paintFlags = paintFlags
- }
-
- private fun bind(transaction: TipAcceptedTransaction) {
- summary.text = null
- amountWithdrawn.text = context.getString(R.string.amount_positive, transaction.tipRaw)
- amountWithdrawn.paintFlags = paintFlags
- }
-
- private fun bind(transaction: TipDeclinedTransaction) {
- summary.text = null
- amountWithdrawn.text = context.getString(R.string.amount_positive, transaction.tipAmount)
- amountWithdrawn.paintFlags = amountWithdrawn.paintFlags or STRIKE_THRU_TEXT_FLAG
- }
-
- }
-
- internal inner class TransactionOutViewHolder(v: View) : TransactionViewHolder(v) {
-
- private val summary: TextView = v.findViewById(R.id.summary)
- private val amountPaidWithFees: TextView = v.findViewById(R.id.amountPaidWithFees)
-
- override fun bind(event: Transaction) {
- super.bind(event)
- when (event) {
- is PaymentTransaction -> bind(event)
- is PaymentAbortedTransaction -> bind(event)
- is RefreshTransaction -> bind(event)
+ private fun bindAmount(displayAmount: DisplayAmount?) {
+ if (displayAmount == null) {
+ amount.visibility = GONE
+ } else {
+ amount.visibility = VISIBLE
+ when (displayAmount.type) {
+ AmountType.Positive -> {
+ amount.text = context.getString(
+ R.string.amount_positive, displayAmount.amount.amountStr
+ )
+ amount.setTextColor(context.getColor(R.color.green))
+ }
+ AmountType.Negative -> {
+ amount.text = context.getString(
+ R.string.amount_negative, displayAmount.amount.amountStr
+ )
+ amount.setTextColor(context.getColor(R.color.red))
+ }
+ AmountType.Neutral -> {
+ amount.text = displayAmount.amount.amountStr
+ amount.setTextColor(amountColor)
+ }
+ }.exhaustive
}
}
- private fun bind(event: PaymentTransaction) {
- summary.text = event.orderShortInfo.summary
- amountPaidWithFees.text =
- context.getString(R.string.amount_negative, event.amountPaidWithFees)
- }
-
- private fun bind(transaction: PaymentAbortedTransaction) {
- summary.text = transaction.orderShortInfo.summary
- amountPaidWithFees.text = context.getString(R.string.amount_negative, transaction.amountLost)
- }
-
- private fun bind(event: RefreshTransaction) {
- val res = when (event.refreshReason) {
+ private fun getRefreshTitle(transaction: RefreshTransaction): String {
+ val res = when (transaction.refreshReason) {
RefreshReason.MANUAL -> R.string.transaction_refresh_reason_manual
RefreshReason.PAY -> R.string.transaction_refresh_reason_pay
RefreshReason.REFUND -> R.string.transaction_refresh_reason_refund
@@ -188,10 +135,7 @@ internal class TransactionAdapter(
RefreshReason.RECOUP -> R.string.transaction_refresh_reason_recoup
RefreshReason.BACKUP_RESTORED -> R.string.transaction_refresh_reason_backup_restored
}
- summary.text = context.getString(res)
- val fee = event.amountRefreshedRaw - event.amountRefreshedEffective
- if (fee.isZero()) amountPaidWithFees.text = null
- else amountPaidWithFees.text = context.getString(R.string.amount_negative, fee)
+ return context.getString(R.string.transaction_refresh) + " " + context.getString(res)
}
}
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 f198215..909a7bf 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -59,7 +59,7 @@ class TransactionDetailFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
requireActivity().title =
- getString(if (event.title != 0) event.title else R.string.transactions_detail_title)
+ if (event.title != null) event.title else getString(R.string.transactions_detail_title)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
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 c4ab785..549b2a8 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
@@ -46,6 +46,7 @@ class TransactionManager(
val showAll = MutableLiveData<Boolean>()
+ var selectedCurrency: String? = null
var selectedEvent: Transaction? = null
val transactions: LiveData<TransactionsResult> = showAll.switchMap { showAll ->
@@ -65,10 +66,13 @@ class TransactionManager(
}
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)
- transactions.add(event)
+ if (currency == null || event.isCurrency(currency)) {
+ transactions.add(event)
+ }
}
transactions.reverse() // show latest first
val filtered =
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 663a5aa..4f62547 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -47,6 +47,7 @@ class TransactionsFragment : Fragment(), OnEventClickListener {
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 currency by lazy { transactionManager.selectedCurrency!! }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -78,6 +79,16 @@ class TransactionsFragment : Fragment(), OnEventClickListener {
if (savedInstanceState == null) transactionManager.showAll.value = model.devMode.value
}
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ model.balances.observe(viewLifecycleOwner, Observer { balances ->
+ balances[currency]?.available?.let { amount ->
+ requireActivity().title =
+ getString(R.string.transactions_detail_title_balance, amount)
+ }
+ })
+ }
+
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.transactions, menu)
}