gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-android] branch master updated (d604f8e -> da098a6)


From: gnunet
Subject: [taler-taler-android] branch master updated (d604f8e -> da098a6)
Date: Tue, 06 Feb 2024 14:01:20 +0100

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

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

    from d604f8e  [wallet] Improved amount input (better suited for DD51)
     new 8062b84  [wallet] List possibleExchanges in exchange selection for 
withdrawals
     new da098a6  [wallet] Replace exchange selection fragment with dialog 
decoupled from withdrawals

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../exchanges/SelectExchangeDialogFragment.kt      | 111 +++++++++++++++++++++
 .../wallet/exchanges/SelectExchangeFragment.kt     |  48 ---------
 .../wallet/withdraw/PromptWithdrawFragment.kt      |  64 ++++++++++--
 .../net/taler/wallet/withdraw/WithdrawManager.kt   |  36 +++----
 wallet/src/main/res/navigation/nav_graph.xml       |   9 --
 5 files changed, 183 insertions(+), 85 deletions(-)
 create mode 100644 
wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeDialogFragment.kt
 delete mode 100644 
wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt

diff --git 
a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeDialogFragment.kt
 
b/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeDialogFragment.kt
new file mode 100644
index 0000000..2da7618
--- /dev/null
+++ 
b/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeDialogFragment.kt
@@ -0,0 +1,111 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2024 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.exchanges
+
+import android.app.Dialog
+import android.os.Bundle
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material3.ListItem
+import androidx.compose.material3.ListItemDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.res.stringResource
+import androidx.fragment.app.DialogFragment
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.asFlow
+import com.google.accompanist.themeadapter.material3.Mdc3Theme
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import net.taler.common.Event
+import net.taler.common.toEvent
+import net.taler.wallet.R
+import net.taler.wallet.cleanExchange
+import net.taler.wallet.compose.collectAsStateLifecycleAware
+
+class SelectExchangeDialogFragment: DialogFragment() {
+    private var exchangeList = MutableLiveData<List<ExchangeItem>>()
+
+    private var mExchangeSelection = MutableLiveData<Event<ExchangeItem>>()
+    val exchangeSelection: LiveData<Event<ExchangeItem>> = mExchangeSelection
+
+    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+        val view = ComposeView(requireContext()).apply {
+            setContent {
+                val exchanges = 
exchangeList.asFlow().collectAsStateLifecycleAware(initial = emptyList())
+                SelectExchangeComposable(exchanges.value) {
+                    onExchangeSelected(it)
+                }
+            }
+        }
+
+        return MaterialAlertDialogBuilder(requireContext(), 
R.style.MaterialAlertDialog_Material3)
+            .setIcon(R.drawable.ic_account_balance)
+            .setTitle(R.string.exchange_list_add)
+            .setView(view)
+            .setNegativeButton(R.string.cancel) { _, _ ->
+                dismiss()
+            }
+            .create()
+    }
+
+    fun setExchanges(exchanges: List<ExchangeItem>) {
+        exchangeList.value = exchanges
+    }
+
+    private fun onExchangeSelected(exchange: ExchangeItem) {
+        mExchangeSelection.value = exchange.toEvent()
+        dismiss()
+    }
+}
+
+@Composable
+fun SelectExchangeComposable(
+    exchanges: List<ExchangeItem>,
+    onExchangeSelected: (exchange: ExchangeItem) -> Unit,
+) {
+    Mdc3Theme {
+        LazyColumn(
+            modifier = Modifier.fillMaxSize(),
+        ) {
+            items(exchanges) {
+                ExchangeItemComposable(it) {
+                    onExchangeSelected(it)
+                }
+            }
+        }
+    }
+}
+
+@Composable
+fun ExchangeItemComposable(exchange: ExchangeItem, onSelected: () -> Unit) {
+    ListItem(
+        modifier = Modifier.clickable { onSelected() },
+        headlineContent = { Text(cleanExchange(exchange.exchangeBaseUrl)) },
+        supportingContent = exchange.currency?.let {
+            { Text(stringResource(R.string.exchange_list_currency, it)) }
+        },
+        colors = ListItemDefaults.colors(
+            containerColor = Color.Transparent,
+        )
+    )
+}
\ No newline at end of file
diff --git 
a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt 
b/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
deleted file mode 100644
index 61e0db5..0000000
--- a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is part of GNU Taler
- * (C) 2020 Taler Systems S.A.
- *
- * GNU Taler is free software; you can redistribute it and/or modify it under 
the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 3, or (at your option) any later version.
- *
- * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
- * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-package net.taler.wallet.exchanges
-
-import androidx.navigation.fragment.findNavController
-import net.taler.common.fadeOut
-
-class SelectExchangeFragment : ExchangeListFragment() {
-
-    private val withdrawManager by lazy { model.withdrawManager }
-
-    override val isSelectOnly = true
-    private val exchangeSelection by lazy {
-        
requireNotNull(withdrawManager.exchangeSelection.value?.getEvenIfConsumedAlready())
-    }
-
-    override fun onExchangeUpdate(exchanges: List<ExchangeItem>) {
-        ui.progressBar.fadeOut()
-        super.onExchangeUpdate(exchanges.filter { exchangeItem ->
-            exchangeItem.currency == exchangeSelection.amount.currency
-        })
-    }
-
-    override fun onExchangeSelected(item: ExchangeItem) {
-        withdrawManager.getWithdrawalDetails(
-            exchangeBaseUrl = item.exchangeBaseUrl,
-            amount = exchangeSelection.amount,
-            showTosImmediately = true,
-            uri = exchangeSelection.talerWithdrawUri,
-        )
-        findNavController().navigateUp()
-    }
-
-}
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 caad7b6..16b956b 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
@@ -36,10 +36,13 @@ import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
 import net.taler.wallet.cleanExchange
 import net.taler.wallet.databinding.FragmentPromptWithdrawBinding
