gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-android] 01/02: [wallet] implement exchange selection for w


From: gnunet
Subject: [taler-taler-android] 01/02: [wallet] implement exchange selection for withdrawals
Date: Mon, 28 Sep 2020 19:46:58 +0200

This is an automated email from the git hooks/post-receive script.

torsten-grote pushed a commit to branch master
in repository taler-android.

commit 0936fc851232c8c6c41ce4a0c479ba7a1e452137
Author: Torsten Grote <t@grobox.de>
AuthorDate: Mon Sep 28 12:12:20 2020 -0300

    [wallet] implement exchange selection for withdrawals
---
 .idea/codeStyles/Project.xml                       |   1 +
 build.gradle                                       |   2 +-
 .../src/main/java/net/taler/common/Event.kt        |   4 +
 wallet/build.gradle                                |   2 +-
 .../net/taler/wallet/exchanges/ExchangeAdapter.kt  |  17 ++-
 ...ExchangeFragment.kt => ExchangeFeesFragment.kt} |  11 +-
 .../taler/wallet/exchanges/ExchangeListFragment.kt |  20 +--
 .../wallet/exchanges/SelectExchangeFragment.kt     | 135 +++------------------
 .../wallet/withdraw/PromptWithdrawFragment.kt      |  88 +++++++++-----
 .../net/taler/wallet/withdraw/WithdrawManager.kt   |  52 +++++---
 ...ect_exchange.xml => fragment_exchange_fees.xml} |   0
 .../main/res/layout/fragment_prompt_withdraw.xml   |   2 +-
 wallet/src/main/res/navigation/nav_graph.xml       |   4 +-
 wallet/src/main/res/values/strings.xml             |   1 +
 14 files changed, 158 insertions(+), 181 deletions(-)

diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index b23c749..587f132 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -17,6 +17,7 @@
       </option>
       <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
       <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" 
value="2147483647" />
+      <option name="ALLOW_TRAILING_COMMA" value="true" />
       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
     </JetCodeStyleSettings>
     <codeStyleSettings language="XML">
diff --git a/build.gradle b/build.gradle
index 8973530..7f12ed4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
 buildscript {
-    ext.kotlin_version = '1.4.0'
+    ext.kotlin_version = '1.4.10'
     ext.ktor_version = "1.4.0"
     ext.nav_version = "2.3.0"
     ext.material_version = "1.2.1"
diff --git a/taler-kotlin-android/src/main/java/net/taler/common/Event.kt 
b/taler-kotlin-android/src/main/java/net/taler/common/Event.kt
index 779247f..752e20e 100644
--- a/taler-kotlin-android/src/main/java/net/taler/common/Event.kt
+++ b/taler-kotlin-android/src/main/java/net/taler/common/Event.kt
@@ -34,6 +34,10 @@ open class Event<out T>(private val content: T) {
         return if (isConsumed.compareAndSet(false, true)) content else null
     }
 
+    fun getEvenIfConsumedAlready(): T {
+        return content
+    }
+
 }
 
 fun <T> T.toEvent() = Event(this)
