commit c1ddc6606e032e73fd788fc10647bae7e9f9b81b parent a8c76d7580345e3d4f9492f883df71dc5537a0e2 Author: Iván Ávalos <avalos@disroot.org> Date: Fri, 25 Oct 2024 23:10:09 +0200 [wallet] Make things asynchronous! Diffstat:
9 files changed, 30 insertions(+), 41 deletions(-)
diff --git a/wallet/src/main/java/net/taler/wallet/Utils.kt b/wallet/src/main/java/net/taler/wallet/Utils.kt @@ -158,7 +158,7 @@ fun Context.getThemeColor(attr: Int): Int { fun <T> T.useDebounce( delayMillis: Long = 300L, coroutineScope: CoroutineScope = rememberCoroutineScope(), - onChange: (T) -> Unit + onChange: suspend (T) -> Unit ): T{ val state by rememberUpdatedState(this) diff --git a/wallet/src/main/java/net/taler/wallet/deposit/DepositFragment.kt b/wallet/src/main/java/net/taler/wallet/deposit/DepositFragment.kt @@ -76,10 +76,8 @@ class DepositFragment : Fragment() { defaultCurrency = scopeInfo?.currency, currencies = balanceManager.getCurrencies(), getCurrencySpec = { runBlocking { balanceManager.getSpecForCurrency(it) } }, - checkDeposit = { a, p -> runBlocking { depositManager.checkDepositFees(p, a) } }, - getDepositWireTypes = { currency -> - runBlocking { depositManager.getDepositWireTypesForCurrency(currency) } - }, + checkDeposit = { a, p -> depositManager.checkDepositFees(p, a) }, + getDepositWireTypes = depositManager::getDepositWireTypesForCurrency, presetName = receiverName, presetIban = iban, validateIban = depositManager::validateIban, diff --git a/wallet/src/main/java/net/taler/wallet/deposit/MakeDepositComposable.kt b/wallet/src/main/java/net/taler/wallet/deposit/MakeDepositComposable.kt @@ -64,8 +64,8 @@ fun MakeDepositComposable( defaultCurrency: String?, currencies: List<String>, getCurrencySpec: (currency: String) -> CurrencySpecification?, - checkDeposit: (amount: Amount, paytoUri: String) -> CheckDepositResult, - getDepositWireTypes: (currency: String) -> GetDepositWireTypesForCurrencyResponse?, + checkDeposit: suspend (amount: Amount, paytoUri: String) -> CheckDepositResult, + getDepositWireTypes: suspend (currency: String) -> GetDepositWireTypesForCurrencyResponse?, presetName: String? = null, presetIban: String? = null, validateIban: suspend (iban: String) -> Boolean, @@ -84,12 +84,15 @@ fun MakeDepositComposable( var checkResult by remember { mutableStateOf<CheckDepositResult>(CheckDepositResult.None) } var amount by remember { mutableStateOf(Amount.zero(defaultCurrency ?: currencies[0])) } - // TODO: make getDepositWireTypes asynchronous! - val depositWireTypes = remember(amount.currency) { getDepositWireTypes(amount.currency) } + var depositWireTypes by remember { mutableStateOf<GetDepositWireTypesForCurrencyResponse?>(null) } val supportedWireTypes = remember(depositWireTypes) { depositWireTypes?.wireTypes ?: emptyList() } val talerBankHostnames = remember(depositWireTypes) { depositWireTypes?.wireTypeDetails?.flatMap { it.talerBankHostnames }?.distinct() ?: emptyList() } var selectedWireType by remember { mutableStateOf(supportedWireTypes.firstOrNull()) } + LaunchedEffect(amount.currency) { + depositWireTypes = getDepositWireTypes(amount.currency) + } + // payto:// stuff var formError by rememberSaveable { mutableStateOf(true) } // TODO: do an initial validation! var ibanName by rememberSaveable { mutableStateOf(presetName ?: "") } @@ -105,8 +108,8 @@ fun MakeDepositComposable( } // reset forms and selected wire type when switching currency - DisposableEffect(amount.currency) { - selectedWireType = supportedWireTypes.first() + DisposableEffect(supportedWireTypes, amount.currency) { + selectedWireType = supportedWireTypes.firstOrNull() formError = true ibanName = presetName ?: "" ibanIban = presetIban ?: "" @@ -116,11 +119,8 @@ fun MakeDepositComposable( onDispose { } } - // TODO: make checkDeposit asynchronous! amount.useDebounce { if (paytoUri != null) { - // TODO: handle insufficient balance! - // TODO: handle KYC limits! checkResult = checkDeposit(amount, paytoUri) } } @@ -164,7 +164,7 @@ fun MakeDepositComposable( initialAmount = amount, initialCurrency = defaultCurrency, onAmountChanged = { amount = it }, - editableCurrency = false, + editableCurrency = true, currencies = currencies, getCurrencySpec = getCurrencySpec, isError = checkResult !is CheckDepositResult.Success, diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt @@ -66,7 +66,7 @@ fun OutgoingPullComposable( defaultCurrency: String?, currencies: List<String>, getCurrencySpec: (currency: String) -> CurrencySpecification?, - checkPeerPullCredit: (amount: Amount) -> CheckPeerPullCreditResult?, + checkPeerPullCredit: suspend (amount: Amount) -> CheckPeerPullCreditResult?, onCreateInvoice: (amount: Amount, subject: String, hours: Long, exchangeBaseUrl: String) -> Unit, onTosAccept: (exchangeBaseUrl: String) -> Unit, onClose: () -> Unit, @@ -104,7 +104,7 @@ fun OutgoingPullIntroComposable( defaultCurrency: String?, currencies: List<String>, getCurrencySpec: (currency: String) -> CurrencySpecification?, - checkPeerPullCredit: (amount: Amount) -> CheckPeerPullCreditResult?, + checkPeerPullCredit: suspend (amount: Amount) -> CheckPeerPullCreditResult?, onCreateInvoice: (amount: Amount, subject: String, hours: Long, exchangeBaseUrl: String) -> Unit, onTosAccept: (exchangeBaseUrl: String) -> Unit, ) { @@ -121,7 +121,6 @@ fun OutgoingPullIntroComposable( val selectedSpec = remember(amount) { getCurrencySpec(amount.currency) } var checkResult by remember { mutableStateOf<CheckPeerPullCreditResult?>(null) } - // TODO: make checkPeerPullCredit asynchronous! amount.useDebounce { checkResult = checkPeerPullCredit(it) } diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt @@ -20,6 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.runtime.getValue import androidx.compose.ui.platform.ComposeView import androidx.core.os.bundleOf import androidx.fragment.app.Fragment @@ -29,7 +30,6 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import net.taler.common.Amount import net.taler.wallet.MainViewModel import net.taler.wallet.R @@ -52,18 +52,16 @@ class OutgoingPullFragment : Fragment() { return ComposeView(requireContext()).apply { setContent { TalerSurface { - val state = peerManager.pullState.collectAsStateLifecycleAware().value + val state by peerManager.pullState.collectAsStateLifecycleAware() + val selectedScope by transactionManager.selectedScope.collectAsStateLifecycleAware() OutgoingPullComposable( state = state, onCreateInvoice = this@OutgoingPullFragment::onCreateInvoice, onTosAccept = this@OutgoingPullFragment::onTosAccept, - defaultCurrency = transactionManager.selectedScope.value?.currency, + defaultCurrency = selectedScope?.currency, currencies = balanceManager.getCurrencies(), getCurrencySpec = balanceManager::getSpecForCurrency, - checkPeerPullCredit = { amount -> - // TODO: make this async!!! - runBlocking { peerManager.checkPeerPullCredit(amount) } - }, + checkPeerPullCredit = peerManager::checkPeerPullCredit, onClose = { findNavController().navigate(R.id.action_nav_peer_pull_to_nav_main) } diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt @@ -61,7 +61,7 @@ fun OutgoingPushComposable( defaultCurrency: String?, currencies: List<String>, getCurrencySpec: (currency: String) -> CurrencySpecification?, - getFees: (amount: Amount) -> CheckFeeResult?, + getFees: suspend (amount: Amount) -> CheckFeeResult?, onSend: (amount: Amount, summary: String, hours: Long) -> Unit, onClose: () -> Unit, ) { @@ -83,7 +83,7 @@ fun OutgoingPushIntroComposable( defaultCurrency: String?, currencies: List<String>, getCurrencySpec: (currency: String) -> CurrencySpecification?, - getFees: (amount: Amount) -> CheckFeeResult?, + getFees: suspend (amount: Amount) -> CheckFeeResult?, onSend: (amount: Amount, summary: String, hours: Long) -> Unit, ) { val scrollState = rememberScrollState() @@ -98,7 +98,6 @@ fun OutgoingPushIntroComposable( val selectedSpec = remember(amount) { getCurrencySpec(amount.currency) } var feeResult by remember { mutableStateOf<CheckFeeResult>(None) } - // TODO: make checkPeerPullCredit asynchronous! amount.useDebounce { feeResult = getFees(it) ?: None } diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushFragment.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushFragment.kt @@ -21,6 +21,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.OnBackPressedCallback +import androidx.compose.runtime.getValue import androidx.compose.ui.platform.ComposeView import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -30,7 +31,6 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import net.taler.common.Amount import net.taler.wallet.MainViewModel import net.taler.wallet.R @@ -64,15 +64,13 @@ class OutgoingPushFragment : Fragment() { setContent { TalerSurface { val state = peerManager.pushState.collectAsStateLifecycleAware().value + val selectedScope by transactionManager.selectedScope.collectAsStateLifecycleAware() OutgoingPushComposable( state = state, - defaultCurrency = transactionManager.selectedScope.value?.currency, + defaultCurrency = selectedScope?.currency, currencies = balanceManager.getCurrencies(), getCurrencySpec = balanceManager::getSpecForCurrency, - getFees = { fees -> - // TODO: make this async!!! - runBlocking { peerManager.checkPeerPushFees(fees) } - }, + getFees = peerManager::checkPeerPushFees, onSend = this@OutgoingPushFragment::onSend, onClose = { findNavController().navigate(R.id.action_nav_peer_push_to_nav_main) diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsComposable.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsComposable.kt @@ -94,6 +94,7 @@ import net.taler.wallet.transactions.TransactionMinorState.KycRequired import net.taler.wallet.transactions.TransactionsResult.Error import net.taler.wallet.transactions.TransactionsResult.None import net.taler.wallet.transactions.TransactionsResult.Success +import net.taler.wallet.withdraw.WithdrawalError @Composable fun TransactionsComposable( @@ -105,7 +106,7 @@ fun TransactionsComposable( onShowBalancesClicked: () -> Unit, ) = when (txResult) { is None -> LoadingScreen() - is Error -> {} // TODO: render error! + is Error -> WithdrawalError(txResult.error) is Success -> { var showDeleteDialog by remember { mutableStateOf(false) } var selectionMode by remember { mutableStateOf(false) } diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt @@ -46,7 +46,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.Center @@ -116,7 +115,6 @@ class PromptWithdrawFragment: Fragment() { setContent { val status by withdrawManager.withdrawStatus.collectAsStateLifecycleAware() - val coroutineScope = rememberCoroutineScope() var defaultExchange by remember { mutableStateOf<ExchangeItem?>(null) } TalerSurface { @@ -177,10 +175,8 @@ class PromptWithdrawFragment: Fragment() { LaunchedEffect(Unit) { val s = status - coroutineScope.launch { - if (s.uriInfo?.amount == null && s.uriInfo?.defaultExchangeBaseUrl != null) { - defaultExchange = exchangeManager.findExchangeByUrl(s.uriInfo.defaultExchangeBaseUrl) - } + if (s.uriInfo?.amount == null && s.uriInfo?.defaultExchangeBaseUrl != null) { + defaultExchange = exchangeManager.findExchangeByUrl(s.uriInfo.defaultExchangeBaseUrl) } } }