summaryrefslogtreecommitdiff
path: root/wallet/src/main/java/net/taler/wallet/withdraw
diff options
context:
space:
mode:
authorTorsten Grote <t@grobox.de>2020-09-28 12:12:20 -0300
committerTorsten Grote <t@grobox.de>2020-09-28 14:27:47 -0300
commit0936fc851232c8c6c41ce4a0c479ba7a1e452137 (patch)
tree8e69b1a58319a275901456056558b28643cb8063 /wallet/src/main/java/net/taler/wallet/withdraw
parent841d87d5f9f05bc4a5e050948af2577cd87efade (diff)
downloadtaler-android-0936fc851232c8c6c41ce4a0c479ba7a1e452137.tar.gz
taler-android-0936fc851232c8c6c41ce4a0c479ba7a1e452137.tar.bz2
taler-android-0936fc851232c8c6c41ce4a0c479ba7a1e452137.zip
[wallet] implement exchange selection for withdrawals
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/withdraw')
-rw-r--r--wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt88
-rw-r--r--wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt52
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)
}