diff --git a/wallet/build.gradle b/wallet/build.gradle
index 02123ee..48e1749 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -139,7 +139,7 @@ dependencies {
     implementation 'me.zhanghai.android.materialprogressbar:library:1.6.1'
 
     // Markdown rendering
-    final def markwon_version = '4.5.1'
+    final def markwon_version = '4.6.0'
     implementation "io.noties.markwon:core:$markwon_version"
     implementation "io.noties.markwon:ext-tables:$markwon_version"
     implementation "io.noties.markwon:recycler:$markwon_version"
diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt 
b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt
index 17ac50f..e315632 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt
@@ -18,6 +18,8 @@ package net.taler.wallet.exchanges
 
 import android.view.LayoutInflater
 import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
 import android.view.ViewGroup
 import android.widget.ImageButton
 import android.widget.TextView
@@ -39,11 +41,14 @@ data class ExchangeItem(
 }
 
 interface ExchangeClickListener {
+    fun onExchangeSelected(item: ExchangeItem)
     fun onManualWithdraw(item: ExchangeItem)
 }
 
-internal class ExchangeAdapter(private val listener: ExchangeClickListener) :
-    Adapter<ExchangeItemViewHolder>() {
+internal class ExchangeAdapter(
+    private val selectOnly: Boolean,
+    private val listener: ExchangeClickListener,
+) : Adapter<ExchangeItemViewHolder>() {
 
     private val items = ArrayList<ExchangeItem>()
 
@@ -74,6 +79,14 @@ internal class ExchangeAdapter(private val listener: 
ExchangeClickListener) :
         fun bind(item: ExchangeItem) {
             urlView.text = item.name
             currencyView.text = 
context.getString(R.string.exchange_list_currency, item.currency)
+            if (selectOnly) {
+                itemView.setOnClickListener { 
listener.onExchangeSelected(item) }
+                overflowIcon.visibility = GONE
+            } else {
+                itemView.setOnClickListener(null)
+                itemView.isClickable = false
+                overflowIcon.visibility = VISIBLE
+            }
             overflowIcon.setOnClickListener { openMenu(overflowIcon, item) }
         }
 
diff --git 
a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt 
b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFeesFragment.kt
similarity index 95%
copy from 
wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
copy to wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFeesFragment.kt
index a95a51c..c59fffe 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFeesFragment.kt
@@ -32,22 +32,23 @@ import net.taler.common.toShortDate
 import net.taler.lib.common.Amount
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
-import net.taler.wallet.databinding.FragmentSelectExchangeBinding
+import net.taler.wallet.databinding.FragmentExchangeFeesBinding
 import net.taler.wallet.exchanges.CoinFeeAdapter.CoinFeeViewHolder
 import net.taler.wallet.exchanges.WireFeeAdapter.WireFeeViewHolder
 
-class SelectExchangeFragment : Fragment() {
+class ExchangeFeesFragment : Fragment() {
 
     private val model: MainViewModel by activityViewModels()
     private val withdrawManager by lazy { model.withdrawManager }
 
-    private lateinit var ui: FragmentSelectExchangeBinding
+    private lateinit var ui: FragmentExchangeFeesBinding
 
     override fun onCreateView(
-        inflater: LayoutInflater, container: ViewGroup?,
+        inflater: LayoutInflater,
+        container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        ui = FragmentSelectExchangeBinding.inflate(inflater, container, false)
+        ui = FragmentExchangeFeesBinding.inflate(inflater, container, false)
         return ui.root
     }
 
diff --git 
a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt 
b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt
index 86b2519..9a96b59 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt
@@ -34,17 +34,19 @@ import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
 import net.taler.wallet.databinding.FragmentExchangeListBinding
 
-class ExchangeListFragment : Fragment(), ExchangeClickListener {
+open class ExchangeListFragment : Fragment(), ExchangeClickListener {
 
-    private val model: MainViewModel by activityViewModels()
+    protected val model: MainViewModel by activityViewModels()
     private val exchangeManager by lazy { model.exchangeManager }
 
-    private lateinit var ui: FragmentExchangeListBinding
-    private val exchangeAdapter by lazy { ExchangeAdapter(this) }
+    protected lateinit var ui: FragmentExchangeListBinding
+    protected open val isSelectOnly = false
+    private val exchangeAdapter by lazy { ExchangeAdapter(isSelectOnly, this) }
 
     override fun onCreateView(
-        inflater: LayoutInflater, container: ViewGroup?,
-        savedInstanceState: Bundle?
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?,
     ): View? {
         ui = FragmentExchangeListBinding.inflate(inflater, container, false)
         return ui.root
@@ -70,7 +72,7 @@ class ExchangeListFragment : Fragment(), 
ExchangeClickListener {
         })
     }
 
-    private fun onExchangeUpdate(exchanges: List<ExchangeItem>) {
+    protected open fun onExchangeUpdate(exchanges: List<ExchangeItem>) {
         exchangeAdapter.update(exchanges)
         if (exchanges.isEmpty()) {
             ui.emptyState.fadeIn()
@@ -85,6 +87,10 @@ class ExchangeListFragment : Fragment(), 
ExchangeClickListener {
         Toast.makeText(requireContext(), R.string.exchange_add_error, 
LENGTH_LONG).show()
     }
 
+    override fun onExchangeSelected(item: ExchangeItem) {
+        throw AssertionError("must not get triggered here")
+    }
+
     override fun onManualWithdraw(item: ExchangeItem) {
         exchangeManager.withdrawalExchange = item
         
findNavController().navigate(R.id.action_nav_settings_exchanges_to_nav_exchange_manual_withdrawal)
diff --git 
a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt 
b/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
index a95a51c..61e0db5 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
@@ -16,130 +16,33 @@
 
 package net.taler.wallet.exchanges
 
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.View.GONE
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.core.content.ContextCompat.getColor
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.activityViewModels
-import androidx.recyclerview.widget.RecyclerView.Adapter
-import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import net.taler.common.toRelativeTime
-import net.taler.common.toShortDate
-import net.taler.lib.common.Amount
-import net.taler.wallet.MainViewModel
-import net.taler.wallet.R
-import net.taler.wallet.databinding.FragmentSelectExchangeBinding
-import net.taler.wallet.exchanges.CoinFeeAdapter.CoinFeeViewHolder
-import net.taler.wallet.exchanges.WireFeeAdapter.WireFeeViewHolder
+import androidx.navigation.fragment.findNavController
+import net.taler.common.fadeOut
 
-class SelectExchangeFragment : Fragment() {
+class SelectExchangeFragment : ExchangeListFragment() {
 
-    private val model: MainViewModel by activityViewModels()
     private val withdrawManager by lazy { model.withdrawManager }
 
-    private lateinit var ui: FragmentSelectExchangeBinding
-
-    override fun onCreateView(
-        inflater: LayoutInflater, container: ViewGroup?,
-        savedInstanceState: Bundle?
-    ): View? {
-        ui = FragmentSelectExchangeBinding.inflate(inflater, container, false)
-        return ui.root
-    }
-
-    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        val fees = withdrawManager.exchangeFees ?: throw 
IllegalStateException()
-        if (fees.withdrawFee.isZero()) {
-            ui.withdrawFeeLabel.visibility = GONE
-            ui.withdrawFeeView.visibility = GONE
-        } else ui.withdrawFeeView.setAmount(fees.withdrawFee)
-        if (fees.overhead.isZero()) {
-            ui.overheadLabel.visibility = GONE
-            ui.overheadView.visibility = GONE
-        } else ui.overheadView.setAmount(fees.overhead)
-        ui.expirationView.text = 
fees.earliestDepositExpiration.ms.toRelativeTime(requireContext())
-        ui.coinFeesList.adapter = CoinFeeAdapter(fees.coinFees)
-        ui.wireFeesList.adapter = WireFeeAdapter(fees.wireFees)
-    }
-
-    private fun TextView.setAmount(amount: Amount) {
-        if (amount.isZero()) text = amount.toString()
-        else {
-            text = getString(R.string.amount_negative, amount)
-            setTextColor(getColor(context, R.color.red))
-        }
+    override val isSelectOnly = true
+    private val exchangeSelection by lazy {
+        
requireNotNull(withdrawManager.exchangeSelection.value?.getEvenIfConsumedAlready())
     }
 
-}
-
-private class CoinFeeAdapter(private val items: List<CoinFee>) : 
Adapter<CoinFeeViewHolder>() {
-    override fun getItemCount() = items.size
-    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): 
CoinFeeViewHolder {
-        val v =
-            
LayoutInflater.from(parent.context).inflate(R.layout.list_item_coin_fee, 
parent, false)
-        return CoinFeeViewHolder(v)
+    override fun onExchangeUpdate(exchanges: List<ExchangeItem>) {
+        ui.progressBar.fadeOut()
+        super.onExchangeUpdate(exchanges.filter { exchangeItem ->
+            exchangeItem.currency == exchangeSelection.amount.currency
+        })
     }
 
-    override fun onBindViewHolder(holder: CoinFeeViewHolder, position: Int) {
-        holder.bind(items[position])
+    override fun onExchangeSelected(item: ExchangeItem) {
+        withdrawManager.getWithdrawalDetails(
+            exchangeBaseUrl = item.exchangeBaseUrl,
+            amount = exchangeSelection.amount,
+            showTosImmediately = true,
+            uri = exchangeSelection.talerWithdrawUri,
+        )
+        findNavController().navigateUp()
     }
 
-    private class CoinFeeViewHolder(private val v: View) : ViewHolder(v) {
-        private val res = v.context.resources
-        private val coinView: TextView = v.findViewById(R.id.coinView)
-        private val withdrawFeeView: TextView = 
v.findViewById(R.id.withdrawFeeView)
-        private val depositFeeView: TextView = 
v.findViewById(R.id.depositFeeView)
-        private val refreshFeeView: TextView = 
v.findViewById(R.id.refreshFeeView)
-        private val refundFeeView: TextView = 
v.findViewById(R.id.refundFeeView)
-        fun bind(item: CoinFee) {
-            coinView.text = res.getQuantityString(
-                R.plurals.exchange_fee_coin,
-                item.quantity,
-                item.coin,
-                item.quantity
-            )
-            withdrawFeeView.text =
-                v.context.getString(R.string.exchange_fee_withdraw_fee, 
item.feeWithdraw)
-            depositFeeView.text =
-                v.context.getString(R.string.exchange_fee_deposit_fee, 
item.feeDeposit)
-            refreshFeeView.text =
-                v.context.getString(R.string.exchange_fee_refresh_fee, 
item.feeRefresh)
-            refundFeeView.text =
-                v.context.getString(R.string.exchange_fee_refund_fee, 
item.feeRefresh)
-        }
-    }
-}
-
-private class WireFeeAdapter(private val items: List<WireFee>) : 
Adapter<WireFeeViewHolder>() {
-    override fun getItemCount() = items.size
-    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): 
WireFeeViewHolder {
-        val v =
-            
LayoutInflater.from(parent.context).inflate(R.layout.list_item_wire_fee, 
parent, false)
-        return WireFeeViewHolder(v)
-    }
-
-    override fun onBindViewHolder(holder: WireFeeViewHolder, position: Int) {
-        holder.bind(items[position])
-    }
-
-    private class WireFeeViewHolder(private val v: View) : ViewHolder(v) {
-        private val validityView: TextView = v.findViewById(R.id.validityView)
-        private val wireFeeView: TextView = v.findViewById(R.id.wireFeeView)
-        private val closingFeeView: TextView = 
v.findViewById(R.id.closingFeeView)
-        fun bind(item: WireFee) {
-            validityView.text = v.context.getString(
-                R.string.exchange_fee_wire_fee_timespan,
-                item.start.ms.toShortDate(v.context),
-                item.end.ms.toShortDate(v.context)
-            )
-            wireFeeView.text =
-                v.context.getString(R.string.exchange_fee_wire_fee_wire_fee, 
item.wireFee)
-            closingFeeView.text =
-                
v.context.getString(R.string.exchange_fee_wire_fee_closing_fee, item.closingFee)
-        }
-    }
 }
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)
             }
diff --git a/wallet/src/main/res/layout/fragment_select_exchange.xml 
b/wallet/src/main/res/layout/fragment_exchange_fees.xml
similarity index 100%
rename from wallet/src/main/res/layout/fragment_select_exchange.xml
rename to wallet/src/main/res/layout/fragment_exchange_fees.xml
diff --git a/wallet/src/main/res/layout/fragment_prompt_withdraw.xml 
b/wallet/src/main/res/layout/fragment_prompt_withdraw.xml
index 6bca4ef..421911a 100644
--- a/wallet/src/main/res/layout/fragment_prompt_withdraw.xml
+++ b/wallet/src/main/res/layout/fragment_prompt_withdraw.xml
@@ -169,7 +169,7 @@
         android:contentDescription="@string/nav_exchange_fees"
         android:src="@drawable/ic_edit"
         android:tint="?attr/colorOnPrimary"
-        android:visibility="invisible"
+        android:visibility="gone"
         app:layout_constraintBottom_toBottomOf="@+id/withdrawExchangeUrl"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toEndOf="@+id/withdrawExchangeUrl"
diff --git a/wallet/src/main/res/navigation/nav_graph.xml 
b/wallet/src/main/res/navigation/nav_graph.xml
index d8ce5b2..cf98b95 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -152,8 +152,8 @@
     <fragment
         android:id="@+id/selectExchangeFragment"
         android:name="net.taler.wallet.exchanges.SelectExchangeFragment"
-        android:label="@string/nav_exchange_fees"
-        tools:layout="@layout/fragment_select_exchange" />
+        android:label="@string/nav_exchange_select"
+        tools:layout="@layout/fragment_exchange_list" />
 
     <fragment
         android:id="@+id/nav_pending_operations"
diff --git a/wallet/src/main/res/values/strings.xml 
b/wallet/src/main/res/values/strings.xml
index 24db2b0..2e32c88 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -39,6 +39,7 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
 
     <string name="nav_prompt_withdraw">Withdraw Digital Cash</string>
     <string name="nav_exchange_tos">Exchange\'s Terms of Service</string>
+    <string name="nav_exchange_select">Select Exchange</string>
     <string name="nav_exchange_fees">Exchange Fees</string>
     <string name="nav_error">Error</string>
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]