summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--taler-kotlin-common/src/main/java/net/taler/common/ContractTerms.kt5
-rw-r--r--wallet/build.gradle4
-rw-r--r--wallet/src/main/java/net/taler/wallet/history/HistoryEvent.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt83
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt71
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt23
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt178
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt7
-rw-r--r--wallet/src/main/res/layout/fragment_transaction_payment.xml (renamed from wallet/src/main/res/layout/fragment_event_paid.xml)0
-rw-r--r--wallet/src/main/res/layout/fragment_transaction_withdrawal.xml (renamed from wallet/src/main/res/layout/fragment_event_withdraw.xml)0
-rw-r--r--wallet/src/main/res/layout/list_item_transaction.xml89
-rw-r--r--wallet/src/main/res/menu/transactions_detail.xml4
-rw-r--r--wallet/src/main/res/navigation/nav_graph.xml2
-rw-r--r--wallet/src/main/res/values/strings.xml6
14 files changed, 351 insertions, 127 deletions
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/ContractTerms.kt b/taler-kotlin-common/src/main/java/net/taler/common/ContractTerms.kt
index cd417ef..63c3eb4 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/ContractTerms.kt
+++ b/taler-kotlin-common/src/main/java/net/taler/common/ContractTerms.kt
@@ -67,6 +67,11 @@ data class ContractProduct(
}
}
+data class ContractMerchant(
+ // TODO this shouldn't be nullable
+ val name: String?
+)
+
@JsonInclude(NON_EMPTY)
class Timestamp(
@JsonProperty("t_ms")
diff --git a/wallet/build.gradle b/wallet/build.gradle
index f976b24..91eb324 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -23,7 +23,7 @@ plugins {
id "de.undercouch.download"
}
-def walletCoreVersion = "v0.7.1-dev.3"
+def walletCoreVersion = "v0.7.1-dev.4"
android {
compileSdkVersion 29
@@ -35,7 +35,7 @@ android {
minSdkVersion 24
targetSdkVersion 29
versionCode 6
- versionName "0.7.1.dev.3"
+ versionName "0.7.1.dev.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "WALLET_CORE_VERSION", "\"$walletCoreVersion\""
}
diff --git a/wallet/src/main/java/net/taler/wallet/history/HistoryEvent.kt b/wallet/src/main/java/net/taler/wallet/history/HistoryEvent.kt
index acca679..1618988 100644
--- a/wallet/src/main/java/net/taler/wallet/history/HistoryEvent.kt
+++ b/wallet/src/main/java/net/taler/wallet/history/HistoryEvent.kt
@@ -233,7 +233,7 @@ class WithdrawHistoryEvent(
*/
val amountWithdrawnEffective: Amount
) : HistoryEvent(timestamp, eventId) {
- override val detailPageLayout = R.layout.fragment_event_withdraw
+ override val detailPageLayout = R.layout.fragment_transaction_withdrawal
override val title = cleanExchange(exchangeBaseUrl)
override val icon = R.drawable.transaction_withdrawal
override val showToUser = true
@@ -298,7 +298,7 @@ class PaymentHistoryEvent(
*/
val sessionId: String?
) : HistoryEvent(timestamp, eventId) {
- override val detailPageLayout = R.layout.fragment_event_paid
+ override val detailPageLayout = R.layout.fragment_transaction_payment
override val title = orderShortInfo.summary
override val icon = R.drawable.ic_cash_usd_outline
override val showToUser = true
@@ -464,7 +464,7 @@ class RefundHistoryEvent(
) : HistoryEvent(timestamp, eventId) {
override val icon = R.drawable.transaction_refund
override val title = orderShortInfo.summary
- override val detailPageLayout = R.layout.fragment_event_paid
+ override val detailPageLayout = R.layout.fragment_transaction_payment
override val showToUser = true
override val displayAmount = DisplayAmount(
amountRefundedEffective,
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 5aca896..044a054 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
@@ -35,24 +35,13 @@ 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 listener: OnTransactionClickListener,
- private var transactions: History = History()
+ private val listener: OnTransactionClickListener
) : Adapter<TransactionViewHolder>() {
+ private var transactions: List<Transaction> = ArrayList()
lateinit var tracker: SelectionTracker<String>
val keyProvider = TransactionKeyProvider()
@@ -62,7 +51,7 @@ internal class TransactionAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder {
val view = LayoutInflater.from(parent.context)
- .inflate(R.layout.list_item_history, parent, false)
+ .inflate(R.layout.list_item_transaction, parent, false)
return TransactionViewHolder(view)
}
@@ -70,16 +59,16 @@ internal class TransactionAdapter(
override fun onBindViewHolder(holder: TransactionViewHolder, position: Int) {
val transaction = transactions[position]
- holder.bind(transaction, tracker.isSelected(transaction.eventId))
+ holder.bind(transaction, tracker.isSelected(transaction.transactionId))
}
- fun update(updatedTransactions: History) {
+ fun update(updatedTransactions: List<Transaction>) {
this.transactions = updatedTransactions
this.notifyDataSetChanged()
}
fun selectAll() = transactions.forEach {
- tracker.select(it.eventId)
+ tracker.select(it.transactionId)
}
internal open inner class TransactionViewHolder(private val v: View) : ViewHolder(v) {
@@ -90,11 +79,14 @@ internal class TransactionAdapter(
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 pendingView: TextView = v.findViewById(R.id.pendingView)
private val selectableForeground = v.foreground
private val amountColor = amount.currentTextColor
+ private val red = context.getColor(R.color.red)
+ private val green = context.getColor(R.color.green)
- open fun bind(transaction: HistoryEvent, selected: Boolean) {
+ open fun bind(transaction: Transaction, selected: Boolean) {
if (transaction.detailPageLayout != 0) {
v.foreground = selectableForeground
v.setOnClickListener { listener.onTransactionClicked(transaction) }
@@ -105,66 +97,43 @@ internal class TransactionAdapter(
v.isActivated = selected
icon.setImageResource(transaction.icon)
- title.text = if (transaction.title == null) {
- when (transaction) {
- 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
-
+ title.text = transaction.getTitle(context)
time.text = transaction.timestamp.ms.toRelativeTime(context)
- bindAmount(transaction.displayAmount)
+ bindAmount(transaction)
+ pendingView.visibility = if (transaction.pending) VISIBLE else GONE
}
- private fun bindAmount(displayAmount: DisplayAmount?) {
- if (displayAmount == null) {
+ private fun bindAmount(transaction: Transaction) {
+ val amountEffective = transaction.amountEffective
+ if (amountEffective == null) {
amount.visibility = GONE
} else {
amount.visibility = VISIBLE
- when (displayAmount.type) {
+ when (transaction.amountType) {
AmountType.Positive -> {
- amount.text = context.getString(
- R.string.amount_positive, displayAmount.amount.amountStr
- )
- amount.setTextColor(context.getColor(R.color.green))
+ amount.text =
+ context.getString(R.string.amount_positive, amountEffective.amountStr)
+ amount.setTextColor(if (transaction.pending) amountColor else green)
}
AmountType.Negative -> {
- amount.text = context.getString(
- R.string.amount_negative, displayAmount.amount.amountStr
- )
- amount.setTextColor(context.getColor(R.color.red))
+ amount.text =
+ context.getString(R.string.amount_negative, amountEffective.amountStr)
+ amount.setTextColor(if (transaction.pending) amountColor else red)
}
AmountType.Neutral -> {
- amount.text = displayAmount.amount.amountStr
+ amount.text = amountEffective.amountStr
amount.setTextColor(amountColor)
}
}.exhaustive
}
}
- 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
- RefreshReason.REFUND -> R.string.transaction_refresh_reason_refund
- RefreshReason.ABORT_PAY -> R.string.transaction_refresh_reason_abort_pay
- RefreshReason.RECOUP -> R.string.transaction_refresh_reason_recoup
- RefreshReason.BACKUP_RESTORED -> R.string.transaction_refresh_reason_backup_restored
- }
- return context.getString(R.string.transaction_refresh) + " " + context.getString(res)
- }
-
}
internal inner class TransactionKeyProvider : ItemKeyProvider<String>(SCOPE_MAPPED) {
- override fun getKey(position: Int) = transactions[position].eventId
+ override fun getKey(position: Int) = transactions[position].transactionId
override fun getPosition(key: String): Int {
- return transactions.indexOfFirst { it.eventId == key }
+ return transactions.indexOfFirst { it.transactionId == key }
}
}
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 bb70b5c..c9e51e4 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -28,26 +28,21 @@ import android.widget.Toast.LENGTH_LONG
import androidx.core.content.ContextCompat.getColor
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
-import kotlinx.android.synthetic.main.fragment_event_paid.*
-import kotlinx.android.synthetic.main.fragment_event_withdraw.*
-import kotlinx.android.synthetic.main.fragment_event_withdraw.feeView
-import kotlinx.android.synthetic.main.fragment_event_withdraw.timeView
+import kotlinx.android.synthetic.main.fragment_transaction_payment.*
+import kotlinx.android.synthetic.main.fragment_transaction_withdrawal.*
+import kotlinx.android.synthetic.main.fragment_transaction_withdrawal.feeView
+import kotlinx.android.synthetic.main.fragment_transaction_withdrawal.timeView
import net.taler.common.Amount
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() {
private val model: MainViewModel by activityViewModels()
private val transactionManager by lazy { model.transactionManager }
- private val event by lazy { requireNotNull(transactionManager.selectedEvent) }
+ private val transaction by lazy { requireNotNull(transactionManager.selectedTransaction) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -58,21 +53,22 @@ class TransactionDetailFragment : Fragment() {
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- return inflater.inflate(event.detailPageLayout, container, false)
+ return inflater.inflate(transaction.detailPageLayout, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
- requireActivity().title =
- if (event.title != null) event.title else getString(R.string.transactions_detail_title)
+ requireActivity().apply {
+ title = transaction.getTitle(this)
+ }
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- timeView.text = event.timestamp.ms.toAbsoluteTime(requireContext())
- when (val e = event) {
- is WithdrawHistoryEvent -> bind(e)
- is PaymentHistoryEvent -> bind(e)
- is RefundHistoryEvent -> bind(e)
+ timeView.text = transaction.timestamp.ms.toAbsoluteTime(requireContext())
+ when (val e = transaction) {
+ is TransactionWithdrawal -> bind(e)
+ is TransactionPayment -> bind(e)
+ is TransactionRefund -> bind(e)
else -> Toast.makeText(
requireContext(),
"event ${e.javaClass} not implement",
@@ -87,46 +83,41 @@ class TransactionDetailFragment : Fragment() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
- R.id.show_json -> {
- JsonDialogFragment.new(event.json.toString(2)).show(parentFragmentManager, null)
- true
- }
else -> super.onOptionsItemSelected(item)
}
}
- private fun bind(event: WithdrawHistoryEvent) {
+ private fun bind(t: TransactionWithdrawal) {
effectiveAmountLabel.text = getString(R.string.withdraw_total)
- effectiveAmountView.text = event.amountWithdrawnEffective.toString()
+ effectiveAmountView.text = t.amountEffective.toString()
chosenAmountLabel.text = getString(R.string.amount_chosen)
chosenAmountView.text =
- getString(R.string.amount_positive, event.amountWithdrawnRaw.toString())
- val fee = event.amountWithdrawnRaw - event.amountWithdrawnEffective
+ getString(R.string.amount_positive, t.amountRaw.toString())
+ val fee = t.amountRaw - (t.amountEffective ?: t.amountRaw)
feeView.text = getString(R.string.amount_negative, fee.toString())
- exchangeView.text = cleanExchange(event.exchangeBaseUrl)
+ exchangeView.text = cleanExchange(t.exchangeBaseUrl)
}
- private fun bind(event: PaymentHistoryEvent) {
- amountPaidWithFeesView.text = event.amountPaidWithFees.toString()
- val fee = event.amountPaidWithFees - event.orderShortInfo.amount
- bindOrderAndFee(event.orderShortInfo, fee)
+ private fun bind(t: TransactionPayment) {
+ amountPaidWithFeesView.text = t.amountEffective.toString()
+ val fee = (t.amountEffective ?: t.amountRaw) - t.amountRaw
+ bindOrderAndFee(t.info, t.amountRaw, fee)
}
- private fun bind(event: RefundHistoryEvent) {
+ private fun bind(t: TransactionRefund) {
amountPaidWithFeesLabel.text = getString(R.string.transaction_refund)
amountPaidWithFeesView.setTextColor(getColor(requireContext(), R.color.green))
amountPaidWithFeesView.text =
- getString(R.string.amount_positive, event.amountRefundedEffective.toString())
- val fee = event.orderShortInfo.amount - event.amountRefundedEffective
- bindOrderAndFee(event.orderShortInfo, fee)
+ getString(R.string.amount_positive, t.amountEffective.toString())
+ val fee = t.amountRaw - (t.amountEffective ?: t.amountRaw)
+ bindOrderAndFee(t.info, t.amountRaw, fee)
}
- private fun bindOrderAndFee(orderShortInfo: OrderShortInfo, fee: Amount) {
- orderAmountView.text = orderShortInfo.amount.toString()
+ private fun bindOrderAndFee(info: TransactionInfo, raw: Amount, fee: Amount) {
+ orderAmountView.text = raw.toString()
feeView.text = getString(R.string.amount_negative, fee.toString())
- orderSummaryView.text = orderShortInfo.summary
- orderIdView.text =
- getString(R.string.transaction_order_id, orderShortInfo.orderId)
+ orderSummaryView.text = info.summary
+ orderIdView.text = getString(R.string.transaction_order_id, info.orderId)
}
}
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 850a3bb..81d53b9 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
@@ -16,6 +16,7 @@
package net.taler.wallet.transactions
+import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.fasterxml.jackson.databind.ObjectMapper
@@ -24,13 +25,12 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
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
+import java.util.*
sealed class TransactionsResult {
object Error : TransactionsResult()
- class Success(val transactions: History) : TransactionsResult()
+ class Success(val transactions: List<Transaction>) : TransactionsResult()
}
class TransactionManager(
@@ -43,14 +43,15 @@ class TransactionManager(
val progress: LiveData<Boolean> = mProgress
var selectedCurrency: String? = null
- var selectedEvent: HistoryEvent? = null
+ var selectedTransaction: Transaction? = null
private val mTransactions = MutableLiveData<TransactionsResult>()
val transactions: LiveData<TransactionsResult> = mTransactions
fun loadTransactions() {
mProgress.postValue(true)
- walletBackendApi.sendRequest("getHistory", null) { isError, result ->
+ val request = JSONObject(mapOf("currency" to selectedCurrency))
+ walletBackendApi.sendRequest("getTransactions", request) { isError, result ->
scope.launch(Dispatchers.Default) {
onTransactionsLoaded(isError, result)
}
@@ -62,15 +63,9 @@ class TransactionManager(
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)
- }
- }
+ Log.e("TEST", result.toString(2)) // TODO remove once API finalized
+ val transactionsArray = result.getString("transactions")
+ val transactions: LinkedList<Transaction> = mapper.readValue(transactionsArray)
transactions.reverse() // show latest first
mProgress.postValue(false)
mTransactions.postValue(TransactionsResult.Success(transactions))
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
new file mode 100644
index 0000000..2a0da3c
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -0,0 +1,178 @@
+/*
+ * 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.content.Context
+import androidx.annotation.DrawableRes
+import androidx.annotation.LayoutRes
+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.ContractMerchant
+import net.taler.common.ContractProduct
+import net.taler.common.Timestamp
+import net.taler.wallet.R
+import net.taler.wallet.cleanExchange
+import net.taler.wallet.history.AmountType
+
+@JsonTypeInfo(use = NAME, include = PROPERTY, property = "type")
+@JsonSubTypes(
+ Type(value = TransactionWithdrawal::class, name = "withdrawal"),
+ Type(value = TransactionPayment::class, name = "payment"),
+ Type(value = TransactionRefund::class, name = "refund"),
+ Type(value = TransactionTip::class, name = "tip"),
+ Type(value = TransactionRefresh::class, name = "refresh")
+)
+abstract class Transaction(
+ val transactionId: String,
+ val timestamp: Timestamp,
+ val pending: Boolean,
+ val amountRaw: Amount,
+ val amountEffective: Amount?
+) {
+ @get:DrawableRes
+ abstract val icon: Int
+
+ @get:LayoutRes
+ abstract val detailPageLayout: Int
+
+ abstract val amountType: AmountType
+
+ abstract fun getTitle(context: Context): String
+}
+
+@JsonTypeName("withdrawal")
+class TransactionWithdrawal(
+ transactionId: String,
+ timestamp: Timestamp,
+ pending: Boolean,
+ val exchangeBaseUrl: String = "unknown", // TODO fix in wallet-core
+ val confirmed: Boolean,
+ val bankConfirmationUrl: String?,
+ @JsonProperty("amountEffective") // TODO remove when fixed in wallet-core
+ amountRaw: Amount,
+ @JsonProperty("amountRaw") // TODO remove when fixed in wallet-core
+ amountEffective: Amount?
+) : Transaction(transactionId, timestamp, pending, amountRaw, amountEffective) {
+ override val icon = R.drawable.transaction_withdrawal
+ override val detailPageLayout = R.layout.fragment_transaction_withdrawal
+ override val amountType = AmountType.Positive
+ override fun getTitle(context: Context) = cleanExchange(exchangeBaseUrl)
+}
+
+@JsonTypeName("payment")
+class TransactionPayment(
+ transactionId: String,
+ timestamp: Timestamp,
+ pending: Boolean,
+ val info: TransactionInfo,
+ val status: PaymentStatus,
+ amountRaw: Amount,
+ amountEffective: Amount?
+) : Transaction(transactionId, timestamp, pending, amountRaw, amountEffective) {
+ override val icon = R.drawable.ic_cash_usd_outline
+ override val detailPageLayout = R.layout.fragment_transaction_payment
+ override val amountType = AmountType.Negative
+ override fun getTitle(context: Context) = info.merchant.name ?: info.summary
+}
+
+class TransactionInfo(
+ val orderId: String,
+ val merchant: ContractMerchant,
+ val summary: String,
+ @get:JsonProperty("description_i18n")
+ val summaryI18n: Map<String, String>?,
+ val products: List<ContractProduct>,
+ val fulfillmentUrl: String
+)
+
+enum class PaymentStatus {
+ @JsonProperty("aborted")
+ Aborted,
+
+ @JsonProperty("failed")
+ Failed,
+
+ @JsonProperty("paid")
+ Paid,
+
+ @JsonProperty("offered")
+ Offered,
+
+ @JsonProperty("accepted")
+ Accepted
+}
+
+@JsonTypeName("refund")
+class TransactionRefund(
+ transactionId: String,
+ timestamp: Timestamp,
+ pending: Boolean,
+ val refundedTransactionId: String,
+ val info: TransactionInfo,
+ val amountInvalid: Amount,
+ amountRaw: Amount,
+ amountEffective: Amount?
+) : Transaction(transactionId, timestamp, pending, amountRaw, amountEffective) {
+ override val icon = R.drawable.transaction_refund
+ override val detailPageLayout = R.layout.fragment_transaction_payment
+ override val amountType = AmountType.Positive
+ override fun getTitle(context: Context): String {
+ return context.getString(R.string.transaction_refund, info.merchant.name)
+ }
+}
+
+@JsonTypeName("tip")
+class TransactionTip(
+ transactionId: String,
+ timestamp: Timestamp,
+ pending: Boolean,
+ // TODO status: TipStatus,
+ val exchangeBaseUrl: String,
+ val merchant: ContractMerchant,
+ amountRaw: Amount,
+ amountEffective: Amount?
+) : Transaction(transactionId, timestamp, pending, amountRaw, amountEffective) {
+ override val icon = R.drawable.transaction_tip_accepted // TODO different when declined
+ override val detailPageLayout = R.layout.fragment_transaction_payment
+ override val amountType = AmountType.Positive
+ override fun getTitle(context: Context): String {
+ return context.getString(R.string.transaction_tip_from, merchant.name)
+ }
+}
+
+@JsonTypeName("refresh")
+class TransactionRefresh(
+ transactionId: String,
+ timestamp: Timestamp,
+ pending: Boolean,
+ val exchangeBaseUrl: String,
+ amountRaw: Amount,
+ amountEffective: Amount?
+) : Transaction(transactionId, timestamp, pending, amountRaw, amountEffective) {
+ override val icon = R.drawable.transaction_refresh
+ override val detailPageLayout = R.layout.fragment_transaction_payment
+ override val amountType = AmountType.Negative
+ override fun getTitle(context: Context): String {
+ return context.getString(R.string.transaction_refresh)
+ }
+}
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 2b5337f..dfd00ea 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -42,10 +42,9 @@ 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 OnTransactionClickListener {
- fun onTransactionClicked(transaction: HistoryEvent)
+ fun onTransactionClicked(transaction: Transaction)
}
class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode.Callback {
@@ -138,10 +137,10 @@ class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode.
}
}
- override fun onTransactionClicked(transaction: HistoryEvent) {
+ override fun onTransactionClicked(transaction: Transaction) {
if (actionMode != null) return // don't react on clicks while in action mode
if (transaction.detailPageLayout != 0) {
- transactionManager.selectedEvent = transaction
+ transactionManager.selectedTransaction = transaction
findNavController().navigate(R.id.action_nav_transaction_detail)
}
}
diff --git a/wallet/src/main/res/layout/fragment_event_paid.xml b/wallet/src/main/res/layout/fragment_transaction_payment.xml
index 3f17464..3f17464 100644
--- a/wallet/src/main/res/layout/fragment_event_paid.xml
+++ b/wallet/src/main/res/layout/fragment_transaction_payment.xml
diff --git a/wallet/src/main/res/layout/fragment_event_withdraw.xml b/wallet/src/main/res/layout/fragment_transaction_withdrawal.xml
index 5d30fcf..5d30fcf 100644
--- a/wallet/src/main/res/layout/fragment_event_withdraw.xml
+++ b/wallet/src/main/res/layout/fragment_transaction_withdrawal.xml
diff --git a/wallet/src/main/res/layout/list_item_transaction.xml b/wallet/src/main/res/layout/list_item_transaction.xml
new file mode 100644
index 0000000..058b170
--- /dev/null
+++ b/wallet/src/main/res/layout/list_item_transaction.xml
@@ -0,0 +1,89 @@
+<?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/>
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
+ android:background="@drawable/selectable_background"
+ android:foreground="?attr/selectableItemBackground"
+ android:paddingStart="16dp"
+ android:paddingTop="8dp"
+ android:paddingEnd="16dp"
+ android:paddingBottom="8dp">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:tint="?android:colorControlNormal"
+ tools:ignore="ContentDescription"
+ tools:src="@drawable/ic_cash_usd_outline" />
+
+ <TextView
+ android:id="@+id/title"
+ style="@style/TransactionTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="8dp"
+ app:layout_constraintEnd_toStartOf="@+id/amount"
+ app:layout_constraintStart_toEndOf="@+id/icon"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="@string/transaction_payment" />
+
+ <TextView
+ android:id="@+id/amount"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="24sp"
+ app:layout_constraintBottom_toTopOf="@+id/pendingView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="- 1337.23" />
+
+ <TextView
+ android:id="@+id/time"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="8dp"
+ android:textSize="14sp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/amount"
+ app:layout_constraintStart_toStartOf="@+id/title"
+ app:layout_constraintTop_toBottomOf="@+id/title"
+ tools:text="23 min ago" />
+
+ <TextView
+ android:id="@+id/pendingView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/transaction_pending"
+ android:textSize="14sp"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toEndOf="@+id/time"
+ app:layout_constraintTop_toBottomOf="@+id/amount"
+ tools:visibility="visible" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/wallet/src/main/res/menu/transactions_detail.xml b/wallet/src/main/res/menu/transactions_detail.xml
index 388e3c4..d4568d4 100644
--- a/wallet/src/main/res/menu/transactions_detail.xml
+++ b/wallet/src/main/res/menu/transactions_detail.xml
@@ -16,8 +16,4 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- <item
- android:id="@+id/show_json"
- android:title="@string/transactions_detail_json"
- app:showAsAction="never" />
</menu>
diff --git a/wallet/src/main/res/navigation/nav_graph.xml b/wallet/src/main/res/navigation/nav_graph.xml
index 8e717c1..5523d8b 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -71,7 +71,7 @@
android:id="@+id/nav_transactions_detail"
android:name="net.taler.wallet.transactions.TransactionDetailFragment"
android:label="@string/transactions_detail_title"
- tools:layout="@layout/fragment_event_withdraw" />
+ tools:layout="@layout/fragment_transaction_withdrawal" />
<fragment
android:id="@+id/alreadyPaid"
diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml
index 56ff2ef..44b2dad 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -80,8 +80,10 @@ GNU Taler is immune against many types of fraud, such as phishing of credit card
<string name="transaction_order_refused">Purchase Cancelled</string>
<string name="transaction_tip_accepted">Tip Accepted</string>
<string name="transaction_tip_declined">Tip Declined</string>
- <string name="transaction_refund">Refund</string>
- <string name="transaction_refresh">Obtained change</string>
+ <string name="transaction_tip_from">Tip from %s</string>
+ <string name="transaction_refund">Refund from %s</string>
+ <string name="transaction_pending">PENDING</string>
+ <string name="transaction_refresh">Coin expiry change fee</string>
<string name="transaction_refresh_reason_manual">because of manual request</string>
<string name="transaction_refresh_reason_pay">for payment</string>
<string name="transaction_refresh_reason_refund">for refund</string>