aboutsummaryrefslogtreecommitdiff
path: root/wallet/src/main/java/net/taler
diff options
context:
space:
mode:
authorTorsten Grote <t@grobox.de>2020-04-03 14:04:22 -0300
committerTorsten Grote <t@grobox.de>2020-04-03 14:04:22 -0300
commitbee652834f90fd8abd46b5adcf30adcc587984c2 (patch)
tree75c66b3ff5c3160ec063cf33d16400a69823a483 /wallet/src/main/java/net/taler
parente52ee8f55326de402a7ad421c396eb6c81a79a68 (diff)
downloadtaler-android-bee652834f90fd8abd46b5adcf30adcc587984c2.tar.gz
taler-android-bee652834f90fd8abd46b5adcf30adcc587984c2.tar.bz2
taler-android-bee652834f90fd8abd46b5adcf30adcc587984c2.zip
[wallet] add detail page for withdrawal event in history
Also make history accessible by tapping the balance
Diffstat (limited to 'wallet/src/main/java/net/taler')
-rw-r--r--wallet/src/main/java/net/taler/wallet/BalanceFragment.kt18
-rw-r--r--wallet/src/main/java/net/taler/wallet/Utils.kt21
-rw-r--r--wallet/src/main/java/net/taler/wallet/history/HistoryAdapter.kt94
-rw-r--r--wallet/src/main/java/net/taler/wallet/history/HistoryEventFragment.kt80
-rw-r--r--wallet/src/main/java/net/taler/wallet/history/HistoryFragment.kt33
-rw-r--r--wallet/src/main/java/net/taler/wallet/history/HistoryManager.kt14
-rw-r--r--wallet/src/main/java/net/taler/wallet/history/JsonDialogFragment.kt7
-rw-r--r--wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt5
8 files changed, 198 insertions, 74 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/BalanceFragment.kt b/wallet/src/main/java/net/taler/wallet/BalanceFragment.kt
index d871cfb..3d5364b 100644
--- a/wallet/src/main/java/net/taler/wallet/BalanceFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/BalanceFragment.kt
@@ -31,6 +31,7 @@ import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
+import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
@@ -41,13 +42,17 @@ import com.google.zxing.integration.android.IntentIntegrator.QR_CODE
import kotlinx.android.synthetic.main.fragment_show_balance.*
import net.taler.wallet.BalanceAdapter.BalanceViewHolder
-class BalanceFragment : Fragment() {
+interface BalanceClickListener {
+ fun onBalanceClick()
+}
+
+class BalanceFragment : Fragment(), BalanceClickListener {
private val model: WalletViewModel by activityViewModels()
private val withdrawManager by lazy { model.withdrawManager }
private var reloadBalanceMenuItem: MenuItem? = null
- private val balancesAdapter = BalanceAdapter()
+ private val balancesAdapter = BalanceAdapter(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -141,9 +146,13 @@ class BalanceFragment : Fragment() {
beginDelayedTransition(view as ViewGroup)
}
+ override fun onBalanceClick() {
+ findNavController().navigate(R.id.walletHistory)
+ }
+
}
-class BalanceAdapter : Adapter<BalanceViewHolder>() {
+class BalanceAdapter(private val listener: BalanceClickListener) : Adapter<BalanceViewHolder>() {
private var items = emptyList<BalanceItem>()
@@ -169,13 +178,14 @@ class BalanceAdapter : Adapter<BalanceViewHolder>() {
this.notifyDataSetChanged()
}
- class BalanceViewHolder(private val v: View) : ViewHolder(v) {
+ inner class BalanceViewHolder(private val v: View) : ViewHolder(v) {
private val currencyView: TextView = v.findViewById(R.id.balance_currency)
private val amountView: TextView = v.findViewById(R.id.balance_amount)
private val balanceInboundAmount: TextView = v.findViewById(R.id.balanceInboundAmount)
private val balanceInboundLabel: TextView = v.findViewById(R.id.balanceInboundLabel)
fun bind(item: BalanceItem) {
+ v.setOnClickListener { listener.onBalanceClick() }
currencyView.text = item.available.currency
amountView.text = item.available.amountStr
diff --git a/wallet/src/main/java/net/taler/wallet/Utils.kt b/wallet/src/main/java/net/taler/wallet/Utils.kt
new file mode 100644
index 0000000..ae8712f
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/Utils.kt
@@ -0,0 +1,21 @@
+/*
+ * 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
+
+fun cleanExchange(exchange: String) = exchange.let {
+ if (it.startsWith("https://")) it.substring(8) else it
+}.trimEnd('/')
diff --git a/wallet/src/main/java/net/taler/wallet/history/HistoryAdapter.kt b/wallet/src/main/java/net/taler/wallet/history/HistoryAdapter.kt
index 43b7bd7..881ada5 100644
--- a/wallet/src/main/java/net/taler/wallet/history/HistoryAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/history/HistoryAdapter.kt
@@ -16,23 +16,19 @@
package net.taler.wallet.history
-import android.annotation.SuppressLint
+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.core.net.toUri
import androidx.recyclerview.widget.RecyclerView.Adapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import net.taler.common.Amount
import net.taler.common.toRelativeTime
-import net.taler.wallet.BuildConfig
import net.taler.wallet.R
+import net.taler.wallet.cleanExchange
import net.taler.wallet.history.HistoryAdapter.HistoryEventViewHolder
@@ -68,23 +64,20 @@ internal class HistoryAdapter(
this.notifyDataSetChanged()
}
- internal abstract inner class HistoryEventViewHolder(protected val v: View) : ViewHolder(v) {
+ internal abstract inner class HistoryEventViewHolder(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)
@CallSuper
open fun bind(event: HistoryEvent) {
- if (BuildConfig.DEBUG) { // doesn't produce recycling issues, no need to cover all cases
- v.setOnClickListener { listener.onEventClicked(event) }
- } else {
- v.background = null
- }
+ v.setOnClickListener { listener.onEventClicked(event) }
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(v.context)
+ time.text = event.timestamp.ms.toRelativeTime(context)
}
}
@@ -96,8 +89,8 @@ internal class HistoryAdapter(
override fun bind(event: HistoryEvent) {
super.bind(event)
info.text = when (event) {
- is ExchangeAddedEvent -> event.exchangeBaseUrl
- is ExchangeUpdatedEvent -> event.exchangeBaseUrl
+ is ExchangeAddedEvent -> cleanExchange(event.exchangeBaseUrl)
+ is ExchangeUpdatedEvent -> cleanExchange(event.exchangeBaseUrl)
is ReserveBalanceUpdatedEvent -> event.amountReserveBalance.toString()
is HistoryPaymentSentEvent -> event.orderShortInfo.summary
is HistoryOrderAcceptedEvent -> event.orderShortInfo.summary
@@ -113,8 +106,7 @@ internal class HistoryAdapter(
private val summary: TextView = v.findViewById(R.id.summary)
private val amountWithdrawn: TextView = v.findViewById(R.id.amountWithdrawn)
- private val feeLabel: TextView = v.findViewById(R.id.feeLabel)
- private val fee: TextView = v.findViewById(R.id.fee)
+ private val paintFlags = amountWithdrawn.paintFlags
override fun bind(event: HistoryEvent) {
super.bind(event)
@@ -127,52 +119,31 @@ internal class HistoryAdapter(
}
private fun bind(event: HistoryWithdrawnEvent) {
- title.text = getHostname(event.exchangeBaseUrl)
- summary.setText(event.title)
-
- showAmounts(event.amountWithdrawnEffective, event.amountWithdrawnRaw)
+ summary.text = cleanExchange(event.exchangeBaseUrl)
+ amountWithdrawn.text =
+ context.getString(R.string.amount_positive, event.amountWithdrawnEffective)
+ amountWithdrawn.paintFlags = paintFlags
}
private fun bind(event: HistoryRefundedEvent) {
- title.text = event.orderShortInfo.summary
- summary.setText(event.title)
-
- showAmounts(event.amountRefundedEffective, event.amountRefundedRaw)
+ summary.text = event.orderShortInfo.summary
+ amountWithdrawn.text =
+ context.getString(R.string.amount_positive, event.amountRefundedEffective)
+ amountWithdrawn.paintFlags = paintFlags
}
private fun bind(event: HistoryTipAcceptedEvent) {
- title.setText(event.title)
summary.text = null
- showAmounts(event.tipRaw, event.tipRaw)
+ amountWithdrawn.text = context.getString(R.string.amount_positive, event.tipRaw)
+ amountWithdrawn.paintFlags = paintFlags
}
private fun bind(event: HistoryTipDeclinedEvent) {
- title.setText(event.title)
summary.text = null
- showAmounts(event.tipAmount, event.tipAmount)
+ amountWithdrawn.text = context.getString(R.string.amount_positive, event.tipAmount)
amountWithdrawn.paintFlags = amountWithdrawn.paintFlags or STRIKE_THRU_TEXT_FLAG
}
- private fun showAmounts(effective: Amount, raw: Amount) {
- @SuppressLint("SetTextI18n")
- amountWithdrawn.text = "+$raw"
- val calculatedFee = raw - effective
- if (calculatedFee.isZero()) {
- fee.visibility = GONE
- feeLabel.visibility = GONE
- } else {
- @SuppressLint("SetTextI18n")
- fee.text = "-$calculatedFee"
- fee.visibility = VISIBLE
- feeLabel.visibility = VISIBLE
- }
- amountWithdrawn.paintFlags = fee.paintFlags
- }
-
- private fun getHostname(url: String): String {
- return url.toUri().host!!
- }
-
}
internal inner class HistoryPaymentViewHolder(v: View) : HistoryEventViewHolder(v) {
@@ -182,7 +153,6 @@ internal class HistoryAdapter(
override fun bind(event: HistoryEvent) {
super.bind(event)
- summary.setText(event.title)
when (event) {
is HistoryPaymentSentEvent -> bind(event)
is HistoryPaymentAbortedEvent -> bind(event)
@@ -191,23 +161,29 @@ internal class HistoryAdapter(
}
private fun bind(event: HistoryPaymentSentEvent) {
- title.text = event.orderShortInfo.summary
- @SuppressLint("SetTextI18n")
- amountPaidWithFees.text = "-${event.amountPaidWithFees}"
+ summary.text = event.orderShortInfo.summary
+ amountPaidWithFees.text =
+ context.getString(R.string.amount_negative, event.amountPaidWithFees)
}
private fun bind(event: HistoryPaymentAbortedEvent) {
- title.text = event.orderShortInfo.summary
- @SuppressLint("SetTextI18n")
- amountPaidWithFees.text = "-${event.amountLost}"
+ summary.text = event.orderShortInfo.summary
+ amountPaidWithFees.text = context.getString(R.string.amount_negative, event.amountLost)
}
private fun bind(event: HistoryRefreshedEvent) {
- title.text = ""
+ val res = when (event.refreshReason) {
+ RefreshReason.MANUAL -> R.string.history_event_refresh_reason_manual
+ RefreshReason.PAY -> R.string.history_event_refresh_reason_pay
+ RefreshReason.REFUND -> R.string.history_event_refresh_reason_refund
+ RefreshReason.ABORT_PAY -> R.string.history_event_refresh_reason_abort_pay
+ RefreshReason.RECOUP -> R.string.history_event_refresh_reason_recoup
+ RefreshReason.BACKUP_RESTORED -> R.string.history_event_refresh_reason_backup_restored
+ }
+ summary.text = context.getString(res)
val fee = event.amountRefreshedRaw - event.amountRefreshedEffective
- @SuppressLint("SetTextI18n")
if (fee.isZero()) amountPaidWithFees.text = null
- else amountPaidWithFees.text = "-$fee"
+ else amountPaidWithFees.text = context.getString(R.string.amount_negative, fee)
}
}
diff --git a/wallet/src/main/java/net/taler/wallet/history/HistoryEventFragment.kt b/wallet/src/main/java/net/taler/wallet/history/HistoryEventFragment.kt
new file mode 100644
index 0000000..f0dec75
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/history/HistoryEventFragment.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.history
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import kotlinx.android.synthetic.main.fragment_history_event.*
+import net.taler.common.toAbsoluteTime
+import net.taler.wallet.R
+import net.taler.wallet.WalletViewModel
+import net.taler.wallet.cleanExchange
+
+class HistoryEventFragment : Fragment() {
+
+ private val model: WalletViewModel by activityViewModels()
+ private val historyManager by lazy { model.historyManager }
+ private val event by lazy { requireNotNull(historyManager.selectedEvent) }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (model.devMode.value == true) setHasOptionsMenu(true)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_history_event, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ val event = event as HistoryWithdrawnEvent
+
+ timeView.text = event.timestamp.ms.toAbsoluteTime(requireContext())
+ effectiveAmountLabel.text = getString(R.string.withdraw_total)
+ effectiveAmountView.text = event.amountWithdrawnEffective.toString()
+ chosenAmountLabel.text = getString(R.string.amount_chosen)
+ chosenAmountView.text =
+ getString(R.string.amount_positive, event.amountWithdrawnRaw.toString())
+ val fee = event.amountWithdrawnRaw - event.amountWithdrawnEffective
+ feeView.text = getString(R.string.amount_negative, fee.toString())
+ exchangeView.text = cleanExchange(event.exchangeBaseUrl)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ inflater.inflate(R.menu.history_event, menu)
+ }
+
+ 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)
+ }
+ }
+
+}
diff --git a/wallet/src/main/java/net/taler/wallet/history/HistoryFragment.kt b/wallet/src/main/java/net/taler/wallet/history/HistoryFragment.kt
index 2586ef8..b0f6728 100644
--- a/wallet/src/main/java/net/taler/wallet/history/HistoryFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/history/HistoryFragment.kt
@@ -28,10 +28,14 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
+import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
import kotlinx.android.synthetic.main.fragment_show_history.*
+import net.taler.common.exhaustive
+import net.taler.common.fadeIn
+import net.taler.common.fadeOut
import net.taler.wallet.R
import net.taler.wallet.WalletViewModel
@@ -73,8 +77,7 @@ class HistoryFragment : Fragment(), OnEventClickListener {
historyProgressBar.visibility = if (show) VISIBLE else INVISIBLE
})
historyManager.history.observe(viewLifecycleOwner, Observer { history ->
- historyEmptyState.visibility = if (history.isEmpty()) VISIBLE else INVISIBLE
- historyAdapter.update(history)
+ onHistoryResult(history)
})
// kicks off initial load, needs to be adapted if showAll state is ever saved
@@ -106,9 +109,29 @@ class HistoryFragment : Fragment(), OnEventClickListener {
}
override fun onEventClicked(event: HistoryEvent) {
- if (model.devMode.value != true) return
- JsonDialogFragment.new(event.json.toString(4))
- .show(parentFragmentManager, null)
+ when (event) {
+ is HistoryWithdrawnEvent -> {
+ historyManager.selectedEvent = event
+ findNavController().navigate(R.id.action_walletHistory_to_historyEventFragment)
+ }
+ else -> {
+ if (model.devMode.value != true) return
+ JsonDialogFragment.new(event.json.toString(2))
+ .show(parentFragmentManager, null)
+ }
+ }.exhaustive
+ }
+
+ private fun onHistoryResult(result: HistoryResult) = when (result) {
+ HistoryResult.Error -> {
+ historyList.fadeOut()
+ historyEmptyState.text = getString(R.string.history_error)
+ historyEmptyState.fadeIn()
+ }
+ is HistoryResult.Success -> {
+ historyEmptyState.visibility = if (result.history.isEmpty()) VISIBLE else INVISIBLE
+ historyAdapter.update(result.history)
+ }
}
}
diff --git a/wallet/src/main/java/net/taler/wallet/history/HistoryManager.kt b/wallet/src/main/java/net/taler/wallet/history/HistoryManager.kt
index c350daa..7ce4f5b 100644
--- a/wallet/src/main/java/net/taler/wallet/history/HistoryManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/history/HistoryManager.kt
@@ -29,6 +29,11 @@ import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import net.taler.wallet.backend.WalletBackendApi
+sealed class HistoryResult {
+ object Error : HistoryResult()
+ class Success(val history: History) : HistoryResult()
+}
+
@Suppress("EXPERIMENTAL_API_USAGE")
class HistoryManager(
private val walletBackendApi: WalletBackendApi,
@@ -40,7 +45,9 @@ class HistoryManager(
val showAll = MutableLiveData<Boolean>()
- val history: LiveData<History> = showAll.switchMap { showAll ->
+ var selectedEvent: HistoryEvent? = null
+
+ val history: LiveData<HistoryResult> = showAll.switchMap { showAll ->
loadHistory(showAll)
.onStart { mProgress.postValue(true) }
.onCompletion { mProgress.postValue(false) }
@@ -50,7 +57,7 @@ class HistoryManager(
private fun loadHistory(showAll: Boolean) = callbackFlow {
walletBackendApi.sendRequest("getHistory", null) { isError, result ->
if (isError) {
- // TODO show error message in [WalletHistory] fragment
+ offer(HistoryResult.Error)
close()
return@sendRequest
}
@@ -62,7 +69,8 @@ class HistoryManager(
history.add(event)
}
history.reverse() // show latest first
- offer(if (showAll) history else history.filter { it.showToUser } as History)
+ val filtered = if (showAll) history else history.filter { it.showToUser } as History
+ offer(HistoryResult.Success(filtered))
close()
}
awaitClose()
diff --git a/wallet/src/main/java/net/taler/wallet/history/JsonDialogFragment.kt b/wallet/src/main/java/net/taler/wallet/history/JsonDialogFragment.kt
index f51dba9..5421db3 100644
--- a/wallet/src/main/java/net/taler/wallet/history/JsonDialogFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/history/JsonDialogFragment.kt
@@ -20,6 +20,8 @@ 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
@@ -47,4 +49,9 @@ class JsonDialogFragment : DialogFragment() {
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/withdraw/PromptWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
index ea04e24..5d0fe63 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
@@ -30,6 +30,7 @@ import net.taler.common.fadeIn
import net.taler.common.fadeOut
import net.taler.wallet.R
import net.taler.wallet.WalletViewModel
+import net.taler.wallet.cleanExchange
import net.taler.wallet.withdraw.WithdrawStatus.Loading
import net.taler.wallet.withdraw.WithdrawStatus.TermsOfServiceReviewRequired
import net.taler.wallet.withdraw.WithdrawStatus.Withdrawing
@@ -115,9 +116,7 @@ class PromptWithdrawFragment : Fragment() {
feeView.fadeIn()
exchangeIntroView.fadeIn()
- withdrawExchangeUrl.text = exchange.let {
- if (it.startsWith("https://")) it.substring(8) else it
- }.trimEnd('/')
+ withdrawExchangeUrl.text = cleanExchange(exchange)
withdrawExchangeUrl.fadeIn()
withdrawCard.fadeIn()