summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
authorTorsten Grote <t@grobox.de>2020-03-04 16:14:29 -0300
committerTorsten Grote <t@grobox.de>2020-03-04 16:14:29 -0300
commit1bbc48f7f9a893c13b07a5436a0b2b5f923de398 (patch)
treea84ba1a7fcc59c5a07dba7083e532726a9eea11a /app/src
parent30980bc83be99ea85205f44c815b78164b11f7b9 (diff)
downloadwallet-android-1bbc48f7f9a893c13b07a5436a0b2b5f923de398.tar.gz
wallet-android-1bbc48f7f9a893c13b07a5436a0b2b5f923de398.tar.bz2
wallet-android-1bbc48f7f9a893c13b07a5436a0b2b5f923de398.zip
Move pending operations into their own fragment
They will be visible only in developer mode and otherwise rendered nicely for the user where appropriate.
Diffstat (limited to 'app/src')
-rw-r--r--app/src/main/java/net/taler/wallet/MainActivity.kt1
-rw-r--r--app/src/main/java/net/taler/wallet/ShowBalance.kt212
-rw-r--r--app/src/main/java/net/taler/wallet/WalletViewModel.kt68
-rw-r--r--app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt27
-rw-r--r--app/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt180
-rw-r--r--app/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt60
-rw-r--r--app/src/main/res/layout/fragment_pending_operations.xml34
-rw-r--r--app/src/main/res/layout/fragment_show_balance.xml16
-rw-r--r--app/src/main/res/menu/activity_main_drawer.xml4
-rw-r--r--app/src/main/res/menu/balance.xml5
-rw-r--r--app/src/main/res/menu/pending_operations.xml24
-rw-r--r--app/src/main/res/navigation/nav_graph.xml10
-rw-r--r--app/src/main/res/values/strings.xml2
13 files changed, 385 insertions, 258 deletions
diff --git a/app/src/main/java/net/taler/wallet/MainActivity.kt b/app/src/main/java/net/taler/wallet/MainActivity.kt
index ebc7136..5267056 100644
--- a/app/src/main/java/net/taler/wallet/MainActivity.kt
+++ b/app/src/main/java/net/taler/wallet/MainActivity.kt
@@ -99,6 +99,7 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener,
R.id.nav_home -> nav.navigate(R.id.showBalance)
R.id.nav_settings -> nav.navigate(R.id.settings)
R.id.nav_history -> nav.navigate(R.id.walletHistory)
+ R.id.nav_pending_operations -> nav.navigate(R.id.nav_pending_operations)
}
drawer_layout.closeDrawer(START)
return true
diff --git a/app/src/main/java/net/taler/wallet/ShowBalance.kt b/app/src/main/java/net/taler/wallet/ShowBalance.kt
index 4b52426..fe1a109 100644
--- a/app/src/main/java/net/taler/wallet/ShowBalance.kt
+++ b/app/src/main/java/net/taler/wallet/ShowBalance.kt
@@ -28,7 +28,6 @@ import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.Button
-import android.widget.LinearLayout
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@@ -36,132 +35,17 @@ import androidx.lifecycle.Observer
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import com.google.android.material.snackbar.Snackbar
import com.google.zxing.integration.android.IntentIntegrator
import com.google.zxing.integration.android.IntentIntegrator.QR_CODE_TYPES
-import org.json.JSONObject
-class WalletBalanceAdapter(private var myDataset: WalletBalances) :
- RecyclerView.Adapter<WalletBalanceAdapter.MyViewHolder>() {
-
- init {
- setHasStableIds(false)
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
- val rowView =
- LayoutInflater.from(parent.context).inflate(R.layout.balance_row, parent, false)
- return MyViewHolder(rowView)
- }
-
- override fun getItemCount(): Int {
- return myDataset.byCurrency.size
- }
-
- override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
- val amount = myDataset.byCurrency[position].available
- val amountIncoming = myDataset.byCurrency[position].pendingIncoming
- val currencyView = holder.rowView.findViewById<TextView>(R.id.balance_currency)
- currencyView.text = amount.currency
- val amountView = holder.rowView.findViewById<TextView>(R.id.balance_amount)
- amountView.text = amount.amount
-
- val amountIncomingRow = holder.rowView.findViewById<View>(R.id.balance_row_pending)
-
- val amountIncomingView = holder.rowView.findViewById<TextView>(R.id.balance_pending)
- if (amountIncoming.isZero()) {
- amountIncomingRow.visibility = GONE
- } else {
- amountIncomingRow.visibility = VISIBLE
- @SuppressLint("SetTextI18n")
- amountIncomingView.text = "${amountIncoming.amount} ${amountIncoming.currency}"
- }
- }
-
- fun update(updatedBalances: WalletBalances) {
- this.myDataset = updatedBalances
- this.notifyDataSetChanged()
- }
-
- class MyViewHolder(val rowView: View) : RecyclerView.ViewHolder(rowView)
-}
-
-class PendingOperationsAdapter(private var myDataset: PendingOperations) :
- RecyclerView.Adapter<PendingOperationsAdapter.MyViewHolder>() {
-
- private var listener: PendingOperationClickListener? = null
-
-
- init {
- setHasStableIds(false)
- }
-
- fun setPendingOperationClickListener(listener: PendingOperationClickListener) {
- this.listener = listener
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
- val rowView =
- LayoutInflater.from(parent.context).inflate(R.layout.pending_row, parent, false)
- return MyViewHolder(rowView)
- }
-
- override fun getItemCount(): Int {
- return myDataset.pending.size
- }
-
- override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
- val p = myDataset.pending[position]
- val pendingContainer = holder.rowView.findViewById<LinearLayout>(R.id.pending_container)
- pendingContainer.setOnClickListener {
- this.listener?.onPendingOperationClick(p.type, p.detail)
- }
- when (p.type) {
- "proposal-choice" -> {
- val btn1 = holder.rowView.findViewById<TextView>(R.id.button_pending_action_1)
- btn1.text = btn1.context.getString(R.string.pending_operations_refuse)
- btn1.visibility = VISIBLE
- btn1.setOnClickListener {
- this.listener?.onPendingOperationActionClick(p.type, p.detail)
- }
- }
- else -> {
- val btn1 = holder.rowView.findViewById<TextView>(R.id.button_pending_action_1)
- btn1.text = btn1.context.getString(R.string.pending_operations_no_action)
- btn1.visibility = GONE
- btn1.setOnClickListener {}
- }
- }
- val textView = holder.rowView.findViewById<TextView>(R.id.pending_text)
- val subTextView = holder.rowView.findViewById<TextView>(R.id.pending_subtext)
- subTextView.text = p.detail.toString(1)
- textView.text = p.type
- }
-
- fun update(updatedDataset: PendingOperations) {
- this.myDataset = updatedDataset
- this.notifyDataSetChanged()
- }
-
- class MyViewHolder(val rowView: View) : RecyclerView.ViewHolder(rowView)
-}
-
-interface PendingOperationClickListener {
- fun onPendingOperationClick(type: String, detail: JSONObject)
- fun onPendingOperationActionClick(type: String, detail: JSONObject)
-}
-
-class ShowBalance : Fragment(), PendingOperationClickListener {
+class ShowBalance : Fragment() {
private val model: WalletViewModel by activityViewModels()
private val withdrawManager by lazy { model.withdrawManager }
- private lateinit var pendingOperationsLabel: View
private lateinit var balancesView: RecyclerView
private lateinit var balancesPlaceholderView: TextView
- private lateinit var balancesAdapter: WalletBalanceAdapter
-
- private lateinit var pendingAdapter: PendingOperationsAdapter
+ private lateinit var balancesAdapter: BalanceAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -187,7 +71,7 @@ class ShowBalance : Fragment(), PendingOperationClickListener {
val balances = model.balances.value!!
- balancesAdapter = WalletBalanceAdapter(balances)
+ balancesAdapter = BalanceAdapter(balances)
view.findViewById<RecyclerView>(R.id.list_balances).apply {
val myLayoutManager = LinearLayoutManager(context)
@@ -216,23 +100,6 @@ class ShowBalance : Fragment(), PendingOperationClickListener {
triggerLoading()
})
- pendingAdapter = PendingOperationsAdapter(PendingOperations(listOf()))
- pendingAdapter.setPendingOperationClickListener(this)
-
- this.pendingOperationsLabel = view.findViewById<View>(R.id.pending_operations_label)
-
- view.findViewById<RecyclerView>(R.id.list_pending).apply {
- val myLayoutManager = LinearLayoutManager(context)
- val myItemDecoration = DividerItemDecoration(context, myLayoutManager.orientation)
- layoutManager = myLayoutManager
- adapter = pendingAdapter
- addItemDecoration(myItemDecoration)
- }
-
- model.pendingOperations.observe(viewLifecycleOwner, Observer {
- updatePending(it)
- })
-
return view
}
@@ -244,10 +111,6 @@ class ShowBalance : Fragment(), PendingOperationClickListener {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
- R.id.retry_pending -> {
- model.retryPendingNow()
- true
- }
R.id.reload_balance -> {
triggerLoading()
model.balances.value = WalletBalances(false, listOf())
@@ -285,39 +148,50 @@ class ShowBalance : Fragment(), PendingOperationClickListener {
balancesAdapter.update(balances)
}
- private fun updatePending(pendingOperations: PendingOperations) {
- if (pendingOperations.pending.isEmpty()) {
- pendingOperationsLabel.visibility = GONE
- } else {
- pendingOperationsLabel.visibility = VISIBLE
- }
- pendingAdapter.update(pendingOperations)
+}
+
+class BalanceAdapter(private var myDataset: WalletBalances) :
+ RecyclerView.Adapter<BalanceAdapter.BalanceViewHolder>() {
+
+ init {
+ setHasStableIds(false)
}
- override fun onPendingOperationClick(type: String, detail: JSONObject) {
- val v = view ?: return
- when {
- else -> {
- val bar = Snackbar.make(
- v,
- "No detail view for $type implemented yet.",
- Snackbar.LENGTH_SHORT
- )
- bar.show()
- }
- }
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BalanceViewHolder {
+ val rowView =
+ LayoutInflater.from(parent.context).inflate(R.layout.balance_row, parent, false)
+ return BalanceViewHolder(rowView)
}
- override fun onPendingOperationActionClick(type: String, detail: JSONObject) {
- when (type) {
- "proposal-choice" -> {
- Log.v(TAG, "got action click on proposal-choice")
- val proposalId = detail.optString("proposalId", "")
- if (proposalId == "") {
- return
- }
- model.paymentManager.abortProposal(proposalId)
- }
+ override fun getItemCount(): Int {
+ return myDataset.byCurrency.size
+ }
+
+ override fun onBindViewHolder(holder: BalanceViewHolder, position: Int) {
+ val amount = myDataset.byCurrency[position].available
+ val amountIncoming = myDataset.byCurrency[position].pendingIncoming
+ val currencyView = holder.rowView.findViewById<TextView>(R.id.balance_currency)
+ currencyView.text = amount.currency
+ val amountView = holder.rowView.findViewById<TextView>(R.id.balance_amount)
+ amountView.text = amount.amount
+
+ val amountIncomingRow = holder.rowView.findViewById<View>(R.id.balance_row_pending)
+
+ val amountIncomingView = holder.rowView.findViewById<TextView>(R.id.balance_pending)
+ if (amountIncoming.isZero()) {
+ amountIncomingRow.visibility = GONE
+ } else {
+ amountIncomingRow.visibility = VISIBLE
+ @SuppressLint("SetTextI18n")
+ amountIncomingView.text = "${amountIncoming.amount} ${amountIncoming.currency}"
}
}
+
+ fun update(updatedBalances: WalletBalances) {
+ this.myDataset = updatedBalances
+ this.notifyDataSetChanged()
+ }
+
+ class BalanceViewHolder(val rowView: View) : RecyclerView.ViewHolder(rowView)
+
}
diff --git a/app/src/main/java/net/taler/wallet/WalletViewModel.kt b/app/src/main/java/net/taler/wallet/WalletViewModel.kt
index d9e730d..2ec88af 100644
--- a/app/src/main/java/net/taler/wallet/WalletViewModel.kt
+++ b/app/src/main/java/net/taler/wallet/WalletViewModel.kt
@@ -37,6 +37,7 @@ import net.taler.wallet.backend.WalletBackendApi
import net.taler.wallet.history.History
import net.taler.wallet.history.HistoryEvent
import net.taler.wallet.payment.PaymentManager
+import net.taler.wallet.pending.PendingOperationsManager
import net.taler.wallet.withdraw.WithdrawManager
import org.json.JSONObject
@@ -48,15 +49,6 @@ data class BalanceEntry(val available: Amount, val pendingIncoming: Amount)
data class WalletBalances(val initialized: Boolean, val byCurrency: List<BalanceEntry>)
-open class PendingOperationInfo(
- val type: String,
- val detail: JSONObject
-)
-
-open class PendingOperations(
- val pending: List<PendingOperationInfo>
-)
-
@Suppress("EXPERIMENTAL_API_USAGE")
class WalletViewModel(val app: Application) : AndroidViewModel(app) {
@@ -65,10 +57,6 @@ class WalletViewModel(val app: Application) : AndroidViewModel(app) {
value = WalletBalances(false, listOf())
}
- val pendingOperations = MutableLiveData<PendingOperations>().apply {
- value = PendingOperations(listOf())
- }
-
private val mHistoryProgress = MutableLiveData<Boolean>()
val historyProgress: LiveData<Boolean> = mHistoryProgress
@@ -84,9 +72,16 @@ class WalletViewModel(val app: Application) : AndroidViewModel(app) {
val showProgressBar = MutableLiveData<Boolean>()
private var activeGetBalance = 0
- private var activeGetPending = 0
- private val walletBackendApi = WalletBackendApi(app)
+ private val walletBackendApi = WalletBackendApi(app, {
+ activeGetBalance = 0
+ getBalances()
+ pendingOperationsManager.getPending()
+ }) {
+ Log.i(TAG, "Received notification from wallet-core")
+ getBalances()
+ pendingOperationsManager.getPending()
+ }
private val mapper = ObjectMapper()
.registerModule(KotlinModule())
@@ -94,23 +89,8 @@ class WalletViewModel(val app: Application) : AndroidViewModel(app) {
val withdrawManager = WithdrawManager(walletBackendApi)
val paymentManager = PaymentManager(walletBackendApi, mapper)
-
- init {
- getBalances()
- getPending()
-
- walletBackendApi.notificationHandler = {
- Log.i(TAG, "got notification from wallet")
- getBalances()
- getPending()
- }
- walletBackendApi.connectedHandler = {
- activeGetBalance = 0
- activeGetPending = 0
- getBalances()
- getPending()
- }
- }
+ val pendingOperationsManager: PendingOperationsManager =
+ PendingOperationsManager(walletBackendApi)
fun getBalances() {
if (activeGetBalance > 0) {
@@ -138,30 +118,6 @@ class WalletViewModel(val app: Application) : AndroidViewModel(app) {
}
}
- private fun getPending() {
- if (activeGetPending > 0) {
- return
- }
- activeGetPending++
- walletBackendApi.sendRequest("getPendingOperations", null) { isError, result ->
- activeGetPending--
- if (isError) {
- Log.i(TAG, "got getPending error result")
- return@sendRequest
- }
- Log.i(TAG, "got getPending result")
- val pendingList = mutableListOf<PendingOperationInfo>()
- val pendingJson = result.getJSONArray("pendingOperations")
- for (i in 0 until pendingJson.length()) {
- val p = pendingJson.getJSONObject(i)
- val type = p.getString("type")
- pendingList.add(PendingOperationInfo(type, p))
- }
- Log.i(TAG, "Got ${pendingList.size} pending operations")
- pendingOperations.postValue(PendingOperations((pendingList)))
- }
- }
-
private fun loadHistory(showAll: Boolean) = callbackFlow {
mHistoryProgress.postValue(true)
walletBackendApi.sendRequest("getHistory", null) { isError, result ->
diff --git a/app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt b/app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
index 8f37ff3..d447287 100644
--- a/app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
+++ b/app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
@@ -22,21 +22,26 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
-import android.os.*
+import android.os.Handler
+import android.os.IBinder
+import android.os.Message
+import android.os.Messenger
import android.util.Log
import android.util.SparseArray
import org.json.JSONObject
import java.lang.ref.WeakReference
import java.util.*
-class WalletBackendApi(private val app: Application) {
+class WalletBackendApi(
+ private val app: Application,
+ private val onConnected: (() -> Unit),
+ private val notificationHandler: (() -> Unit)
+) {
private var walletBackendMessenger: Messenger? = null
private val queuedMessages = LinkedList<Message>()
private val handlers = SparseArray<(isError: Boolean, message: JSONObject) -> Unit>()
private var nextRequestID = 1
- var notificationHandler: (() -> Unit)? = null
- var connectedHandler: (() -> Unit)? = null
private val walletBackendConn = object : ServiceConnection {
override fun onServiceDisconnected(p0: ComponentName?) {
@@ -52,15 +57,12 @@ class WalletBackendApi(private val app: Application) {
val msg = Message.obtain(null, WalletBackendService.MSG_SUBSCRIBE_NOTIFY)
msg.replyTo = incomingMessenger
bm.send(msg)
- val ch = connectedHandler
- if (ch != null) {
- ch()
- }
+ onConnected.invoke()
}
}
private class IncomingHandler(strongApi: WalletBackendApi) : Handler() {
- private val weakApi = WeakReference<WalletBackendApi>(strongApi)
+ private val weakApi = WeakReference(strongApi)
override fun handleMessage(msg: Message) {
val api = weakApi.get() ?: return
when (msg.what) {
@@ -83,10 +85,7 @@ class WalletBackendApi(private val app: Application) {
h(isError, json)
}
WalletBackendService.MSG_NOTIFY -> {
- val nh = api.notificationHandler
- if (nh != null) {
- nh()
- }
+ api.notificationHandler.invoke()
}
}
}
@@ -139,4 +138,4 @@ class WalletBackendApi(private val app: Application) {
companion object {
const val TAG = "WalletBackendApi"
}
-} \ No newline at end of file
+}
diff --git a/app/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt b/app/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt
new file mode 100644
index 0000000..7595827
--- /dev/null
+++ b/app/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt
@@ -0,0 +1,180 @@
+/*
+ * 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.pending
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.snackbar.Snackbar
+import com.google.android.material.snackbar.Snackbar.LENGTH_SHORT
+import kotlinx.android.synthetic.main.fragment_pending_operations.*
+import net.taler.wallet.R
+import net.taler.wallet.TAG
+import net.taler.wallet.WalletViewModel
+import org.json.JSONObject
+
+interface PendingOperationClickListener {
+ fun onPendingOperationClick(type: String, detail: JSONObject)
+ fun onPendingOperationActionClick(type: String, detail: JSONObject)
+}
+
+class PendingOperationsFragment : Fragment(), PendingOperationClickListener {
+
+ private val model: WalletViewModel by activityViewModels()
+ private val pendingOperationsManager by lazy { model.pendingOperationsManager }
+
+ private val pendingAdapter = PendingOperationsAdapter(emptyList(), this)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setHasOptionsMenu(true)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_pending_operations, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ list_pending.apply {
+ val myLayoutManager = LinearLayoutManager(requireContext())
+ val myItemDecoration =
+ DividerItemDecoration(requireContext(), myLayoutManager.orientation)
+ layoutManager = myLayoutManager
+ adapter = pendingAdapter
+ addItemDecoration(myItemDecoration)
+ }
+
+ pendingOperationsManager.pendingOperations.observe(viewLifecycleOwner, Observer {
+ updatePending(it)
+ })
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return when (item.itemId) {
+ R.id.retry_pending -> {
+ model.retryPendingNow()
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ inflater.inflate(R.menu.pending_operations, menu)
+ super.onCreateOptionsMenu(menu, inflater)
+ }
+
+ private fun updatePending(pendingOperations: List<PendingOperationInfo>) {
+ pendingAdapter.update(pendingOperations)
+ }
+
+ override fun onPendingOperationClick(type: String, detail: JSONObject) {
+ Snackbar.make(view!!, "No detail view for $type implemented yet.", LENGTH_SHORT).show()
+ }
+
+ override fun onPendingOperationActionClick(type: String, detail: JSONObject) {
+ when (type) {
+ "proposal-choice" -> {
+ Log.v(TAG, "got action click on proposal-choice")
+ val proposalId = detail.optString("proposalId", "")
+ if (proposalId == "") {
+ return
+ }
+ model.paymentManager.abortProposal(proposalId)
+ }
+ }
+ }
+
+}
+
+class PendingOperationsAdapter(
+ private var items: List<PendingOperationInfo>,
+ private val listener: PendingOperationClickListener
+) :
+ RecyclerView.Adapter<PendingOperationsAdapter.MyViewHolder>() {
+
+ init {
+ setHasStableIds(false)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
+ val rowView =
+ LayoutInflater.from(parent.context).inflate(R.layout.pending_row, parent, false)
+ return MyViewHolder(rowView)
+ }
+
+ override fun getItemCount(): Int {
+ return items.size
+ }
+
+ override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
+ val p = items[position]
+ val pendingContainer = holder.rowView.findViewById<LinearLayout>(R.id.pending_container)
+ pendingContainer.setOnClickListener {
+ listener.onPendingOperationClick(p.type, p.detail)
+ }
+ when (p.type) {
+ "proposal-choice" -> {
+ val btn1 = holder.rowView.findViewById<TextView>(R.id.button_pending_action_1)
+ btn1.text = btn1.context.getString(R.string.pending_operations_refuse)
+ btn1.visibility = VISIBLE
+ btn1.setOnClickListener {
+ listener.onPendingOperationActionClick(p.type, p.detail)
+ }
+ }
+ else -> {
+ val btn1 = holder.rowView.findViewById<TextView>(R.id.button_pending_action_1)
+ btn1.text = btn1.context.getString(R.string.pending_operations_no_action)
+ btn1.visibility = GONE
+ btn1.setOnClickListener {}
+ }
+ }
+ val textView = holder.rowView.findViewById<TextView>(R.id.pending_text)
+ val subTextView = holder.rowView.findViewById<TextView>(R.id.pending_subtext)
+ subTextView.text = p.detail.toString(1)
+ textView.text = p.type
+ }
+
+ fun update(items: List<PendingOperationInfo>) {
+ this.items = items
+ this.notifyDataSetChanged()
+ }
+
+ class MyViewHolder(val rowView: View) : RecyclerView.ViewHolder(rowView)
+
+}
diff --git a/app/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt b/app/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt
new file mode 100644
index 0000000..b6d5904
--- /dev/null
+++ b/app/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.pending
+
+import android.util.Log
+import androidx.lifecycle.MutableLiveData
+import net.taler.wallet.TAG
+import net.taler.wallet.backend.WalletBackendApi
+import org.json.JSONObject
+
+open class PendingOperationInfo(
+ val type: String,
+ val detail: JSONObject
+)
+
+class PendingOperationsManager(private val walletBackendApi: WalletBackendApi) {
+
+ private var activeGetPending = 0
+
+ val pendingOperations = MutableLiveData<List<PendingOperationInfo>>()
+
+ internal fun getPending() {
+ if (activeGetPending > 0) {
+ return
+ }
+ activeGetPending++
+ walletBackendApi.sendRequest("getPendingOperations", null) { isError, result ->
+ activeGetPending--
+ if (isError) {
+ Log.i(TAG, "got getPending error result")
+ return@sendRequest
+ }
+ Log.i(TAG, "got getPending result")
+ val pendingList = mutableListOf<PendingOperationInfo>()
+ val pendingJson = result.getJSONArray("pendingOperations")
+ for (i in 0 until pendingJson.length()) {
+ val p = pendingJson.getJSONObject(i)
+ val type = p.getString("type")
+ pendingList.add(PendingOperationInfo(type, p))
+ }
+ Log.i(TAG, "Got ${pendingList.size} pending operations")
+ pendingOperations.postValue((pendingList))
+ }
+ }
+
+}
diff --git a/app/src/main/res/layout/fragment_pending_operations.xml b/app/src/main/res/layout/fragment_pending_operations.xml
new file mode 100644
index 0000000..26c1be1
--- /dev/null
+++ b/app/src/main/res/layout/fragment_pending_operations.xml
@@ -0,0 +1,34 @@
+<?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">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/list_pending"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:scrollbars="vertical"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:listitem="@layout/pending_row" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/fragment_show_balance.xml b/app/src/main/res/layout/fragment_show_balance.xml
index af003eb..db50754 100644
--- a/app/src/main/res/layout/fragment_show_balance.xml
+++ b/app/src/main/res/layout/fragment_show_balance.xml
@@ -34,7 +34,8 @@
android:id="@+id/list_balances"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:scrollbars="vertical" />
+ android:scrollbars="vertical"
+ tools:listitem="@layout/balance_row" />
<TextView
android:id="@+id/list_balances_placeholder"
@@ -60,17 +61,6 @@
android:layout_height="wrap_content"
android:text="@string/button_scan_qr_code" />
- <TextView
- android:id="@+id/pending_operations_label"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/pending_operations_label" />
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/list_pending"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scrollbars="vertical" />
-
</LinearLayout>
+
</androidx.core.widget.NestedScrollView>
diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml
index f06f0ab..7a54077 100644
--- a/app/src/main/res/menu/activity_main_drawer.xml
+++ b/app/src/main/res/menu/activity_main_drawer.xml
@@ -31,6 +31,10 @@
android:id="@+id/nav_settings"
android:icon="@drawable/ic_menu_manage"
android:title="@string/menu_settings" />
+ <item
+ android:id="@+id/nav_pending_operations"
+ android:icon="@drawable/history_refresh"
+ android:title="Pending Operations" />
</group>
</menu>
diff --git a/app/src/main/res/menu/balance.xml b/app/src/main/res/menu/balance.xml
index 15a6016..69b5def 100644
--- a/app/src/main/res/menu/balance.xml
+++ b/app/src/main/res/menu/balance.xml
@@ -21,9 +21,4 @@
android:orderInCategory="100"
android:title="@string/menu_balance_reload"
app:showAsAction="never" />
- <item
- android:id="@+id/retry_pending"
- android:orderInCategory="100"
- android:title="@string/menu_retry_pending_operations"
- app:showAsAction="never" />
</menu>
diff --git a/app/src/main/res/menu/pending_operations.xml b/app/src/main/res/menu/pending_operations.xml
new file mode 100644
index 0000000..980ea66
--- /dev/null
+++ b/app/src/main/res/menu/pending_operations.xml
@@ -0,0 +1,24 @@
+<?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/retry_pending"
+ android:orderInCategory="100"
+ android:title="@string/menu_retry_pending_operations"
+ app:showAsAction="never" />
+</menu>
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
index 2cc1eaa..3b875e7 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -99,8 +99,18 @@
app:popUpTo="@id/showBalance" />
</fragment>
+ <fragment
+ android:id="@+id/nav_pending_operations"
+ android:name="net.taler.wallet.pending.PendingOperationsFragment"
+ android:label="Pending Operations"
+ tools:layout="@layout/fragment_pending_operations" />
+
<action
android:id="@+id/action_global_promptPayment"
app:destination="@id/promptPayment" />
+ <action
+ android:id="@+id/action_global_pending_operations"
+ app:destination="@id/nav_pending_operations" />
+
</navigation> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 19159b9..0b69c3c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -71,7 +71,7 @@
<string name="payment_already_paid">You\'ve already paid for this order.</string>
<string name="withdraw_accepted">Withdrawal accepted</string>
- <string name="withdraw_success_info">Your bank will now ask you to approve a transfer to the selected change. After you\'ve confirmed the transfer with your bank, the digital cash will show in this wallet.</string>
+ <string name="withdraw_success_info">The wire transfer now needs to be confirmed with the bank. Once the wire transfer is complete, the digital cash will automatically show in this wallet.</string>
<string name="withdraw_do_you_want">Do you want to withdraw</string>
<string name="withdraw_fees">(minus exchange fees not shown in this prototype)</string>
<string name="withdraw_exchange">Using the exchange provider</string>