+import net.taler.wallet.exchanges.ExchangeItem
+import net.taler.wallet.exchanges.SelectExchangeDialogFragment
 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.NeedsExchange
 
 class PromptWithdrawFragment : Fragment() {
 
@@ -47,6 +50,8 @@ class PromptWithdrawFragment : Fragment() {
     private val withdrawManager by lazy { model.withdrawManager }
     private val transactionManager by lazy { model.transactionManager }
 
+    private val selectExchangeDialog = SelectExchangeDialogFragment()
+
     private lateinit var ui: FragmentPromptWithdrawBinding
 
     override fun onCreateView(
@@ -64,22 +69,20 @@ class PromptWithdrawFragment : Fragment() {
         withdrawManager.withdrawStatus.observe(viewLifecycleOwner) {
             showWithdrawStatus(it)
         }
-        withdrawManager.exchangeSelection.observe(viewLifecycleOwner, 
EventObserver {
-            
findNavController().navigate(R.id.action_promptWithdraw_to_selectExchangeFragment)
+
+        selectExchangeDialog.exchangeSelection.observe(viewLifecycleOwner, 
EventObserver {
+            onExchangeSelected(it)
         })
     }
 
     private fun showWithdrawStatus(status: WithdrawStatus?): Any = when 
(status) {
         null -> model.showProgressBar.value = false
         is Loading -> model.showProgressBar.value = true
-        is WithdrawStatus.NeedsExchange -> {
+        is NeedsExchange -> {
             model.showProgressBar.value = false
-            val exchangeSelection = status.exchangeSelection.getIfNotConsumed()
-            if (exchangeSelection == null) { // already consumed
-                findNavController().popBackStack()
-            } else {
-                withdrawManager.selectExchange(exchangeSelection)
-            }
+            if (selectExchangeDialog.dialog?.isShowing != true) {
+                selectExchange()
+            } else {}
         }
         is TosReviewRequired -> onTosReviewRequired(status)
         is ReceivedDetails -> onReceivedDetails(status)
@@ -178,8 +181,7 @@ class PromptWithdrawFragment : Fragment() {
         if (uri != null) {  // no Uri for manual withdrawals
             ui.selectExchangeButton.fadeIn()
             ui.selectExchangeButton.setOnClickListener {
-                val exchangeSelection = ExchangeSelection(amountRaw, uri)
-                withdrawManager.selectExchange(exchangeSelection)
+                selectExchange()
             }
         }
 
@@ -195,4 +197,44 @@ class PromptWithdrawFragment : Fragment() {
         ui.withdrawCard.fadeIn()
     }
 
+    private fun selectExchange() {
+        val exchanges = when (val status = 
withdrawManager.withdrawStatus.value) {
+            is ReceivedDetails -> status.possibleExchanges
+            is NeedsExchange -> status.possibleExchanges
+            is TosReviewRequired -> status.possibleExchanges
+            else -> return
+        }
+        selectExchangeDialog.setExchanges(exchanges)
+        selectExchangeDialog.show(parentFragmentManager, "SELECT_EXCHANGE")
+    }
+
+    private fun onExchangeSelected(exchange: ExchangeItem) {
+        val status = withdrawManager.withdrawStatus.value
+        val amount = when (status) {
+            is ReceivedDetails -> status.amountRaw
+            is NeedsExchange -> status.amount
+            is TosReviewRequired -> status.amountRaw
+            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
+            is TosReviewRequired -> status.possibleExchanges
+            else -> return
+        }
+
+        withdrawManager.getWithdrawalDetails(
+            exchangeBaseUrl = exchange.exchangeBaseUrl,
+            amount = amount,
+            showTosImmediately = false,
+            uri = uri,
+            possibleExchanges = exchanges,
+        )
+    }
 }
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 ceae7e1..6e8eafd 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
@@ -20,7 +20,6 @@ import android.net.Uri
 import android.util.Log
 import androidx.annotation.UiThread
 import androidx.annotation.WorkerThread
-import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
@@ -40,7 +39,11 @@ 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 NeedsExchange(
+        val talerWithdrawUri: String,
+        val amount: Amount,
+        val possibleExchanges: List<ExchangeItem>,
+    ) : WithdrawStatus()
 
     data class TosReviewRequired(
         val talerWithdrawUri: String? = null,
@@ -52,6 +55,7 @@ sealed class WithdrawStatus {
         val tosText: String,
         val tosEtag: String,
         val showImmediately: Event<Boolean>,
+        val possibleExchanges: List<ExchangeItem> = emptyList(),
     ) : WithdrawStatus()
 
     data class ReceivedDetails(
@@ -61,6 +65,7 @@ sealed class WithdrawStatus {
         val amountEffective: Amount,
         val withdrawalAccountList: List<WithdrawalExchangeAccountDetails>,
         val ageRestrictionOptions: List<Int>? = null,
+        val possibleExchanges: List<ExchangeItem> = emptyList(),
     ) : WithdrawStatus()
 
     data object Withdrawing : WithdrawStatus()
@@ -144,11 +149,6 @@ data class AcceptManualWithdrawalResponse(
     val transactionId: String,
 )
 
-data class ExchangeSelection(
-    val amount: Amount,
-    val talerWithdrawUri: String,
-)
-
 class WithdrawManager(
     private val api: WalletBackendApi,
     private val scope: CoroutineScope,
@@ -157,8 +157,6 @@ class WithdrawManager(
     val withdrawStatus = MutableLiveData<WithdrawStatus>()
     val testWithdrawalStatus = MutableLiveData<WithdrawTestStatus>()
 
-    private val _exchangeSelection = 
MutableLiveData<Event<ExchangeSelection>>()
-    val exchangeSelection: LiveData<Event<ExchangeSelection>> = 
_exchangeSelection
     var exchangeFees: ExchangeFees? = null
         private set
 
@@ -171,11 +169,6 @@ 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()) {
@@ -184,13 +177,17 @@ class WithdrawManager(
             handleError("getWithdrawalDetailsForUri", error)
         }.onSuccess { details ->
             if (details.defaultExchangeBaseUrl == null) {
-                val exchangeSelection = ExchangeSelection(details.amount, uri)
-                withdrawStatus.value = 
WithdrawStatus.NeedsExchange(exchangeSelection.toEvent())
+                withdrawStatus.value = WithdrawStatus.NeedsExchange(
+                    talerWithdrawUri = uri,
+                    amount = details.amount,
+                    possibleExchanges = details.possibleExchanges,
+                )
             } else getWithdrawalDetails(
                 exchangeBaseUrl = details.defaultExchangeBaseUrl,
                 amount = details.amount,
                 showTosImmediately = false,
                 uri = uri,
+                possibleExchanges = details.possibleExchanges,
             )
         }
     }
@@ -200,6 +197,7 @@ class WithdrawManager(
         amount: Amount,
         showTosImmediately: Boolean = false,
         uri: String? = null,
+        possibleExchanges: List<ExchangeItem> = emptyList(),
     ) = scope.launch {
         withdrawStatus.value = WithdrawStatus.Loading(uri)
         api.request("getWithdrawalDetailsForAmount", 
ManualWithdrawalDetails.serializer()) {
@@ -216,8 +214,9 @@ class WithdrawManager(
                     amountEffective = details.amountEffective,
                     withdrawalAccountList = details.withdrawalAccountsList,
                     ageRestrictionOptions = details.ageRestrictionOptions,
+                    possibleExchanges = possibleExchanges,
                 )
-            } else getExchangeTos(exchangeBaseUrl, details, 
showTosImmediately, uri)
+            } else getExchangeTos(exchangeBaseUrl, details, 
showTosImmediately, uri, possibleExchanges)
         }
     }
 
@@ -240,6 +239,7 @@ class WithdrawManager(
         details: ManualWithdrawalDetails,
         showImmediately: Boolean,
         uri: String?,
+        possibleExchanges: List<ExchangeItem>,
     ) = scope.launch {
         api.request("getExchangeTos", TosResponse.serializer()) {
             put("exchangeBaseUrl", exchangeBaseUrl)
@@ -256,6 +256,7 @@ class WithdrawManager(
                 tosText = it.content,
                 tosEtag = it.currentEtag,
                 showImmediately = showImmediately.toEvent(),
+                possibleExchanges = possibleExchanges,
             )
         }
     }
@@ -278,6 +279,7 @@ class WithdrawManager(
                 amountEffective = s.amountEffective,
                 withdrawalAccountList = s.withdrawalAccountList,
                 ageRestrictionOptions = s.ageRestrictionOptions,
+                possibleExchanges = s.possibleExchanges,
             )
         }
     }
diff --git a/wallet/src/main/res/navigation/nav_graph.xml 
b/wallet/src/main/res/navigation/nav_graph.xml
index 8c1010c..24def7f 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -300,9 +300,6 @@
         android:name="net.taler.wallet.withdraw.PromptWithdrawFragment"
         android:label="@string/nav_prompt_withdraw"
         tools:layout="@layout/fragment_prompt_withdraw">
-        <action
-            android:id="@+id/action_promptWithdraw_to_selectExchangeFragment"
-            app:destination="@id/selectExchangeFragment" />
         <action
             android:id="@+id/action_promptWithdraw_to_reviewExchangeTOS"
             app:destination="@id/reviewExchangeTOS" />
@@ -334,12 +331,6 @@
             app:destination="@id/promptWithdraw"
             app:popUpTo="@id/nav_main" />
     </fragment>
-    <fragment
-        android:id="@+id/selectExchangeFragment"
-        android:name="net.taler.wallet.exchanges.SelectExchangeFragment"
-        android:label="@string/nav_exchange_select"
-        tools:layout="@layout/fragment_exchange_list" />
-
     <fragment
         android:id="@+id/nav_pending_operations"
         android:name="net.taler.wallet.pending.PendingOperationsFragment"

-- 
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]