diff options
author | Torsten Grote <t@grobox.de> | 2020-03-04 16:14:29 -0300 |
---|---|---|
committer | Torsten Grote <t@grobox.de> | 2020-03-04 16:14:29 -0300 |
commit | 1bbc48f7f9a893c13b07a5436a0b2b5f923de398 (patch) | |
tree | a84ba1a7fcc59c5a07dba7083e532726a9eea11a /app/src | |
parent | 30980bc83be99ea85205f44c815b78164b11f7b9 (diff) | |
download | wallet-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.kt | 1 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/ShowBalance.kt | 212 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/WalletViewModel.kt | 68 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt | 27 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/pending/PendingOperationsFragment.kt | 180 | ||||
-rw-r--r-- | app/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt | 60 | ||||
-rw-r--r-- | app/src/main/res/layout/fragment_pending_operations.xml | 34 | ||||
-rw-r--r-- | app/src/main/res/layout/fragment_show_balance.xml | 16 | ||||
-rw-r--r-- | app/src/main/res/menu/activity_main_drawer.xml | 4 | ||||
-rw-r--r-- | app/src/main/res/menu/balance.xml | 5 | ||||
-rw-r--r-- | app/src/main/res/menu/pending_operations.xml | 24 | ||||
-rw-r--r-- | app/src/main/res/navigation/nav_graph.xml | 10 | ||||
-rw-r--r-- | app/src/main/res/values/strings.xml | 2 |
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> |