diff options
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/withdraw')
-rw-r--r-- | wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt | 88 | ||||
-rw-r--r-- | wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt | 52 |
2 files changed, 94 insertions, 46 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt index 0c7687c..38e09fa 100644 --- a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt @@ -20,13 +20,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Toast -import android.widget.Toast.LENGTH_SHORT import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar.LENGTH_LONG +import net.taler.common.EventObserver import net.taler.common.fadeIn import net.taler.common.fadeOut import net.taler.lib.common.Amount @@ -35,6 +34,7 @@ import net.taler.wallet.R import net.taler.wallet.cleanExchange import net.taler.wallet.databinding.FragmentPromptWithdrawBinding import net.taler.wallet.withdraw.WithdrawStatus.Loading +import net.taler.wallet.withdraw.WithdrawStatus.ReceivedDetails import net.taler.wallet.withdraw.WithdrawStatus.TosReviewRequired import net.taler.wallet.withdraw.WithdrawStatus.Withdrawing @@ -46,8 +46,9 @@ class PromptWithdrawFragment : Fragment() { private lateinit var ui: FragmentPromptWithdrawBinding override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, ): View? { ui = FragmentPromptWithdrawBinding.inflate(inflater, container, false) return ui.root @@ -59,21 +60,26 @@ class PromptWithdrawFragment : Fragment() { withdrawManager.withdrawStatus.observe(viewLifecycleOwner, { showWithdrawStatus(it) }) + withdrawManager.exchangeSelection.observe(viewLifecycleOwner, EventObserver { + findNavController().navigate(R.id.action_promptWithdraw_to_selectExchangeFragment) + }) } private fun showWithdrawStatus(status: WithdrawStatus?): Any = when (status) { - is WithdrawStatus.ReceivedDetails -> { - showContent(status.amountRaw, status.amountEffective, status.exchangeBaseUrl) - ui.confirmWithdrawButton.apply { - text = getString(R.string.withdraw_button_confirm) - setOnClickListener { - it.fadeOut() - ui.confirmProgressBar.fadeIn() - withdrawManager.acceptWithdrawal() - } - isEnabled = true + null -> model.showProgressBar.value = false + is Loading -> model.showProgressBar.value = true + is WithdrawStatus.NeedsExchange -> { + model.showProgressBar.value = false + val exchangeSelection = status.exchangeSelection.getIfNotConsumed() + if (exchangeSelection == null) { // already consumed + findNavController().popBackStack() + } else { + withdrawManager.selectExchange(exchangeSelection) } } + is TosReviewRequired -> onTosReviewRequired(status) + is ReceivedDetails -> onReceivedDetails(status) + is Withdrawing -> model.showProgressBar.value = true is WithdrawStatus.Success -> { model.showProgressBar.value = false withdrawManager.withdrawStatus.value = null @@ -81,14 +87,18 @@ class PromptWithdrawFragment : Fragment() { model.showTransactions(status.currency) Snackbar.make(requireView(), R.string.withdraw_initiated, LENGTH_LONG).show() } - is Loading -> { - model.showProgressBar.value = true - } - is Withdrawing -> { - model.showProgressBar.value = true + is WithdrawStatus.Error -> { + model.showProgressBar.value = false + findNavController().navigate(R.id.action_promptWithdraw_to_errorFragment) } - is TosReviewRequired -> { - showContent(status.amountRaw, status.amountEffective, status.exchangeBaseUrl) + } + + private fun onTosReviewRequired(s: TosReviewRequired) { + model.showProgressBar.value = false + if (s.showImmediately.getIfNotConsumed() == true) { + findNavController().navigate(R.id.action_promptWithdraw_to_reviewExchangeTOS) + } else { + showContent(s.amountRaw, s.amountEffective, s.exchangeBaseUrl, s.talerWithdrawUri) ui.confirmWithdrawButton.apply { text = getString(R.string.withdraw_button_tos) setOnClickListener { @@ -97,14 +107,27 @@ class PromptWithdrawFragment : Fragment() { isEnabled = true } } - is WithdrawStatus.Error -> { - model.showProgressBar.value = false - findNavController().navigate(R.id.action_promptWithdraw_to_errorFragment) + } + + private fun onReceivedDetails(s: ReceivedDetails) { + showContent(s.amountRaw, s.amountEffective, s.exchangeBaseUrl, s.talerWithdrawUri) + ui.confirmWithdrawButton.apply { + text = getString(R.string.withdraw_button_confirm) + setOnClickListener { + it.fadeOut() + ui.confirmProgressBar.fadeIn() + withdrawManager.acceptWithdrawal() + } + isEnabled = true } - null -> model.showProgressBar.value = false } - private fun showContent(amountRaw: Amount, amountEffective: Amount, exchange: String) { + private fun showContent( + amountRaw: Amount, + amountEffective: Amount, + exchange: String, + uri: String?, + ) { model.showProgressBar.value = false ui.progressBar.fadeOut() @@ -117,15 +140,20 @@ class PromptWithdrawFragment : Fragment() { ui.chosenAmountView.fadeIn() ui.feeLabel.fadeIn() - ui.feeView.text = getString(R.string.amount_negative, (amountRaw - amountEffective).toString()) + ui.feeView.text = + getString(R.string.amount_negative, (amountRaw - amountEffective).toString()) ui.feeView.fadeIn() ui.exchangeIntroView.fadeIn() ui.withdrawExchangeUrl.text = cleanExchange(exchange) ui.withdrawExchangeUrl.fadeIn() - ui.selectExchangeButton.fadeIn() - ui.selectExchangeButton.setOnClickListener { - Toast.makeText(context, "Not yet implemented", LENGTH_SHORT).show() + + if (uri != null) { // no Uri for manual withdrawals + ui.selectExchangeButton.fadeIn() + ui.selectExchangeButton.setOnClickListener { + val exchangeSelection = ExchangeSelection(amountRaw, uri) + withdrawManager.selectExchange(exchangeSelection) + } } ui.withdrawCard.fadeIn() diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt index 25c5b72..5e11c04 100644 --- a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt +++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt @@ -18,10 +18,13 @@ package net.taler.wallet.withdraw import android.util.Log import androidx.annotation.UiThread +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlinx.serialization.Serializable +import net.taler.common.Event +import net.taler.common.toEvent import net.taler.lib.common.Amount import net.taler.wallet.TAG import net.taler.wallet.backend.TalerErrorInfo @@ -32,20 +35,23 @@ import net.taler.wallet.withdraw.WithdrawStatus.ReceivedDetails sealed class WithdrawStatus { data class Loading(val talerWithdrawUri: String? = null) : WithdrawStatus() + data class NeedsExchange(val exchangeSelection: Event<ExchangeSelection>) : WithdrawStatus() + data class TosReviewRequired( val talerWithdrawUri: String? = null, val exchangeBaseUrl: String, val amountRaw: Amount, val amountEffective: Amount, val tosText: String, - val tosEtag: String + val tosEtag: String, + val showImmediately: Event<Boolean>, ) : WithdrawStatus() data class ReceivedDetails( val talerWithdrawUri: String? = null, val exchangeBaseUrl: String, val amountRaw: Amount, - val amountEffective: Amount + val amountEffective: Amount, ) : WithdrawStatus() object Withdrawing : WithdrawStatus() @@ -57,24 +63,31 @@ sealed class WithdrawStatus { data class WithdrawalDetailsForUri( val amount: Amount, val defaultExchangeBaseUrl: String?, - val possibleExchanges: List<ExchangeItem> + val possibleExchanges: List<ExchangeItem>, ) @Serializable data class WithdrawalDetails( val tosAccepted: Boolean, val amountRaw: Amount, - val amountEffective: Amount + val amountEffective: Amount, +) + +data class ExchangeSelection( + val amount: Amount, + val talerWithdrawUri: String, ) class WithdrawManager( private val api: WalletBackendApi, - private val scope: CoroutineScope + private val scope: CoroutineScope, ) { val withdrawStatus = MutableLiveData<WithdrawStatus>() val testWithdrawalInProgress = MutableLiveData(false) + private val _exchangeSelection = MutableLiveData<Event<ExchangeSelection>>() + val exchangeSelection: LiveData<Event<ExchangeSelection>> = _exchangeSelection var exchangeFees: ExchangeFees? = null private set @@ -87,6 +100,11 @@ class WithdrawManager( } } + @UiThread + fun selectExchange(selection: ExchangeSelection) { + _exchangeSelection.value = selection.toEvent() + } + fun getWithdrawalDetails(uri: String) = scope.launch { withdrawStatus.value = WithdrawStatus.Loading(uri) api.request("getWithdrawalDetailsForUri", WithdrawalDetailsForUri.serializer()) { @@ -95,11 +113,10 @@ class WithdrawManager( handleError("getWithdrawalDetailsForUri", error) }.onSuccess { details -> if (details.defaultExchangeBaseUrl == null) { - // TODO go to exchange selection screen instead - val chosenExchange = details.possibleExchanges[0].exchangeBaseUrl - getWithdrawalDetails(chosenExchange, details.amount, uri) + val exchangeSelection = ExchangeSelection(details.amount, uri) + withdrawStatus.value = WithdrawStatus.NeedsExchange(exchangeSelection.toEvent()) } else { - getWithdrawalDetails(details.defaultExchangeBaseUrl, details.amount, uri) + getWithdrawalDetails(details.defaultExchangeBaseUrl, details.amount, false, uri) } } } @@ -107,7 +124,8 @@ class WithdrawManager( fun getWithdrawalDetails( exchangeBaseUrl: String, amount: Amount, - uri: String? = null + showTosImmediately: Boolean = false, + uri: String? = null, ) = scope.launch { withdrawStatus.value = WithdrawStatus.Loading(uri) api.request("getWithdrawalDetailsForAmount", WithdrawalDetails.serializer()) { @@ -121,16 +139,17 @@ class WithdrawManager( talerWithdrawUri = uri, exchangeBaseUrl = exchangeBaseUrl, amountRaw = details.amountRaw, - amountEffective = details.amountEffective + amountEffective = details.amountEffective, ) - } else getExchangeTos(exchangeBaseUrl, details, uri) + } else getExchangeTos(exchangeBaseUrl, details, showTosImmediately, uri) } } private fun getExchangeTos( exchangeBaseUrl: String, details: WithdrawalDetails, - uri: String? + showImmediately: Boolean, + uri: String?, ) = scope.launch { api.request("getExchangeTos", TosResponse.serializer()) { put("exchangeBaseUrl", exchangeBaseUrl) @@ -143,7 +162,8 @@ class WithdrawManager( amountRaw = details.amountRaw, amountEffective = details.amountEffective, tosText = it.tos, - tosEtag = it.currentEtag + tosEtag = it.currentEtag, + showImmediately = showImmediately.toEvent(), ) } } @@ -163,7 +183,7 @@ class WithdrawManager( talerWithdrawUri = s.talerWithdrawUri, exchangeBaseUrl = s.exchangeBaseUrl, amountRaw = s.amountRaw, - amountEffective = s.amountEffective + amountEffective = s.amountEffective, ) } } @@ -181,7 +201,7 @@ class WithdrawManager( api.request<Unit>(operation) { put("exchangeBaseUrl", status.exchangeBaseUrl) if (status.talerWithdrawUri == null) { - put("amount", status.amountRaw) + put("amount", status.amountRaw.toJSONString()) } else { put("talerWithdrawUri", status.talerWithdrawUri) } |