commit 0f816b80f13b6061720aa036f5e0e4f9cb3f2589
parent 2e99e3afa708639cf9e11125e39ca62e81a382ba
Author: Iván Ávalos <avalos@disroot.org>
Date: Mon, 29 Jul 2024 22:46:52 +0200
[wallet] improvements and fixes to ToS review flow
Diffstat:
2 files changed, 65 insertions(+), 32 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
@@ -97,6 +97,8 @@ class PromptWithdrawFragment: Fragment() {
private val selectExchangeDialog = SelectExchangeDialogFragment()
+ private var startup: Boolean = true
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -115,9 +117,9 @@ class PromptWithdrawFragment: Fragment() {
}
when (s.status) {
- None, Loading, TosReviewRequired -> LoadingScreen()
+ None, Loading -> LoadingScreen()
- InfoReceived, Updating -> {
+ InfoReceived, TosReviewRequired, Updating -> {
val spec = remember(s) {
defaultExchange?.scopeInfo?.let { scopeInfo ->
balanceManager.getSpecForScopeInfo(scopeInfo)
@@ -138,9 +140,15 @@ class PromptWithdrawFragment: Fragment() {
loading = false,
)
},
+ onTosReview = {
+ // TODO: rewrite ToS review screen in compose
+ findNavController().navigate(
+ R.id.action_promptWithdraw_to_reviewExchangeTOS,
+ )
+ },
onConfirm = { age ->
withdrawManager.acceptWithdrawal(age)
- }
+ },
)
}
else -> {}
@@ -149,8 +157,8 @@ class PromptWithdrawFragment: Fragment() {
}
LaunchedEffect(Unit) {
+ val s = status
coroutineScope.launch {
- val s = status
if (s.uriInfo?.amount == null && s.uriInfo?.defaultExchangeBaseUrl != null) {
defaultExchange = exchangeManager.findExchangeByUrl(s.uriInfo.defaultExchangeBaseUrl)
}
@@ -175,10 +183,12 @@ class PromptWithdrawFragment: Fragment() {
}
when (status.status) {
- // TODO: rewrite ToS review screen in compose
- TosReviewRequired -> {
- findNavController().navigate(
- R.id.action_promptWithdraw_to_reviewExchangeTOS,
+ InfoReceived -> if (startup) { // only fire at startup
+ startup = false
+ withdrawManager.getWithdrawalDetails(
+ amount = status.amountInfo?.amountRaw ?: status.uriInfo?.amount,
+ exchangeBaseUrl = status.exchangeBaseUrl ?: status.uriInfo?.defaultExchangeBaseUrl,
+ loading = true,
)
}
@@ -228,9 +238,10 @@ fun WithdrawalShowInfo(
spec: CurrencySpecification?,
onSelectAmount: (amount: Amount) -> Unit,
onSelectExchange: () -> Unit,
+ onTosReview: () -> Unit,
onConfirm: (age: Int?) -> Unit,
) {
- val defaultAmount = status.uriInfo?.amount
+ val defaultAmount = status.amountInfo?.amountRaw ?: status.uriInfo?.amount
val maxAmount = status.uriInfo?.maxAmount
val editableAmount = status.uriInfo?.editableAmount ?: false
val wireFee = status.uriInfo?.wireFee ?: Amount.zero(currency)
@@ -238,16 +249,17 @@ fun WithdrawalShowInfo(
val possibleExchanges = status.uriInfo?.possibleExchanges ?: emptyList()
val ageRestrictionOptions = status.amountInfo?.ageRestrictionOptions ?: emptyList()
+ var startup by remember { mutableStateOf(true) }
var selectedAmount by remember { mutableStateOf(defaultAmount) }
var selectedAge by remember { mutableStateOf<Int?>(null) }
var error by remember { mutableStateOf(false) }
val scrollState = rememberScrollState()
selectedAmount.useDebounce {
- it?.let { amount ->
- if (editableAmount) {
- onSelectAmount(amount)
- }
+ if (startup) { // do not fire at startup
+ startup = false
+ } else it?.let {
+ onSelectAmount(it)
}
}
@@ -374,15 +386,17 @@ fun WithdrawalShowInfo(
&& status.status != Updating
&& selectedAmount?.let { !it.isZero() } == true,
onClick = {
- selectedAmount?.let { onConfirm(selectedAge) }
+ if (status.status == TosReviewRequired) {
+ onTosReview()
+ } else selectedAmount?.let {
+ onConfirm(selectedAge)
+ }
},
) {
- if (status.status == Updating) {
- CircularProgressIndicator(
- modifier = Modifier.size(15.dp)
- )
- } else {
- Text(stringResource(R.string.withdraw_button_confirm))
+ when (status.status) {
+ Updating -> CircularProgressIndicator(modifier = Modifier.size(15.dp))
+ TosReviewRequired -> Text(stringResource(R.string.withdraw_button_tos))
+ else -> Text(stringResource(R.string.withdraw_button_confirm))
}
}
}
@@ -507,6 +521,7 @@ fun WithdrawalShowInfoPreview() {
spec = null,
onSelectExchange = {},
onSelectAmount = {},
+ onTosReview = {},
onConfirm = {},
)
}
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
@@ -272,8 +272,16 @@ class WithdrawManager(
val status = _withdrawStatus.getAndUpdate { value ->
value.copy(status = if (loading) Loading else Updating)
}
- val exchangeBaseUrl2 = exchangeBaseUrl ?: status.exchangeBaseUrl!!
- val amount2 = amount?.toJSONString() ?: status.amountInfo!!.amountRaw.toJSONString()
+
+ val exchangeBaseUrl2 = exchangeBaseUrl
+ ?: status.exchangeBaseUrl
+ ?: error("no exchangeBaseUrl")
+
+ val amount2 = amount?.toJSONString()
+ ?: status.uriInfo?.amount?.toJSONString()
+ ?: status.amountInfo?.amountRaw?.toJSONString()
+ ?: error("no amount")
+
api.request("getWithdrawalDetailsForAmount", WithdrawalDetailsForAmount.serializer()) {
put("exchangeBaseUrl", exchangeBaseUrl2)
put("amount", amount2)
@@ -285,12 +293,15 @@ class WithdrawManager(
value.copy(
status = InfoReceived,
exchangeBaseUrl = exchangeBaseUrl2,
- uriInfo = uriInfo,
+ uriInfo = uriInfo ?: value.uriInfo,
amountInfo = details,
currency = details.amountRaw.currency,
)
}
- } else getExchangeTos(exchangeBaseUrl2)
+ } else getExchangeTos(
+ exchangeBaseUrl2,
+ amountInfo = details,
+ )
}
}
@@ -310,6 +321,7 @@ class WithdrawManager(
private fun getExchangeTos(
exchangeBaseUrl: String,
+ amountInfo: WithdrawalDetailsForAmount? = null,
) = scope.launch {
api.request("getExchangeTos", TosResponse.serializer()) {
put("exchangeBaseUrl", exchangeBaseUrl)
@@ -319,6 +331,7 @@ class WithdrawManager(
_withdrawStatus.update { value ->
value.copy(
status = TosReviewRequired,
+ amountInfo = amountInfo ?: value.amountInfo,
tosDetails = tos,
)
}
@@ -329,8 +342,11 @@ class WithdrawManager(
* Accept the currently displayed terms of service.
*/
fun acceptCurrentTos() = scope.launch {
- val exchangeBaseUrl = withdrawStatus.value.exchangeBaseUrl!!
- val tos = withdrawStatus.value.tosDetails!!
+ val exchangeBaseUrl = withdrawStatus.value.exchangeBaseUrl
+ ?: error("no exchangeBaseUrl")
+ val tos = withdrawStatus.value.tosDetails
+ ?: error("no tosDetails")
+
api.request<Unit>("setExchangeTosAccepted") {
put("exchangeBaseUrl", exchangeBaseUrl)
put("etag", tos.currentEtag)
@@ -360,9 +376,10 @@ class WithdrawManager(
status: WithdrawStatus,
restrictAge: Int? = null,
) {
- val exchangeBaseUrl = status.exchangeBaseUrl!!
- val talerWithdrawUri = status.talerWithdrawUri!!
- val amountInfo = status.amountInfo!!
+ val exchangeBaseUrl = status.exchangeBaseUrl ?: error("no exchangeBaseUrl")
+ val talerWithdrawUri = status.talerWithdrawUri ?: error("no talerWithdrawUri")
+ val amountInfo = status.amountInfo ?: error("no amountInfo")
+
api.request("acceptBankIntegratedWithdrawal", AcceptWithdrawalResponse.serializer()) {
restrictAge?.let { put("restrictAge", it) }
put("exchangeBaseUrl", exchangeBaseUrl)
@@ -384,8 +401,9 @@ class WithdrawManager(
status: WithdrawStatus,
restrictAge: Int? = null,
) {
- val exchangeBaseUrl = status.exchangeBaseUrl!!
- val amountInfo = status.amountInfo!!
+ val exchangeBaseUrl = status.exchangeBaseUrl ?: error("no exchangeBaseUrl")
+ val amountInfo = status.amountInfo ?: error("no amountInfo")
+
api.request("acceptManualWithdrawal", AcceptManualWithdrawalResponse.serializer()) {
restrictAge?.let { put("restrictAge", it) }
put("exchangeBaseUrl", exchangeBaseUrl)
@@ -458,7 +476,7 @@ class WithdrawManager(
status = ManualTransferRequired,
manualTransferResponse = response,
withdrawalTransfers = response.withdrawalAccountsList.mapNotNull {
- val details = status.amountInfo!!
+ val details = status.amountInfo ?: error("no amountInfo")
val uri = Uri.parse(it.paytoUri.replace("receiver-name=", "receiver_name="))
if ("bitcoin".equals(uri.authority, true)) {
val msg = uri.getQueryParameter("message").orEmpty()