summaryrefslogtreecommitdiff
path: root/wallet
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2024-01-15 17:50:24 -0600
committerTorsten Grote <t@grobox.de>2024-02-09 14:41:30 -0300
commit512e79eaf07eadd24914eb4a41b52c824866c528 (patch)
tree586378014845c0a2989be495bc38ea63c0722e3b /wallet
parentb028df13b8366ef8a9ae1c08a49a7c172d30a159 (diff)
downloadtaler-android-512e79eaf07eadd24914eb4a41b52c824866c528.tar.gz
taler-android-512e79eaf07eadd24914eb4a41b52c824866c528.tar.bz2
taler-android-512e79eaf07eadd24914eb4a41b52c824866c528.zip
[wallet] Refactor balances into BalanceManager
Diffstat (limited to 'wallet')
-rw-r--r--wallet/src/main/java/net/taler/wallet/MainFragment.kt11
-rw-r--r--wallet/src/main/java/net/taler/wallet/MainViewModel.kt30
-rw-r--r--wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt12
-rw-r--r--wallet/src/main/java/net/taler/wallet/balances/BalanceManager.kt76
-rw-r--r--wallet/src/main/java/net/taler/wallet/balances/Balances.kt (renamed from wallet/src/main/java/net/taler/wallet/balances/BalanceResponse.kt)14
-rw-r--r--wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt35
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt7
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
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 ->