taler-android

Android apps for GNU Taler (wallet, PoS, cashier)
Log | Files | Refs | README | LICENSE

commit 9a0c901734c8141327a6c9e6b50a10ad778a18f5
parent 7f12008802c603ac0c6b71dbedbff48717397e08
Author: Iván Ávalos <avalos@disroot.org>
Date:   Mon, 15 Jul 2024 12:48:39 -0600

[wallet] Invert withdrawal flow when default amount is available

Diffstat:
Mwallet/src/main/java/net/taler/wallet/HandleUriFragment.kt | 2+-
Mwallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt | 8+++++---
Mwallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt | 57++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mwallet/src/main/java/net/taler/wallet/withdraw/WithdrawAmountFragment.kt | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mwallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt | 131++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mwallet/src/main/java/net/taler/wallet/withdraw/manual/ManualWithdrawFragment.kt | 6+++++-
Mwallet/src/main/res/layout/fragment_prompt_withdraw.xml | 18+++++++++++++++++-
Mwallet/src/main/res/navigation/nav_graph.xml | 11+++++++++--
8 files changed, 281 insertions(+), 40 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/HandleUriFragment.kt b/wallet/src/main/java/net/taler/wallet/HandleUriFragment.kt @@ -119,7 +119,7 @@ class HandleUriFragment: Fragment() { action.startsWith("withdraw/", ignoreCase = true) -> { Log.v(TAG, "navigating!") // there's more than one entry point, so use global action - findNavController().navigate(R.id.action_handleUri_to_withdrawAmount) + findNavController().navigate(R.id.action_handleUri_to_promptWithdraw) model.withdrawManager.getWithdrawalDetails(u2) } diff --git a/wallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt b/wallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt @@ -23,11 +23,9 @@ import android.view.ViewGroup import android.widget.Toast import android.widget.Toast.LENGTH_LONG import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState @@ -114,7 +112,11 @@ class ReceiveFundsFragment : Fragment() { // now that we have the exchange, we can navigate exchangeManager.withdrawalExchange = exchange - withdrawManager.getWithdrawalDetails(exchange.exchangeBaseUrl, amount) + withdrawManager.getWithdrawalDetails( + exchangeBaseUrl = exchange.exchangeBaseUrl, + currency = amount.currency, + amount = amount, + ) findNavController().navigate(R.id.action_receiveFunds_to_nav_prompt_withdraw) } diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt @@ -42,6 +42,7 @@ 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 +import net.taler.wallet.withdraw.WithdrawStatus.NeedsAmount import net.taler.wallet.withdraw.WithdrawStatus.NeedsExchange class PromptWithdrawFragment : Fragment() { @@ -78,7 +79,10 @@ class PromptWithdrawFragment : Fragment() { private fun showWithdrawStatus(status: WithdrawStatus?): Any = when (status) { null -> model.showProgressBar.value = false is Loading -> model.showProgressBar.value = true - is WithdrawStatus.NeedsAmount -> {} // handled in WithdrawAmountFragment + is NeedsAmount -> { + model.showProgressBar.value = false + findNavController().navigate(R.id.action_promptWithdraw_to_withdrawAmount) + } is NeedsExchange -> { model.showProgressBar.value = false if (selectExchangeDialog.dialog?.isShowing != true) { @@ -122,6 +126,7 @@ class PromptWithdrawFragment : Fragment() { exchange = s.exchangeBaseUrl, uri = s.talerWithdrawUri, exchanges = s.possibleExchanges, + editableAmount = s.editableAmount, ) ui.confirmWithdrawButton.apply { text = getString(R.string.withdraw_button_tos) @@ -141,6 +146,7 @@ class PromptWithdrawFragment : Fragment() { uri = s.talerWithdrawUri, ageRestrictionOptions = s.ageRestrictionOptions, exchanges = s.possibleExchanges, + editableAmount = s.editableAmount, ) ui.confirmWithdrawButton.apply { text = getString(R.string.withdraw_button_confirm) @@ -164,6 +170,7 @@ class PromptWithdrawFragment : Fragment() { uri: String?, exchanges: List<ExchangeItem> = emptyList(), ageRestrictionOptions: List<Int>? = null, + editableAmount: Boolean, ) { model.showProgressBar.value = false ui.progressBar.fadeOut() @@ -176,6 +183,15 @@ class PromptWithdrawFragment : Fragment() { ui.chosenAmountView.text = amountRaw.toString() ui.chosenAmountView.fadeIn() + if (editableAmount) { + ui.selectAmountButton.fadeIn() + ui.selectAmountButton.setOnClickListener { + findNavController().navigate(R.id.action_promptWithdraw_to_withdrawAmount) + } + } else { + ui.selectAmountButton.fadeOut() + } + if (amountRaw > amountEffective) { val fee = amountRaw - amountEffective ui.feeLabel.fadeIn() @@ -209,6 +225,7 @@ class PromptWithdrawFragment : Fragment() { private fun selectExchange() { val exchanges = when (val status = withdrawManager.withdrawStatus.value) { + is NeedsAmount -> status.possibleExchanges is ReceivedDetails -> status.possibleExchanges is NeedsExchange -> status.possibleExchanges is TosReviewRequired -> status.possibleExchanges @@ -220,18 +237,52 @@ class PromptWithdrawFragment : Fragment() { private fun onExchangeSelected(exchange: ExchangeItem) { val status = withdrawManager.withdrawStatus.value + + val maxAmount = when (status) { + is NeedsAmount -> status.maxAmount + is ReceivedDetails -> status.maxAmount + is NeedsExchange -> status.maxAmount + is TosReviewRequired -> status.maxAmount + else -> return + } + + val wireFee = when (status) { + is NeedsAmount -> status.wireFee + is ReceivedDetails -> status.wireFee + is NeedsExchange -> status.wireFee + is TosReviewRequired -> status.wireFee + else -> return + } + + val editableAmount = when (status) { + is NeedsAmount -> status.editableAmount + is ReceivedDetails -> status.editableAmount + is NeedsExchange -> status.editableAmount + is TosReviewRequired -> status.editableAmount + else -> return + } + val amount = when (status) { is ReceivedDetails -> status.amountRaw is NeedsExchange -> status.amount is TosReviewRequired -> status.amountRaw else -> return } + + val currency = when (status) { + is ReceivedDetails -> status.currency + is NeedsExchange -> status.currency + is TosReviewRequired -> status.currency + else -> return + } + val uri = when (status) { is ReceivedDetails -> status.talerWithdrawUri is NeedsExchange -> status.talerWithdrawUri is TosReviewRequired -> status.talerWithdrawUri else -> return } + val exchanges = when (status) { is ReceivedDetails -> status.possibleExchanges is NeedsExchange -> status.possibleExchanges @@ -241,7 +292,11 @@ class PromptWithdrawFragment : Fragment() { withdrawManager.getWithdrawalDetails( exchangeBaseUrl = exchange.exchangeBaseUrl, + currency = currency, amount = amount, + maxAmount = maxAmount, + wireFee = wireFee, + editableAmount = editableAmount, showTosImmediately = false, uri = uri, possibleExchanges = exchanges, diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawAmountFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawAmountFragment.kt @@ -65,6 +65,9 @@ import net.taler.wallet.transactions.AmountType import net.taler.wallet.transactions.TransactionAmountComposable import net.taler.wallet.withdraw.WithdrawStatus.Loading import net.taler.wallet.withdraw.WithdrawStatus.NeedsAmount +import net.taler.wallet.withdraw.WithdrawStatus.NeedsExchange +import net.taler.wallet.withdraw.WithdrawStatus.ReceivedDetails +import net.taler.wallet.withdraw.WithdrawStatus.TosReviewRequired class WithdrawAmountFragment: Fragment() { private val model: MainViewModel by activityViewModels() @@ -72,6 +75,8 @@ class WithdrawAmountFragment: Fragment() { private val balanceManager by lazy { model.balanceManager } private val exchangeManager by lazy { model.exchangeManager } + var selected: Boolean = false + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -88,13 +93,21 @@ class WithdrawAmountFragment: Fragment() { LoadingScreen() } - is NeedsAmount -> { + else -> { + val currency = when(s) { + is NeedsAmount -> s.currency + is NeedsExchange -> s.currency + is ReceivedDetails -> s.currency + is TosReviewRequired -> s.currency + else -> error("invalid state") + } + // Find currencySpec for currency or exchange val exchange = defaultExchange val spec = if (exchange?.scopeInfo != null) { balanceManager.getSpecForScopeInfo(exchange.scopeInfo) } else { - balanceManager.getSpecForCurrency(s.currency) + balanceManager.getSpecForCurrency(currency) } WithdrawAmountComposable( @@ -103,11 +116,10 @@ class WithdrawAmountFragment: Fragment() { onCreateAmount = model::createAmount, onSubmit = { amount -> withdrawManager.selectWithdrawalAmount(amount) + selected = true } ) } - - else -> {} } } @@ -128,7 +140,11 @@ class WithdrawAmountFragment: Fragment() { when (status) { is Loading -> {} is NeedsAmount -> {} - else -> findNavController().navigate(R.id.action_withdrawAmount_to_promptWithdraw) + else -> { + if (selected) { + findNavController().navigate(R.id.action_withdrawAmount_to_promptWithdraw) + } + } } } } @@ -136,14 +152,46 @@ class WithdrawAmountFragment: Fragment() { @Composable fun WithdrawAmountComposable( - status: NeedsAmount, + status: WithdrawStatus, spec: CurrencySpecification?, onCreateAmount: (str: String, currency: String, incoming: Boolean) -> AmountResult, onSubmit: (amount: Amount) -> Unit, ) { + val amount = when (status) { + is NeedsAmount -> null + is NeedsExchange -> status.amount + is ReceivedDetails -> status.amountRaw + is TosReviewRequired -> status.amountRaw + else -> error("invalid state") + } + + val maxAmount = when (status) { + is NeedsAmount -> status.maxAmount + is NeedsExchange -> status.maxAmount + is ReceivedDetails -> status.maxAmount + is TosReviewRequired -> status.maxAmount + else -> error("invalid state") + } + + val currency = when (status) { + is NeedsAmount -> status.currency + is NeedsExchange -> status.currency + is ReceivedDetails -> status.currency + is TosReviewRequired -> status.currency + else -> error("invalid state") + } + + val wireFee = when (status) { + is NeedsAmount -> status.wireFee + is NeedsExchange -> status.wireFee + is ReceivedDetails -> status.wireFee + is TosReviewRequired -> status.wireFee + else -> error("invalid state") + } + var error by remember { mutableStateOf<String?>(null) } var selectedAmount by remember { - mutableStateOf(status.amount?.amountStr ?: "0") + mutableStateOf(amount?.amountStr ?: "0") } val supportingText = @Composable { @@ -154,12 +202,12 @@ fun WithdrawAmountComposable( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { - if (status.maxAmount != null) { + if (maxAmount != null) { Spacer(Modifier.height(16.dp)) TransactionAmountComposable( label = stringResource(R.string.amount_max), - amount = status.maxAmount, + amount = maxAmount, amountType = AmountType.Neutral, ) } @@ -184,31 +232,31 @@ fun WithdrawAmountComposable( Text( modifier = Modifier, - text = spec?.symbol ?: status.currency, + text = spec?.symbol ?: currency, softWrap = false, style = MaterialTheme.typography.titleLarge, ) } - if (status.wireFee != null && !status.wireFee.isZero()) { + if (wireFee != null && !wireFee.isZero()) { TransactionAmountComposable( label = stringResource(R.string.amount_fee), - amount = status.wireFee, + amount = wireFee, amountType = AmountType.Negative, ) - val amount = try { + val selected = try { Amount.fromString( - currency = status.currency, + currency = currency, str = selectedAmount, ) } catch (_: AmountParserException) { null } - if (amount != null) { + if (selected != null) { TransactionAmountComposable( label = stringResource(R.string.amount_total), - amount = amount + status.wireFee, - amountType = AmountType.Negative, + amount = selected + wireFee, + amountType = AmountType.Positive, ) } } @@ -218,14 +266,14 @@ fun WithdrawAmountComposable( Button( modifier = Modifier.padding(top = 16.dp), onClick = { - when (val res = onCreateAmount(selectedAmount, status.currency, true)) { + when (val res = onCreateAmount(selectedAmount, currency, true)) { is InsufficientBalance -> {} // doesn't apply is InvalidAmount -> { error = context.getString(R.string.amount_invalid) } is Success -> { // Check that amount doesn't exceed maximum - if (status.maxAmount != null && res.amount > status.maxAmount) { + if (maxAmount != null && res.amount > maxAmount) { error = context.getString(R.string.amount_excess) } else { onSubmit(res.amount) @@ -249,9 +297,9 @@ fun WithdrawAmountComposablePreview() { currency = "KUDOS", maxAmount = Amount.fromJSONString("KUDOS:100"), wireFee = Amount.fromJSONString("KUDOS:0.2"), - amount = null, possibleExchanges = listOf(), defaultExchangeBaseUrl = null, + editableAmount = true, ), spec = null, onCreateAmount = { _, _, _ -> InvalidAmount }, diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt @@ -44,8 +44,8 @@ sealed class WithdrawStatus { data class NeedsAmount( val talerWithdrawUri: String, val currency: String, - val amount: Amount?, val maxAmount: Amount?, + val editableAmount: Boolean, val wireFee: Amount?, val possibleExchanges: List<ExchangeItem>, val defaultExchangeBaseUrl: String?, @@ -53,13 +53,21 @@ sealed class WithdrawStatus { data class NeedsExchange( val talerWithdrawUri: String, + val currency: String, val amount: Amount, + val maxAmount: Amount?, + val editableAmount: Boolean, + val wireFee: Amount?, val possibleExchanges: List<ExchangeItem>, ) : WithdrawStatus() data class TosReviewRequired( val talerWithdrawUri: String? = null, val exchangeBaseUrl: String, + val currency: String, + val maxAmount: Amount?, + val wireFee: Amount?, + val editableAmount: Boolean, val amountRaw: Amount, val amountEffective: Amount, val withdrawalAccountList: List<WithdrawalExchangeAccountDetails>, @@ -72,6 +80,10 @@ sealed class WithdrawStatus { data class ReceivedDetails( val talerWithdrawUri: String? = null, + val currency: String, + val maxAmount: Amount?, + val wireFee: Amount?, + val editableAmount: Boolean, val exchangeBaseUrl: String, val amountRaw: Amount, val amountEffective: Amount, @@ -228,12 +240,13 @@ class WithdrawManager( handleError("getWithdrawalDetailsForUri", error) }.onSuccess { details -> Log.d(TAG, "Withdraw details: $details") - if (details.amount == null || details.editableAmount) { + + if (details.amount == null) { withdrawStatus.value = WithdrawStatus.NeedsAmount( talerWithdrawUri = uri, wireFee = details.wireFee, - amount = details.amount, maxAmount = details.maxAmount, + editableAmount = details.editableAmount, currency = details.currency, possibleExchanges = details.possibleExchanges, defaultExchangeBaseUrl = details.defaultExchangeBaseUrl, @@ -241,12 +254,20 @@ class WithdrawManager( } else if (details.defaultExchangeBaseUrl == null) { withdrawStatus.value = WithdrawStatus.NeedsExchange( talerWithdrawUri = uri, + currency = details.currency, amount = details.amount, possibleExchanges = details.possibleExchanges, + maxAmount = details.maxAmount, + wireFee = details.wireFee, + editableAmount = details.editableAmount, ) } else getWithdrawalDetails( exchangeBaseUrl = details.defaultExchangeBaseUrl, + currency = details.currency, amount = details.amount, + maxAmount = details.maxAmount, + wireFee = details.wireFee, + editableAmount = details.editableAmount, showTosImmediately = false, uri = uri, possibleExchanges = details.possibleExchanges, @@ -256,7 +277,11 @@ class WithdrawManager( fun getWithdrawalDetails( exchangeBaseUrl: String, + currency: String, amount: Amount, + maxAmount: Amount? = null, + wireFee: Amount? = null, + editableAmount: Boolean = false, showTosImmediately: Boolean = false, uri: String? = null, possibleExchanges: List<ExchangeItem> = emptyList(), @@ -271,32 +296,104 @@ class WithdrawManager( if (details.tosAccepted) { withdrawStatus.value = ReceivedDetails( talerWithdrawUri = uri, + currency = currency, exchangeBaseUrl = exchangeBaseUrl, amountRaw = details.amountRaw, amountEffective = details.amountEffective, withdrawalAccountList = details.withdrawalAccountsList, ageRestrictionOptions = details.ageRestrictionOptions, possibleExchanges = possibleExchanges, + maxAmount = maxAmount, + wireFee = wireFee, + editableAmount = editableAmount, ) - } else getExchangeTos(exchangeBaseUrl, details, showTosImmediately, uri, possibleExchanges) + } else getExchangeTos( + exchangeBaseUrl = exchangeBaseUrl, + currency = currency, + details = details, + showImmediately = showTosImmediately, + uri = uri, + possibleExchanges = possibleExchanges, + maxAmount = maxAmount, + wireFee = wireFee, + editableAmount = editableAmount, + ) } } fun selectWithdrawalAmount(amount: Amount) { - val s = withdrawStatus.value as WithdrawStatus.NeedsAmount + val s = withdrawStatus.value - if (s.defaultExchangeBaseUrl == null) { - withdrawStatus.value = WithdrawStatus.NeedsExchange( - talerWithdrawUri = s.talerWithdrawUri, + val details = when (s) { + is WithdrawStatus.NeedsExchange -> WithdrawalDetailsForUri( + defaultExchangeBaseUrl = null, + currency = s.currency, + amount = amount, + possibleExchanges = s.possibleExchanges, + maxAmount = s.maxAmount, + wireFee = s.wireFee, + editableAmount = s.editableAmount, + ) + is WithdrawStatus.NeedsAmount -> WithdrawalDetailsForUri( + defaultExchangeBaseUrl = s.defaultExchangeBaseUrl, + currency = s.currency, + amount = amount, + possibleExchanges = s.possibleExchanges, + maxAmount = s.maxAmount, + wireFee = s.wireFee, + editableAmount = s.editableAmount, + ) + is ReceivedDetails -> WithdrawalDetailsForUri( + defaultExchangeBaseUrl = s.exchangeBaseUrl, + currency = s.currency, amount = amount, possibleExchanges = s.possibleExchanges, + maxAmount = s.maxAmount, + wireFee = s.wireFee, + editableAmount = s.editableAmount, ) + is WithdrawStatus.TosReviewRequired -> WithdrawalDetailsForUri( + defaultExchangeBaseUrl = s.exchangeBaseUrl, + currency = s.currency, + amount = amount, + possibleExchanges = s.possibleExchanges, + maxAmount = s.maxAmount, + wireFee = s.wireFee, + editableAmount = s.editableAmount, + ) + else -> return + } + + val uri = when(s) { + is WithdrawStatus.NeedsExchange -> s.talerWithdrawUri + is WithdrawStatus.NeedsAmount -> s.talerWithdrawUri + is ReceivedDetails -> s.talerWithdrawUri + is WithdrawStatus.TosReviewRequired -> s.talerWithdrawUri + else -> return + } + + if (details.defaultExchangeBaseUrl == null) { + if (uri != null) { + withdrawStatus.value = WithdrawStatus.NeedsExchange( + talerWithdrawUri = uri, + currency = details.currency, + amount = amount, + possibleExchanges = details.possibleExchanges, + maxAmount = details.maxAmount, + wireFee = details.wireFee, + editableAmount = details.editableAmount + ) + } } else getWithdrawalDetails( - exchangeBaseUrl = s.defaultExchangeBaseUrl, + exchangeBaseUrl = details.defaultExchangeBaseUrl, + currency = details.currency, amount = amount, + maxAmount = details.maxAmount, + wireFee = details.wireFee, + editableAmount = details.editableAmount, showTosImmediately = false, - uri = s.talerWithdrawUri, - possibleExchanges = s.possibleExchanges, + uri = uri, + possibleExchanges =details.possibleExchanges, ) } @@ -316,10 +413,14 @@ class WithdrawManager( private fun getExchangeTos( exchangeBaseUrl: String, + currency: String, details: ManualWithdrawalDetails, showImmediately: Boolean, uri: String?, possibleExchanges: List<ExchangeItem>, + maxAmount: Amount?, + wireFee: Amount?, + editableAmount: Boolean, ) = scope.launch { api.request("getExchangeTos", TosResponse.serializer()) { put("exchangeBaseUrl", exchangeBaseUrl) @@ -329,6 +430,7 @@ class WithdrawManager( withdrawStatus.value = WithdrawStatus.TosReviewRequired( talerWithdrawUri = uri, exchangeBaseUrl = exchangeBaseUrl, + currency = currency, amountRaw = details.amountRaw, amountEffective = details.amountEffective, withdrawalAccountList = details.withdrawalAccountsList, @@ -337,6 +439,9 @@ class WithdrawManager( tosEtag = it.currentEtag, showImmediately = showImmediately.toEvent(), possibleExchanges = possibleExchanges, + maxAmount = maxAmount, + wireFee = wireFee, + editableAmount = editableAmount, ) } } @@ -354,12 +459,16 @@ class WithdrawManager( }.onSuccess { withdrawStatus.value = ReceivedDetails( talerWithdrawUri = s.talerWithdrawUri, + currency = s.currency, exchangeBaseUrl = s.exchangeBaseUrl, amountRaw = s.amountRaw, amountEffective = s.amountEffective, withdrawalAccountList = s.withdrawalAccountList, ageRestrictionOptions = s.ageRestrictionOptions, possibleExchanges = s.possibleExchanges, + maxAmount = s.maxAmount, + wireFee = s.wireFee, + editableAmount = s.editableAmount, ) } } diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/manual/ManualWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/manual/ManualWithdrawFragment.kt @@ -91,7 +91,11 @@ class ManualWithdrawFragment : Fragment() { } ui.amountView.hideKeyboard() - withdrawManager.getWithdrawalDetails(exchangeItem.exchangeBaseUrl, amount) + withdrawManager.getWithdrawalDetails( + exchangeBaseUrl = exchangeItem.exchangeBaseUrl, + currency = currency, + amount = amount, + ) findNavController().navigate(R.id.action_nav_exchange_manual_withdrawal_to_promptWithdraw) } diff --git a/wallet/src/main/res/layout/fragment_prompt_withdraw.xml b/wallet/src/main/res/layout/fragment_prompt_withdraw.xml @@ -41,7 +41,7 @@ <TextView android:id="@+id/chosenAmountView" - android:layout_width="0dp" + android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="8dp" @@ -56,6 +56,22 @@ tools:text="10 TESTKUDOS" tools:visibility="visible" /> + <ImageButton + android:id="@+id/selectAmountButton" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_marginEnd="16dp" + android:backgroundTint="@color/colorPrimary" + android:contentDescription="@string/nav_exchange_fees" + android:src="@drawable/ic_edit" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="@+id/chosenAmountView" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/chosenAmountView" + app:layout_constraintTop_toTopOf="@+id/chosenAmountView" + app:tint="?attr/colorOnPrimary" + tools:visibility="visible" /> + <TextView android:id="@+id/feeLabel" android:layout_width="0dp" diff --git a/wallet/src/main/res/navigation/nav_graph.xml b/wallet/src/main/res/navigation/nav_graph.xml @@ -343,8 +343,7 @@ android:label="@string/withdraw_title"> <action android:id="@+id/action_withdrawAmount_to_promptWithdraw" - app:destination="@id/promptWithdraw" - app:popUpTo="@id/nav_main"/> + app:destination="@id/promptWithdraw"/> </fragment> <fragment @@ -360,6 +359,9 @@ app:destination="@id/nav_main" app:popUpTo="@id/nav_main" /> <action + android:id="@+id/action_promptWithdraw_to_withdrawAmount" + app:destination="@id/withdrawAmount" /> + <action android:id="@+id/action_promptWithdraw_to_nav_exchange_manual_withdrawal_success" app:destination="@id/nav_exchange_manual_withdrawal_success" app:popUpTo="@id/nav_main" /> @@ -409,6 +411,11 @@ app:destination="@id/sendFunds" /> <action + android:id="@+id/action_handleUri_to_promptWithdraw" + app:destination="@id/promptWithdraw" + app:popUpTo="@id/nav_main" /> + + <action android:id="@+id/action_global_promptPayment" app:destination="@id/promptPayment" />