aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--taler-kotlin-common/src/main/java/net/taler/common/AndroidUtils.kt6
-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
-rw-r--r--wallet/src/main/res/layout/fragment_history_event.xml160
-rw-r--r--wallet/src/main/res/layout/history_payment.xml24
-rw-r--r--wallet/src/main/res/layout/history_receive.xml43
-rw-r--r--wallet/src/main/res/layout/history_row.xml11
-rw-r--r--wallet/src/main/res/layout/list_item_balance.xml1
-rw-r--r--wallet/src/main/res/menu/history_event.xml23
-rw-r--r--wallet/src/main/res/navigation/nav_graph.xml14
-rw-r--r--wallet/src/main/res/values/strings.xml10
-rw-r--r--wallet/src/main/res/values/styles.xml2
18 files changed, 446 insertions, 120 deletions
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/AndroidUtils.kt b/taler-kotlin-common/src/main/java/net/taler/common/AndroidUtils.kt
index 5bc5721..ad9dab9 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/AndroidUtils.kt
+++ b/taler-kotlin-common/src/main/java/net/taler/common/AndroidUtils.kt
@@ -27,6 +27,7 @@ import android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE
import android.text.format.DateUtils.FORMAT_NO_YEAR
import android.text.format.DateUtils.FORMAT_SHOW_DATE
import android.text.format.DateUtils.FORMAT_SHOW_TIME
+import android.text.format.DateUtils.FORMAT_SHOW_YEAR
import android.text.format.DateUtils.MINUTE_IN_MILLIS
import android.text.format.DateUtils.formatDateTime
import android.text.format.DateUtils.getRelativeTimeSpanString
@@ -82,3 +83,8 @@ fun Long.toRelativeTime(context: Context): CharSequence {
formatDateTime(context, this, flags)
} else getRelativeTimeSpanString(this, now, MINUTE_IN_MILLIS, FORMAT_ABBREV_RELATIVE)
}
+
+fun Long.toAbsoluteTime(context: Context): CharSequence {
+ val flags = FORMAT_SHOW_TIME or FORMAT_SHOW_DATE or FORMAT_SHOW_YEAR
+ return formatDateTime(context, this, flags)
+}
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()
diff --git a/wallet/src/main/res/layout/fragment_history_event.xml b/wallet/src/main/res/layout/fragment_history_event.xml
new file mode 100644
index 0000000..4224093
--- /dev/null
+++ b/wallet/src/main/res/layout/fragment_history_event.xml
@@ -0,0 +1,160 @@
+<?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="match_parent"
+ tools:context=".history.HistoryEventFragment">
+
+ <TextView
+ android:id="@+id/timeView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:gravity="center"
+ android:textAppearance="@style/TextAppearance.AppCompat.Medium"
+ app:layout_constraintBottom_toTopOf="@+id/effectiveAmountLabel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_chainStyle="packed"
+ tools:text="23 March 2020 23:42pm" />
+
+ <TextView
+ android:id="@+id/effectiveAmountLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="16dp"
+ android:gravity="center"
+ app:layout_constraintBottom_toTopOf="@+id/effectiveAmountView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/timeView"
+ tools:text="@string/withdraw_total" />
+
+ <TextView
+ android:id="@+id/effectiveAmountView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginBottom="16dp"
+ android:gravity="center"
+ android:textColor="@color/green"
+ android:textSize="24sp"
+ app:layout_constraintBottom_toTopOf="@+id/chosenAmountLabel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/effectiveAmountLabel"
+ tools:text="23.42 TESTKUDOS" />
+
+ <TextView
+ android:id="@+id/chosenAmountLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="16dp"
+ android:gravity="center"
+ app:layout_constraintBottom_toTopOf="@+id/chosenAmountView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/effectiveAmountView"
+ tools:text="@string/amount_chosen" />
+
+ <TextView
+ android:id="@+id/chosenAmountView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginBottom="16dp"
+ android:gravity="center"
+ android:textSize="24sp"
+ app:layout_constraintBottom_toTopOf="@+id/feeLabel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/chosenAmountLabel"
+ tools:text="24 TESTKUDOS" />
+
+ <TextView
+ android:id="@+id/feeLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="16dp"
+ android:gravity="center"
+ android:text="@string/withdraw_fees"
+ app:layout_constraintBottom_toTopOf="@+id/feeView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/chosenAmountView" />
+
+ <TextView
+ android:id="@+id/feeView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginBottom="16dp"
+ android:gravity="center"
+ android:textColor="@color/red"
+ android:textSize="24sp"
+ app:layout_constraintBottom_toTopOf="@+id/exchangeLabel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/feeLabel"
+ tools:text="-0.38 TESTKUDOS" />
+
+ <TextView
+ android:id="@+id/exchangeLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="16dp"
+ android:gravity="center"
+ android:text="@string/withdraw_exchange"
+ app:layout_constraintBottom_toTopOf="@+id/exchangeView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/feeView" />
+
+ <TextView
+ android:id="@+id/exchangeView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="16dp"
+ android:gravity="center"
+ android:textSize="24sp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/exchangeLabel"
+ tools:text="exchange.demo.taler.net" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/wallet/src/main/res/layout/history_payment.xml b/wallet/src/main/res/layout/history_payment.xml
index 3839038..33cb676 100644
--- a/wallet/src/main/res/layout/history_payment.xml
+++ b/wallet/src/main/res/layout/history_payment.xml
@@ -19,11 +19,11 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_marginTop="8dp"
- android:layout_marginEnd="16dp"
- android:layout_marginBottom="8dp"
- android:background="?attr/selectableItemBackground">
+ android:background="?attr/selectableItemBackground"
+ android:paddingStart="16dp"
+ android:paddingTop="8dp"
+ android:paddingEnd="16dp"
+ android:paddingBottom="8dp">
<ImageView
android:id="@+id/icon"
@@ -32,36 +32,36 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
- app:srcCompat="@drawable/history_withdrawn"
app:tint="?android:colorControlNormal"
- tools:ignore="ContentDescription" />
+ tools:ignore="ContentDescription"
+ tools:src="@drawable/ic_cash_usd_outline" />
<TextView
android:id="@+id/title"
style="@style/HistoryTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
+ android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toStartOf="@+id/amountPaidWithFees"
app:layout_constraintStart_toEndOf="@+id/icon"
app:layout_constraintTop_toTopOf="parent"
- tools:text="Lots of books with very long titles" />
+ tools:text="@string/history_event_payment_sent" />
<TextView
android:id="@+id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
+ android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/amountPaidWithFees"
+ app:layout_constraintEnd_toStartOf="@+id/time"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/icon"
app:layout_constraintTop_toBottomOf="@+id/title"
app:layout_constraintVertical_bias="0.0"
- tools:text="@string/history_event_payment_sent" />
+ tools:text="Lots of books with very long titles" />
<TextView
android:id="@+id/amountPaidWithFees"
diff --git a/wallet/src/main/res/layout/history_receive.xml b/wallet/src/main/res/layout/history_receive.xml
index def97a2..5f386a2 100644
--- a/wallet/src/main/res/layout/history_receive.xml
+++ b/wallet/src/main/res/layout/history_receive.xml
@@ -19,11 +19,11 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_marginTop="8dp"
- android:layout_marginEnd="16dp"
- android:layout_marginBottom="8dp"
- android:background="?attr/selectableItemBackground">
+ android:background="?attr/selectableItemBackground"
+ android:paddingStart="16dp"
+ android:paddingTop="8dp"
+ android:paddingEnd="16dp"
+ android:paddingBottom="8dp">
<ImageView
android:id="@+id/icon"
@@ -41,7 +41,7 @@
style="@style/HistoryTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
+ android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
android:text="@string/history_event_withdrawn"
app:layout_constraintEnd_toStartOf="@+id/amountWithdrawn"
@@ -52,34 +52,18 @@
android:id="@+id/summary"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
+ android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/feeLabel"
+ app:layout_constraintEnd_toStartOf="@+id/time"
+ app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/icon"
app:layout_constraintTop_toBottomOf="@+id/title"
- tools:text="http://taler.quite-long-exchange.url" />
-
- <TextView
- android:id="@+id/feeLabel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="2dp"
- android:text="@string/history_fee_label"
- app:layout_constraintEnd_toStartOf="@+id/fee"
- app:layout_constraintTop_toTopOf="@+id/fee" />
-
- <TextView
- android:id="@+id/fee"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/red"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/amountWithdrawn"
- tools:text="0.2 TESTKUDOS" />
+ app:layout_constraintVertical_bias="0.0"
+ tools:text="exchange.taler.quite-long-domain-name.org" />
<TextView
android:id="@+id/amountWithdrawn"
@@ -96,10 +80,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/fee"
+ app:layout_constraintStart_toEndOf="@+id/summary"
+ app:layout_constraintTop_toBottomOf="@+id/amountWithdrawn"
+ app:layout_constraintVertical_bias="1.0"
tools:text="23 min. ago" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/wallet/src/main/res/layout/history_row.xml b/wallet/src/main/res/layout/history_row.xml
index 2982008..5eac44b 100644
--- a/wallet/src/main/res/layout/history_row.xml
+++ b/wallet/src/main/res/layout/history_row.xml
@@ -19,8 +19,11 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="15dp"
- android:background="?attr/selectableItemBackground">
+ android:background="?attr/selectableItemBackground"
+ android:paddingStart="16dp"
+ android:paddingTop="8dp"
+ android:paddingEnd="16dp"
+ android:paddingBottom="8dp">
<ImageView
android:id="@+id/icon"
@@ -38,7 +41,7 @@
style="@style/HistoryTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
+ android:layout_marginStart="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/icon"
app:layout_constraintTop_toTopOf="parent"
@@ -49,7 +52,7 @@
android:id="@+id/info"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
+ android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/wallet/src/main/res/layout/list_item_balance.xml b/wallet/src/main/res/layout/list_item_balance.xml
index dc24232..a9e15df 100644
--- a/wallet/src/main/res/layout/list_item_balance.xml
+++ b/wallet/src/main/res/layout/list_item_balance.xml
@@ -19,6 +19,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
android:padding="16dp">
<TextView
diff --git a/wallet/src/main/res/menu/history_event.xml b/wallet/src/main/res/menu/history_event.xml
new file mode 100644
index 0000000..45a1e0e
--- /dev/null
+++ b/wallet/src/main/res/menu/history_event.xml
@@ -0,0 +1,23 @@
+<?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/>
+ -->
+
+<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/history_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 9875b8a..1ab9666 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -57,11 +57,23 @@
android:name="net.taler.wallet.Settings"
android:label="Settings"
tools:layout="@layout/fragment_settings" />
+
<fragment
android:id="@+id/walletHistory"
android:name="net.taler.wallet.history.HistoryFragment"
android:label="@string/history_title"
- tools:layout="@layout/fragment_show_history" />
+ tools:layout="@layout/fragment_show_history">
+ <action
+ android:id="@+id/action_walletHistory_to_historyEventFragment"
+ app:destination="@id/historyEventFragment" />
+ </fragment>
+
+ <fragment
+ android:id="@+id/historyEventFragment"
+ android:name="net.taler.wallet.history.HistoryEventFragment"
+ android:label="@string/history_detail_title"
+ tools:layout="@layout/fragment_history_event" />
+
<fragment
android:id="@+id/alreadyPaid"
android:name="net.taler.wallet.payment.AlreadyPaidFragment"
diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml
index bcd173f..1f028c2 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -41,6 +41,7 @@
<string name="balances_title">Balances</string>
<string name="amount_positive">+%s</string>
<string name="amount_negative">-%s</string>
+ <string name="amount_chosen">Chosen Amount</string>
<string name="balances_inbound_label">inbound</string>
<string name="balances_empty_state">There is no digital cash in your wallet.\n\nYou can get test money from the demo bank:\n\nhttps://bank.demo.taler.net</string>
@@ -49,6 +50,9 @@
<string name="history_show_all">Show All</string>
<string name="history_reload">Reload History</string>
<string name="history_empty">The wallet history is empty</string>
+ <string name="history_error">Could not load history</string>
+ <string name="history_detail_title">Transaction</string>
+ <string name="history_detail_json">Show JSON</string>
<!-- HistoryEvents -->
<string name="history_event_exchange_added">Exchange Added</string>
@@ -64,6 +68,12 @@
<string name="history_event_order_redirected">Purchase Redirected</string>
<string name="history_event_refund">Refund</string>
<string name="history_event_refreshed">Obtained change</string>
+ <string name="history_event_refresh_reason_manual">because of manual request</string>
+ <string name="history_event_refresh_reason_pay">for payment</string>
+ <string name="history_event_refresh_reason_refund">for refund</string>
+ <string name="history_event_refresh_reason_abort_pay">to abort payment</string>
+ <string name="history_event_refresh_reason_recoup">to recoup funds</string>
+ <string name="history_event_refresh_reason_backup_restored">because of restoring from backup</string>
<string name="history_event_unknown">Unknown Event</string>
<string name="payment_fee">+%s payment fee</string>
diff --git a/wallet/src/main/res/values/styles.xml b/wallet/src/main/res/values/styles.xml
index 83f3e3a..c3e18a6 100644
--- a/wallet/src/main/res/values/styles.xml
+++ b/wallet/src/main/res/values/styles.xml
@@ -34,7 +34,7 @@
<style name="AppTheme.Toolbar" parent="Widget.MaterialComponents.Toolbar.Primary" />
<style name="HistoryTitle">
- <item name="android:textSize">17sp</item>
+ <item name="android:textSize">16sp</item>
<item name="android:textColor">?android:textColorPrimary</item>
</style>