gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-android] 01/03: [wallet] Refactor balances into BalanceMana


From: gnunet
Subject: [taler-taler-android] 01/03: [wallet] Refactor balances into BalanceManager
Date: Fri, 09 Feb 2024 18:49:57 +0100

This is an automated email from the git hooks/post-receive script.

torsten-grote pushed a commit to branch master
in repository taler-android.

commit 512e79eaf07eadd24914eb4a41b52c824866c528
Author: Iván Ávalos <avalos@disroot.org>
AuthorDate: Mon Jan 15 17:50:24 2024 -0600

    [wallet] Refactor balances into BalanceManager
---
 .../src/main/java/net/taler/wallet/MainFragment.kt | 11 ++--
 .../main/java/net/taler/wallet/MainViewModel.kt    | 30 ++-------
 .../net/taler/wallet/balances/BalanceAdapter.kt    | 12 ----
 .../net/taler/wallet/balances/BalanceManager.kt    | 76 ++++++++++++++++++++++
 .../balances/{BalanceResponse.kt => Balances.kt}   | 14 ++--
 .../net/taler/wallet/balances/BalancesFragment.kt  | 35 +++++++---
 .../wallet/transactions/TransactionsFragment.kt    |  7 +-
 7 files changed, 128 insertions(+), 57 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/MainFragment.kt 
b/wallet/src/main/java/net/taler/wallet/MainFragment.kt
index 2521e29..656db63 100644
--- a/wallet/src/main/java/net/taler/wallet/MainFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainFragment.kt
@@ -26,7 +26,8 @@ import androidx.navigation.fragment.findNavController
 import net.taler.common.EventObserver
 import net.taler.wallet.CurrencyMode.MULTI
 import net.taler.wallet.CurrencyMode.SINGLE
-import net.taler.wallet.balances.BalanceItem
+import net.taler.wallet.balances.BalanceState
+import net.taler.wallet.balances.BalanceState.Success
 import net.taler.wallet.balances.BalancesFragment
 import net.taler.wallet.databinding.FragmentMainBinding
 import net.taler.wallet.transactions.TransactionsFragment
@@ -50,7 +51,7 @@ class MainFragment : Fragment() {
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        model.balances.observe(viewLifecycleOwner) {
+        model.balanceManager.state.observe(viewLifecycleOwner) {
             onBalancesChanged(it)
         }
         model.transactionsEvent.observe(viewLifecycleOwner, EventObserver { 
currency ->
@@ -72,10 +73,12 @@ class MainFragment : Fragment() {
 
     override fun onStart() {
         super.onStart()
-        model.loadBalances()
+        model.balanceManager.loadBalances()
     }
 
-    private fun onBalancesChanged(balances: List<BalanceItem>) {
+    private fun onBalancesChanged(state: BalanceState) {
+        if (state !is Success) return
+        val balances = state.balances
         val mode = if (balances.size == 1) SINGLE else MULTI
         if (currencyMode != mode) {
             val f = if (mode == SINGLE) {
diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt 
b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
index 3c2c4ae..c28c027 100644
--- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -22,10 +22,8 @@ import androidx.annotation.UiThread
 import androidx.lifecycle.AndroidViewModel
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.distinctUntilChanged
 import androidx.lifecycle.viewModelScope
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
 import kotlinx.coroutines.launch
 import net.taler.common.Amount
 import net.taler.common.AmountParserException
@@ -37,8 +35,7 @@ import net.taler.wallet.backend.NotificationReceiver
 import net.taler.wallet.backend.VersionReceiver
 import net.taler.wallet.backend.WalletBackendApi
 import net.taler.wallet.backend.WalletCoreVersion
-import net.taler.wallet.balances.BalanceItem
-import net.taler.wallet.balances.BalanceResponse
+import net.taler.wallet.balances.BalanceManager
 import net.taler.wallet.deposit.DepositManager
 import net.taler.wallet.exchanges.ExchangeManager
 import net.taler.wallet.payment.PaymentManager
@@ -60,9 +57,6 @@ class MainViewModel(
     app: Application,
 ) : AndroidViewModel(app), VersionReceiver, NotificationReceiver {
 
-    private val mBalances = MutableLiveData<List<BalanceItem>>()
-    val balances: LiveData<List<BalanceItem>> = 
mBalances.distinctUntilChanged()
-
     val devMode = MutableLiveData(BuildConfig.DEBUG)
     val showProgressBar = MutableLiveData<Boolean>()
     var walletVersion: String? = null
@@ -83,6 +77,7 @@ class MainViewModel(
         PendingOperationsManager(api, viewModelScope)
     val transactionManager: TransactionManager = TransactionManager(api, 
viewModelScope)
     val refundManager = RefundManager(api, viewModelScope)
+    val balanceManager = BalanceManager(api, viewModelScope)
     val exchangeManager: ExchangeManager = ExchangeManager(api, viewModelScope)
     val peerManager: PeerManager = PeerManager(api, exchangeManager, 
viewModelScope)
     val settingsManager: SettingsManager = 
SettingsManager(app.applicationContext, api, viewModelScope)
@@ -108,7 +103,7 @@ class MainViewModel(
 
         // Only update balances when we're told they changed
         if (payload.type == "balance-change") {
-            loadBalances()
+            balanceManager.loadBalances()
         }
 
         if (payload.type in transactionNotifications) 
viewModelScope.launch(Dispatchers.Main) {
@@ -122,19 +117,6 @@ class MainViewModel(
         }
     }
 
-    @UiThread
-    fun loadBalances(): Job = viewModelScope.launch {
-        showProgressBar.value = true
-        val response = api.request("getBalances", BalanceResponse.serializer())
-        showProgressBar.value = false
-        response.onError {
-            Log.e(TAG, "Error retrieving balances: $it")
-        }
-        response.onSuccess {
-            mBalances.value = it.balances
-        }
-    }
-
     /**
      * Navigates to the given currency's transaction list, when [MainFragment] 
is shown.
      */
@@ -145,7 +127,7 @@ class MainViewModel(
 
     @UiThread
     fun getCurrencies(): List<String> {
-        return balances.value?.map { balanceItem ->
+        return balanceManager.balancesOrNull?.map { balanceItem ->
             balanceItem.currency
         } ?: emptyList()
     }
@@ -163,7 +145,7 @@ class MainViewModel(
 
     @UiThread
     fun hasSufficientBalance(amount: Amount): Boolean {
-        balances.value?.forEach { balanceItem ->
+        balanceManager.balancesOrNull?.forEach { balanceItem ->
             if (balanceItem.currency == amount.currency) {
                 return balanceItem.available >= amount
             }
@@ -177,7 +159,7 @@ class MainViewModel(
             api.sendRequest("clearDb")
         }
         withdrawManager.testWithdrawalStatus.value = null
-        mBalances.value = emptyList()
+        balanceManager.resetBalances()
     }
 
     fun startTunnel() {
diff --git a/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt 
b/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt
index 24ee1a1..6f3d79b 100644
--- a/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt
@@ -24,21 +24,9 @@ import android.view.ViewGroup
 import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
 import androidx.recyclerview.widget.RecyclerView.Adapter
-import kotlinx.serialization.Serializable
-import net.taler.common.Amount
 import net.taler.wallet.R
 import net.taler.wallet.balances.BalanceAdapter.BalanceViewHolder
 
-@Serializable
-data class BalanceItem(
-    val available: Amount,
-    val pendingIncoming: Amount,
-    val pendingOutgoing: Amount
-) {
-    val currency: String get() = available.currency
-    val hasPending: Boolean get() = !pendingIncoming.isZero() || 
!pendingOutgoing.isZero()
-}
-
 class BalanceAdapter(private val listener: BalanceClickListener) : 
Adapter<BalanceViewHolder>() {
 
     private var items = emptyList<BalanceItem>()
diff --git a/wallet/src/main/java/net/taler/wallet/balances/BalanceManager.kt 
b/wallet/src/main/java/net/taler/wallet/balances/BalanceManager.kt
new file mode 100644
index 0000000..3321cd1
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/balances/BalanceManager.kt
@@ -0,0 +1,76 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2024 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.balances
+
+import android.util.Log
+import androidx.annotation.UiThread
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.distinctUntilChanged
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.serialization.Serializable
+import net.taler.wallet.TAG
+import net.taler.wallet.backend.TalerErrorInfo
+import net.taler.wallet.backend.WalletBackendApi
+
+@Serializable
+data class BalanceResponse(
+    val balances: List<BalanceItem>
+)
+
+sealed class BalanceState {
+    data object None: BalanceState()
+    data object Loading: BalanceState()
+
+    data class Success(
+        val balances: List<BalanceItem>,
+    ): BalanceState()
+
+    data class Error(
+        val error: TalerErrorInfo,
+    ): BalanceState()
+}
+
+class BalanceManager(
+    private val api: WalletBackendApi,
+    private val scope: CoroutineScope,
+) {
+    private val mState = MutableLiveData<BalanceState>(BalanceState.None)
+    val state: LiveData<BalanceState> = mState.distinctUntilChanged()
+
+    val balancesOrNull get() = (state.value as? BalanceState.Success)?.balances
+
+    @UiThread
+    fun loadBalances() {
+        mState.value = BalanceState.Loading
+        scope.launch {
+            val response = api.request("getBalances", 
BalanceResponse.serializer())
+            response.onError {
+                Log.e(TAG, "Error retrieving balances: $it")
+                mState.value = BalanceState.Error(it)
+            }
+            response.onSuccess {
+                mState.value = BalanceState.Success(it.balances)
+            }
+        }
+    }
+
+    fun resetBalances() {
+        mState.value = BalanceState.None
+    }
+}
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/balances/BalanceResponse.kt 
b/wallet/src/main/java/net/taler/wallet/balances/Balances.kt
similarity index 70%
rename from wallet/src/main/java/net/taler/wallet/balances/BalanceResponse.kt
rename to wallet/src/main/java/net/taler/wallet/balances/Balances.kt
index d1a111f..2954f5b 100644
--- a/wallet/src/main/java/net/taler/wallet/balances/BalanceResponse.kt
+++ b/wallet/src/main/java/net/taler/wallet/balances/Balances.kt
@@ -1,6 +1,6 @@
 /*
  * This file is part of GNU Taler
- * (C) 2020 Taler Systems S.A.
+ * (C) 2024 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
@@ -17,8 +17,14 @@
 package net.taler.wallet.balances
 
 import kotlinx.serialization.Serializable
+import net.taler.common.Amount
 
 @Serializable
-data class BalanceResponse(
-    val balances: List<BalanceItem>
-)
+data class BalanceItem(
+    val available: Amount,
+    val pendingIncoming: Amount,
+    val pendingOutgoing: Amount,
+) {
+    val currency: String get() = available.currency
+    val hasPending: Boolean get() = !pendingIncoming.isZero() || 
!pendingOutgoing.isZero()
+}
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt 
b/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt
index c1be674..466246d 100644
--- a/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt
@@ -30,7 +30,12 @@ import androidx.recyclerview.widget.DividerItemDecoration
 import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
 import net.taler.common.fadeIn
 import net.taler.wallet.MainViewModel
+import net.taler.wallet.balances.BalanceState.Error
+import net.taler.wallet.balances.BalanceState.Loading
+import net.taler.wallet.balances.BalanceState.None
+import net.taler.wallet.balances.BalanceState.Success
 import net.taler.wallet.databinding.FragmentBalancesBinding
+import net.taler.wallet.showError
 
 interface BalanceClickListener {
     fun onBalanceClick(currency: String)
@@ -59,20 +64,30 @@ class BalancesFragment : Fragment(),
             addItemDecoration(DividerItemDecoration(context, VERTICAL))
         }
 
-        model.balances.observe(viewLifecycleOwner) {
+        model.balanceManager.state.observe(viewLifecycleOwner) {
             onBalancesChanged(it)
         }
     }
 
-    private fun onBalancesChanged(balances: List<BalanceItem>) {
-        beginDelayedTransition(view as ViewGroup)
-        if (balances.isEmpty()) {
-            ui.mainEmptyState.visibility = VISIBLE
-            ui.mainList.visibility = GONE
-        } else {
-            balancesAdapter.setItems(balances)
-            ui.mainEmptyState.visibility = INVISIBLE
-            ui.mainList.fadeIn()
+    private fun onBalancesChanged(state: BalanceState) {
+        model.showProgressBar.value = false
+        when (state) {
+            is None -> {}
+            is Loading -> {
+                model.showProgressBar.value = true
+            }
+            is Success -> {
+                beginDelayedTransition(view as ViewGroup)
+                if (state.balances.isEmpty()) {
+                    ui.mainEmptyState.visibility = VISIBLE
+                    ui.mainList.visibility = GONE
+                } else {
+                    balancesAdapter.setItems(state.balances)
+                    ui.mainEmptyState.visibility = INVISIBLE
+                    ui.mainList.fadeIn()
+                }
+            }
+            is Error -> showError(state.error)
         }
     }
 
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
index 2f00bf8..b898bec 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -43,10 +43,9 @@ import net.taler.common.fadeOut
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
 import net.taler.wallet.TAG
+import net.taler.wallet.balances.BalanceState.Success
 import net.taler.wallet.databinding.FragmentTransactionsBinding
 import net.taler.wallet.showError
-import net.taler.wallet.transactions.TransactionMajorState.*
-import net.taler.wallet.transactions.TransactionMinorState.*
 
 interface OnTransactionClickListener {
     fun onTransactionClicked(transaction: Transaction)
@@ -108,7 +107,9 @@ class TransactionsFragment : Fragment(), 
OnTransactionClickListener, ActionMode.
             }
         })
 
-        model.balances.observe(viewLifecycleOwner) { balances ->
+        model.balanceManager.state.observe(viewLifecycleOwner) { state ->
+            if (state !is Success) return@observe
+            val balances = state.balances
             // hide extra fab when in single currency mode (uses 
MainFragment's FAB)
             if (balances.size == 1) ui.mainFab.visibility = INVISIBLE
             balances.find { it.currency == currency }?.available?.let { 
amount: Amount ->

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]