gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-android] 06/12: [wallet] Refactor p2p payments to show tx d


From: gnunet
Subject: [taler-taler-android] 06/12: [wallet] Refactor p2p payments to show tx details when ready
Date: Mon, 08 Jan 2024 21:58:39 +0100

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 f52100135f5784fe81b0377a0034faab17d543df
Author: Iván Ávalos <avalos@disroot.org>
AuthorDate: Tue Jan 2 13:39:41 2024 -0600

    [wallet] Refactor p2p payments to show tx details when ready
---
 ...ntroComposable.kt => OutgoingPullComposable.kt} | 128 ++++++++++++++++--
 .../net/taler/wallet/peer/OutgoingPullFragment.kt  |  46 ++++---
 .../wallet/peer/OutgoingPullResultComposable.kt    | 150 ---------------------
 ...ntroComposable.kt => OutgoingPushComposable.kt} |  75 ++++++++++-
 .../net/taler/wallet/peer/OutgoingPushFragment.kt  |  45 ++++---
 .../wallet/peer/OutgoingPushResultComposable.kt    | 150 ---------------------
 .../java/net/taler/wallet/peer/OutgoingState.kt    |  12 +-
 .../main/java/net/taler/wallet/peer/PeerManager.kt |   8 +-
 .../taler/wallet/peer/TransactionPeerPushDebit.kt  |   2 +-
 .../net/taler/wallet/transactions/Transactions.kt  |   5 +-
 wallet/src/main/res/navigation/nav_graph.xml       |   8 ++
 11 files changed, 258 insertions(+), 371 deletions(-)

diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt
similarity index 64%
rename from 
wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt
rename to wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt
index 92bc72e..8efa64c 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt
@@ -16,12 +16,16 @@
 
 package net.taler.wallet.peer
 
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.Surface
@@ -33,6 +37,7 @@ import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment.Companion.Center
 import androidx.compose.ui.Alignment.Companion.CenterHorizontally
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusRequester
@@ -42,8 +47,11 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
+import kotlinx.serialization.json.JsonPrimitive
 import net.taler.common.Amount
 import net.taler.wallet.R
+import net.taler.wallet.backend.TalerErrorCode
+import net.taler.wallet.backend.TalerErrorInfo
 import net.taler.wallet.cleanExchange
 import net.taler.wallet.exchanges.ExchangeItem
 import net.taler.wallet.transactions.AmountType
@@ -51,6 +59,38 @@ import 
net.taler.wallet.transactions.TransactionAmountComposable
 import net.taler.wallet.transactions.TransactionInfoComposable
 import kotlin.random.Random
 
+@Composable
+fun OutgoingPullComposable(
+    amount: Amount,
+    state: OutgoingState,
+    onCreateInvoice: (amount: Amount, subject: String, hours: Long, exchange: 
ExchangeItem) -> Unit,
+    onClose: () -> Unit,
+) {
+    when(state) {
+        is OutgoingChecking, is OutgoingCreating, is OutgoingResponse -> 
PeerCreatingComposable()
+        is OutgoingIntro, is OutgoingChecked -> OutgoingPullIntroComposable(
+            amount = amount,
+            state = state,
+            onCreateInvoice = onCreateInvoice,
+        )
+        is OutgoingError -> PeerErrorComposable(state, onClose)
+    }
+}
+
+@Composable
+fun PeerCreatingComposable() {
+    Box(
+        modifier = Modifier
+            .fillMaxSize(),
+    ) {
+        CircularProgressIndicator(
+            modifier = Modifier
+                .padding(32.dp)
+                .align(Center),
+        )
+    }
+}
+
 @Composable
 fun OutgoingPullIntroComposable(
     amount: Amount,
@@ -67,6 +107,7 @@ fun OutgoingPullIntroComposable(
     ) {
         var subject by rememberSaveable { mutableStateOf("") }
         val focusRequester = remember { FocusRequester() }
+
         OutlinedTextField(
             modifier = Modifier
                 .fillMaxWidth()
@@ -87,9 +128,11 @@ fun OutgoingPullIntroComposable(
                 )
             }
         )
+
         LaunchedEffect(Unit) {
             focusRequester.requestFocus()
         }
+
         Text(
             modifier = Modifier
                 .fillMaxWidth()
@@ -98,11 +141,13 @@ fun OutgoingPullIntroComposable(
             text = stringResource(R.string.char_count, subject.length, 
MAX_LENGTH_SUBJECT),
             textAlign = TextAlign.End,
         )
+
         TransactionAmountComposable(
             label = stringResource(id = R.string.amount_chosen),
             amount = amount,
             amountType = AmountType.Positive,
         )
+
         if (state is OutgoingChecked) {
             val fee = state.amountRaw - state.amountEffective
             if (!fee.isZero()) TransactionAmountComposable(
@@ -111,16 +156,19 @@ fun OutgoingPullIntroComposable(
                 amountType = AmountType.Negative,
             )
         }
+
         val exchangeItem = (state as? OutgoingChecked)?.exchangeItem
         TransactionInfoComposable(
             label = stringResource(id = R.string.withdraw_exchange),
             info = if (exchangeItem == null) "" else 
cleanExchange(exchangeItem.exchangeBaseUrl),
         )
+
         Text(
             modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 
16.dp),
             text = stringResource(R.string.send_peer_expiration_period),
             style = MaterialTheme.typography.bodyMedium,
         )
+
         var option by rememberSaveable { mutableStateOf(DEFAULT_EXPIRY) }
         var hours by rememberSaveable { mutableStateOf(DEFAULT_EXPIRY.hours) }
         ExpirationComposable(
@@ -129,6 +177,7 @@ fun OutgoingPullIntroComposable(
             hours = hours,
             onOptionChange = { option = it }
         ) { hours = it }
+
         Button(
             modifier = Modifier.padding(16.dp),
             enabled = subject.isNotBlank() && state is OutgoingChecked,
@@ -146,27 +195,86 @@ fun OutgoingPullIntroComposable(
     }
 }
 
+@Composable
+fun PeerErrorComposable(state: OutgoingError, onClose: () -> Unit) {
+    Column(
+        modifier = Modifier
+            .padding(16.dp)
+            .fillMaxWidth(),
+        horizontalAlignment = CenterHorizontally,
+    ) {
+        Text(
+            color = MaterialTheme.colorScheme.error,
+            style = MaterialTheme.typography.bodyLarge,
+            text = state.info.userFacingMsg,
+        )
+
+        Button(
+            modifier = Modifier.padding(16.dp),
+            onClick = onClose,
+            colors = ButtonDefaults.buttonColors(
+                containerColor = MaterialTheme.colorScheme.error,
+                contentColor = MaterialTheme.colorScheme.onError,
+            ),
+        ) {
+            Text(text = stringResource(R.string.close))
+        }
+    }
+}
+
 @Preview
 @Composable
-fun PreviewReceiveFundsCheckingIntro() {
+fun PeerPullComposableCreatingPreview() {
     Surface {
-        OutgoingPullIntroComposable(
-            Amount.fromString("TESTKUDOS", "42.23"),
-            if (Random.nextBoolean()) OutgoingIntro else OutgoingChecking,
-        ) { _, _, _, _ -> }
+        OutgoingPullComposable(
+            amount = Amount.fromString("TESTKUDOS", "42.23"),
+            state = OutgoingCreating,
+            onCreateInvoice = { _, _, _, _ -> },
+            onClose = {},
+        )
     }
 }
 
 @Preview
 @Composable
-fun PreviewReceiveFundsCheckedIntro() {
+fun PeerPullComposableCheckingPreview() {
+    Surface {
+        OutgoingPullComposable(
+            amount = Amount.fromString("TESTKUDOS", "42.23"),
+            state = if (Random.nextBoolean()) OutgoingIntro else 
OutgoingChecking,
+            onCreateInvoice = { _, _, _, _ -> },
+            onClose = {},
+        )
+    }
+}
+
+@Preview
+@Composable
+fun PeerPullComposableCheckedPreview() {
     Surface {
         val amountRaw = Amount.fromString("TESTKUDOS", "42.42")
         val amountEffective = Amount.fromString("TESTKUDOS", "42.23")
         val exchangeItem = ExchangeItem("https://example.org";, "TESTKUDOS", 
emptyList())
-        OutgoingPullIntroComposable(
-            Amount.fromString("TESTKUDOS", "42.23"),
-            OutgoingChecked(amountRaw, amountEffective, exchangeItem)
-        ) { _, _, _, _ -> }
+        OutgoingPullComposable(
+            amount = Amount.fromString("TESTKUDOS", "42.23"),
+            state = OutgoingChecked(amountRaw, amountEffective, exchangeItem),
+            onCreateInvoice = { _, _, _, _ -> },
+            onClose = {},
+        )
     }
 }
+
+@Preview
+@Composable
+fun PeerPullComposableErrorPreview() {
+    Surface {
+        val json = mapOf("foo" to JsonPrimitive("bar"))
+        val state = 
OutgoingError(TalerErrorInfo(TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED, 
"hint", "message", json))
+        OutgoingPullComposable(
+            amount = Amount.fromString("TESTKUDOS", "42.23"),
+            state = state,
+            onCreateInvoice = { _, _, _, _ -> },
+            onClose = {},
+        )
+    }
+}
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt
index 7b1eee8..0205ae0 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt
@@ -23,8 +23,11 @@ import android.view.ViewGroup
 import androidx.compose.ui.platform.ComposeView
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
-import androidx.navigation.findNavController
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.navigation.fragment.findNavController
+import kotlinx.coroutines.launch
 import net.taler.common.Amount
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
@@ -35,8 +38,8 @@ import net.taler.wallet.showError
 
 class OutgoingPullFragment : Fragment() {
     private val model: MainViewModel by activityViewModels()
-    private val exchangeManager get() = model.exchangeManager
     private val peerManager get() = model.peerManager
+    private val transactionManager get() = model.transactionManager
 
     override fun onCreateView(
         inflater: LayoutInflater,
@@ -49,20 +52,15 @@ class OutgoingPullFragment : Fragment() {
         return ComposeView(requireContext()).apply {
             setContent {
                 TalerSurface {
-                    when (val state = 
peerManager.pullState.collectAsStateLifecycleAware().value) {
-                        is OutgoingIntro, OutgoingChecking, is OutgoingChecked 
-> {
-                            OutgoingPullIntroComposable(
-                                amount = amount,
-                                state = state,
-                                onCreateInvoice = 
this@OutgoingPullFragment::onCreateInvoice,
-                            )
+                    val state = 
peerManager.pullState.collectAsStateLifecycleAware().value
+                    OutgoingPullComposable(
+                        amount = amount,
+                        state = state,
+                        onCreateInvoice = 
this@OutgoingPullFragment::onCreateInvoice,
+                        onClose = {
+                            
findNavController().navigate(R.id.action_nav_peer_pull_to_nav_main)
                         }
-                        OutgoingCreating, is OutgoingResponse, is 
OutgoingError -> {
-                            OutgoingPullResultComposable(state) {
-                                
findNavController().navigate(R.id.action_nav_peer_pull_to_nav_main)
-                            }
-                        }
-                    }
+                    )
                 }
             }
         }
@@ -70,10 +68,20 @@ class OutgoingPullFragment : Fragment() {
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
-        lifecycleScope.launchWhenStarted {
-            peerManager.pullState.collect {
-                if (it is OutgoingError && model.devMode.value == true) {
-                    showError(it.info)
+        lifecycleScope.launch {
+            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
+                peerManager.pullState.collect {
+                    if (it is OutgoingResponse) {
+                        if 
(transactionManager.selectTransaction(it.transactionId)) {
+                            
findNavController().navigate(R.id.action_nav_peer_pull_to_nav_transactions_detail_peer)
+                        } else {
+                            
findNavController().navigate(R.id.action_nav_peer_pull_to_nav_main)
+                        }
+                    }
+
+                    if (it is OutgoingError && model.devMode.value == true) {
+                        showError(it.info)
+                    }
                 }
             }
         }
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt
deleted file mode 100644
index de62cda..0000000
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * This file is part of GNU Taler
- * (C) 2022 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.peer
-
-import android.content.res.Configuration.UI_MODE_NIGHT_YES
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.ColumnScope
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.Button
-import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment.Companion.CenterHorizontally
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import kotlinx.serialization.json.JsonPrimitive
-import net.taler.common.QrCodeManager
-import net.taler.wallet.R
-import net.taler.wallet.backend.TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED
-import net.taler.wallet.backend.TalerErrorInfo
-import net.taler.wallet.compose.QrCodeUriComposable
-import net.taler.wallet.compose.TalerSurface
-import net.taler.wallet.compose.getQrCodeSize
-
-@Composable
-fun OutgoingPullResultComposable(state: OutgoingState, onClose: () -> Unit) {
-    val scrollState = rememberScrollState()
-    Column(
-        modifier = Modifier
-            .fillMaxWidth()
-            .verticalScroll(scrollState),
-    ) {
-        Text(
-            modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 
16.dp),
-            style = MaterialTheme.typography.titleLarge,
-            text = stringResource(id = 
R.string.receive_peer_invoice_instruction),
-        )
-        when (state) {
-            OutgoingIntro, OutgoingChecking, is OutgoingChecked -> {
-                error("Result composable with ${state::class.simpleName}")
-            }
-            is OutgoingCreating -> PeerPullCreatingComposable()
-            is OutgoingResponse -> PeerPullResponseComposable(state)
-            is OutgoingError -> PeerPullErrorComposable(state)
-        }
-        Button(modifier = Modifier
-            .padding(16.dp)
-            .align(CenterHorizontally),
-            onClick = onClose) {
-            Text(text = stringResource(R.string.close))
-        }
-    }
-}
-
-@Composable
-private fun ColumnScope.PeerPullCreatingComposable() {
-    val qrCodeSize = getQrCodeSize()
-    CircularProgressIndicator(
-        modifier = Modifier
-            .padding(32.dp)
-            .size(qrCodeSize)
-            .align(CenterHorizontally),
-    )
-}
-
-@Composable
-private fun ColumnScope.PeerPullResponseComposable(state: OutgoingResponse) {
-    QrCodeUriComposable(
-        talerUri = state.talerUri,
-        clipBoardLabel = "Invoice",
-    ) {
-        Text(
-            modifier = Modifier.padding(horizontal = 16.dp),
-            style = MaterialTheme.typography.bodyLarge,
-            text = stringResource(id = R.string.receive_peer_invoice_uri),
-        )
-    }
-}
-
-@Composable
-private fun ColumnScope.PeerPullErrorComposable(state: OutgoingError) {
-    Text(
-        modifier = Modifier
-            .align(CenterHorizontally)
-            .padding(16.dp),
-        color = MaterialTheme.colorScheme.error,
-        style = MaterialTheme.typography.bodyLarge,
-        text = state.info.userFacingMsg,
-    )
-}
-
-@Preview
-@Composable
-fun PeerPullCreatingPreview() {
-    Surface {
-        OutgoingPullResultComposable(OutgoingCreating) {}
-    }
-}
-
-@Preview(uiMode = UI_MODE_NIGHT_YES)
-@Composable
-fun PeerPullResponsePreview() {
-    TalerSurface {
-        val talerUri = 
"https://example.org/foo/bar/can/be/very/long/url/so/fit/it/on/screen";
-        val response = OutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
-        OutgoingPullResultComposable(response) {}
-    }
-}
-
-@Preview(widthDp = 720, uiMode = UI_MODE_NIGHT_YES)
-@Composable
-fun PeerPullResponseLandscapePreview() {
-    TalerSurface {
-        val talerUri = 
"https://example.org/foo/bar/can/be/very/long/url/so/fit/it/on/screen";
-        val response = OutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
-        OutgoingPullResultComposable(response) {}
-    }
-}
-
-@Preview
-@Composable
-fun PeerPullErrorPreview() {
-    Surface {
-        val json = mapOf("foo" to JsonPrimitive("bar"))
-        val response = 
OutgoingError(TalerErrorInfo(WALLET_WITHDRAWAL_KYC_REQUIRED, "hint", "message", 
json))
-        OutgoingPullResultComposable(response) {}
-    }
-}
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt
similarity index 75%
rename from 
wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt
rename to wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt
index 98391be..9d972bf 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt
@@ -22,7 +22,6 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.Button
-import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.Surface
@@ -44,10 +43,31 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
+import kotlinx.serialization.json.JsonPrimitive
 import net.taler.common.Amount
 import net.taler.wallet.R
+import net.taler.wallet.backend.TalerErrorCode
+import net.taler.wallet.backend.TalerErrorInfo
 import kotlin.random.Random
 
+@Composable
+fun OutgoingPushComposable(
+    state: OutgoingState,
+    amount: Amount,
+    onSend: (amount: Amount, summary: String, hours: Long) -> Unit,
+    onClose: () -> Unit,
+) {
+    when(state) {
+        is OutgoingChecking, is OutgoingCreating, is OutgoingResponse -> 
PeerCreatingComposable()
+        is OutgoingIntro, is OutgoingChecked -> OutgoingPushIntroComposable(
+            amount = amount,
+            state = state,
+            onSend = onSend,
+        )
+        is OutgoingError -> PeerErrorComposable(state, onClose)
+    }
+}
+
 @Composable
 fun OutgoingPushIntroComposable(
     state: OutgoingState,
@@ -68,6 +88,7 @@ fun OutgoingPushIntroComposable(
             softWrap = false,
             style = MaterialTheme.typography.titleLarge,
         )
+
         if (state is OutgoingChecked) {
             val fee = state.amountEffective - state.amountRaw
             Text(
@@ -100,9 +121,11 @@ fun OutgoingPushIntroComposable(
                 )
             }
         )
+
         LaunchedEffect(Unit) {
             focusRequester.requestFocus()
         }
+
         Text(
             modifier = Modifier
                 .fillMaxWidth()
@@ -111,11 +134,13 @@ fun OutgoingPushIntroComposable(
             text = stringResource(R.string.char_count, subject.length, 
MAX_LENGTH_SUBJECT),
             textAlign = TextAlign.End,
         )
+
         Text(
             modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 
16.dp),
             text = stringResource(R.string.send_peer_expiration_period),
             style = MaterialTheme.typography.bodyMedium,
         )
+
         var option by rememberSaveable { mutableStateOf(DEFAULT_EXPIRY) }
         var hours by rememberSaveable { 
mutableLongStateOf(DEFAULT_EXPIRY.hours) }
         ExpirationComposable(
@@ -124,10 +149,12 @@ fun OutgoingPushIntroComposable(
             hours = hours,
             onOptionChange = { option = it }
         ) { hours = it }
+
         Text(
             modifier = Modifier.padding(top = 8.dp, bottom = 16.dp),
             text = stringResource(R.string.send_peer_warning),
         )
+
         Button(
             enabled = state is OutgoingChecked && subject.isNotBlank(),
             onClick = { onSend(amount, subject, hours) },
@@ -139,20 +166,58 @@ fun OutgoingPushIntroComposable(
 
 @Preview
 @Composable
-fun PeerPushIntroComposableCheckingPreview() {
+fun PeerPushComposableCreatingPreview() {
+    Surface {
+        OutgoingPushComposable(
+            amount = Amount.fromString("TESTKUDOS", "42.23"),
+            state = OutgoingCreating,
+            onSend = { _, _, _ -> },
+            onClose = {},
+        )
+    }
+}
+
+@Preview
+@Composable
+fun PeerPushComposableCheckingPreview() {
     Surface {
         val state = if (Random.nextBoolean()) OutgoingIntro else 
OutgoingChecking
-        OutgoingPushIntroComposable(state, Amount.fromString("TESTKUDOS", 
"42.23")) { _, _, _ -> }
+        OutgoingPushComposable(
+            state = state,
+            amount = Amount.fromString("TESTKUDOS", "42.23"),
+            onSend = { _, _, _ -> },
+            onClose = {},
+        )
     }
 }
 
 @Preview
 @Composable
-fun PeerPushIntroComposableCheckedPreview() {
+fun PeerPushComposableCheckedPreview() {
     Surface {
         val amountEffective = Amount.fromString("TESTKUDOS", "42.42")
         val amountRaw = Amount.fromString("TESTKUDOS", "42.23")
         val state = OutgoingChecked(amountRaw, amountEffective)
-        OutgoingPushIntroComposable(state, amountEffective) { _, _, _ -> }
+        OutgoingPushComposable(
+            state = state,
+            amount = amountEffective,
+            onSend = { _, _, _ -> },
+            onClose = {},
+        )
     }
 }
+
+@Preview
+@Composable
+fun PeerPushComposableErrorPreview() {
+    Surface {
+        val json = mapOf("foo" to JsonPrimitive("bar"))
+        val state = 
OutgoingError(TalerErrorInfo(TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED, 
"hint", "message", json))
+        OutgoingPushComposable(
+            amount = Amount.fromString("TESTKUDOS", "42.23"),
+            state = state,
+            onSend = { _, _, _ -> },
+            onClose = {},
+        )
+    }
+}
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushFragment.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushFragment.kt
index c586a1d..8cd45b0 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushFragment.kt
@@ -24,9 +24,12 @@ import androidx.activity.OnBackPressedCallback
 import androidx.compose.ui.platform.ComposeView
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
 import androidx.navigation.findNavController
 import androidx.navigation.fragment.findNavController
+import kotlinx.coroutines.launch
 import net.taler.common.Amount
 import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
@@ -37,6 +40,7 @@ import net.taler.wallet.showError
 class OutgoingPushFragment : Fragment() {
     private val model: MainViewModel by activityViewModels()
     private val peerManager get() = model.peerManager
+    private val transactionManager get() = model.transactionManager
 
     // hacky way to change back action until we have navigation for compose
     private val backPressedCallback = object : OnBackPressedCallback(false) {
@@ -61,22 +65,15 @@ class OutgoingPushFragment : Fragment() {
         return ComposeView(requireContext()).apply {
             setContent {
                 TalerSurface {
-                    when (val state = 
peerManager.pushState.collectAsStateLifecycleAware().value) {
-                        is OutgoingIntro, OutgoingChecking, is OutgoingChecked 
-> {
-                            backPressedCallback.isEnabled = false
-                            OutgoingPushIntroComposable(
-                                state = state,
-                                amount = amount,
-                                onSend = this@OutgoingPushFragment::onSend,
-                            )
+                    val state = 
peerManager.pushState.collectAsStateLifecycleAware().value
+                    OutgoingPushComposable(
+                        amount = amount,
+                        state = state,
+                        onSend = this@OutgoingPushFragment::onSend,
+                        onClose = {
+                            
findNavController().navigate(R.id.action_nav_peer_pull_to_nav_main)
                         }
-                        OutgoingCreating, is OutgoingResponse, is 
OutgoingError -> {
-                            backPressedCallback.isEnabled = true
-                            OutgoingPushResultComposable(state) {
-                                
findNavController().navigate(R.id.action_nav_peer_push_to_nav_main)
-                            }
-                        }
-                    }
+                    )
                 }
             }
         }
@@ -84,10 +81,20 @@ class OutgoingPushFragment : Fragment() {
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
-        lifecycleScope.launchWhenStarted {
-            peerManager.pushState.collect {
-                if (it is OutgoingError && model.devMode.value == true) {
-                    showError(it.info)
+        lifecycleScope.launch {
+            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
+                peerManager.pushState.collect {
+                    if (it is OutgoingResponse) {
+                        if 
(transactionManager.selectTransaction(it.transactionId)) {
+                            
findNavController().navigate(R.id.action_nav_peer_push_to_nav_transactions_detail_peer)
+                        } else {
+                            
findNavController().navigate(R.id.action_nav_peer_push_to_nav_main)
+                        }
+                    }
+
+                    if (it is OutgoingError && model.devMode.value == true) {
+                        showError(it.info)
+                    }
                 }
             }
         }
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt
deleted file mode 100644
index 0a4ee70..0000000
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * This file is part of GNU Taler
- * (C) 2022 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.peer
-
-import android.content.res.Configuration.UI_MODE_NIGHT_YES
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.ColumnScope
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.Button
-import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment.Companion.CenterHorizontally
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import kotlinx.serialization.json.JsonPrimitive
-import net.taler.common.QrCodeManager
-import net.taler.wallet.R
-import net.taler.wallet.backend.TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED
-import net.taler.wallet.backend.TalerErrorInfo
-import net.taler.wallet.compose.QrCodeUriComposable
-import net.taler.wallet.compose.TalerSurface
-import net.taler.wallet.compose.getQrCodeSize
-
-@Composable
-fun OutgoingPushResultComposable(state: OutgoingState, onClose: () -> Unit) {
-    val scrollState = rememberScrollState()
-    Column(
-        modifier = Modifier
-            .fillMaxWidth()
-            .verticalScroll(scrollState),
-    ) {
-        Text(
-            modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 
16.dp),
-            style = MaterialTheme.typography.titleLarge,
-            text = stringResource(id = R.string.send_peer_payment_instruction),
-        )
-        when (state) {
-            OutgoingIntro, OutgoingChecking, is OutgoingChecked -> {
-                error("Result composable with ${state::class.simpleName}")
-            }
-            is OutgoingCreating -> PeerPushCreatingComposable()
-            is OutgoingResponse -> PeerPushResponseComposable(state)
-            is OutgoingError -> PeerPushErrorComposable(state)
-        }
-        Button(modifier = Modifier
-            .padding(16.dp)
-            .align(CenterHorizontally),
-            onClick = onClose) {
-            Text(text = stringResource(R.string.close))
-        }
-    }
-}
-
-@Composable
-private fun ColumnScope.PeerPushCreatingComposable() {
-    val qrCodeSize = getQrCodeSize()
-    CircularProgressIndicator(
-        modifier = Modifier
-            .padding(32.dp)
-            .size(qrCodeSize)
-            .align(CenterHorizontally),
-    )
-}
-
-@Composable
-private fun ColumnScope.PeerPushResponseComposable(state: OutgoingResponse) {
-    QrCodeUriComposable(
-        talerUri = state.talerUri,
-        clipBoardLabel = "Invoice",
-    ) {
-        Text(
-            modifier = Modifier.padding(horizontal = 16.dp),
-            style = MaterialTheme.typography.bodyLarge,
-            text = stringResource(id = R.string.receive_peer_invoice_uri),
-        )
-    }
-}
-
-@Composable
-private fun ColumnScope.PeerPushErrorComposable(state: OutgoingError) {
-    Text(
-        modifier = Modifier
-            .align(CenterHorizontally)
-            .padding(16.dp),
-        color = MaterialTheme.colorScheme.error,
-        style = MaterialTheme.typography.bodyLarge,
-        text = state.info.userFacingMsg,
-    )
-}
-
-@Preview
-@Composable
-fun PeerPushCreatingPreview() {
-    Surface {
-        OutgoingPushResultComposable(OutgoingCreating) {}
-    }
-}
-
-@Preview(uiMode = UI_MODE_NIGHT_YES)
-@Composable
-fun PeerPushResponsePreview() {
-    TalerSurface {
-        val talerUri = 
"https://example.org/foo/bar/can/be/very/long/url/so/fit/it/on/screen";
-        val response = OutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
-        OutgoingPushResultComposable(response) {}
-    }
-}
-
-@Preview(widthDp = 720, uiMode = UI_MODE_NIGHT_YES)
-@Composable
-fun PeerPushResponseLandscapePreview() {
-    TalerSurface {
-        val talerUri = 
"https://example.org/foo/bar/can/be/very/long/url/so/fit/it/on/screen";
-        val response = OutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
-        OutgoingPushResultComposable(response) {}
-    }
-}
-
-@Preview
-@Composable
-fun PeerPushErrorPreview() {
-    Surface {
-        val json = mapOf("foo" to JsonPrimitive("bar"))
-        val response = 
OutgoingError(TalerErrorInfo(WALLET_WITHDRAWAL_KYC_REQUIRED, "hint", "message", 
json))
-        OutgoingPushResultComposable(response) {}
-    }
-}
diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt
index e53dd40..05da294 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt
@@ -16,7 +16,6 @@
 
 package net.taler.wallet.peer
 
-import android.graphics.Bitmap
 import kotlinx.serialization.Serializable
 import net.taler.common.Amount
 import net.taler.wallet.backend.TalerErrorInfo
@@ -32,8 +31,7 @@ data class OutgoingChecked(
 ) : OutgoingState()
 object OutgoingCreating : OutgoingState()
 data class OutgoingResponse(
-    val talerUri: String,
-    val qrCode: Bitmap,
+    val transactionId: String,
 ) : OutgoingState()
 
 data class OutgoingError(
@@ -49,10 +47,7 @@ data class CheckPeerPullCreditResponse(
 
 @Serializable
 data class InitiatePeerPullPaymentResponse(
-    /**
-     * Taler URI for the other party to make the payment that was requested.
-     */
-    val talerUri: String,
+    val transactionId: String,
 )
 
 @Serializable
@@ -64,8 +59,5 @@ data class CheckPeerPushDebitResponse(
 @Serializable
 data class InitiatePeerPushDebitResponse(
     val exchangeBaseUrl: String,
-    @Deprecated("Will be removed in future version")
-    val talerUri: String,
-    // TODO bring the user to that transaction and only show QR when in 
Pending/Ready state
     val transactionId: String,
 )
diff --git a/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt 
b/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt
index 6e65e0b..5bd2b0b 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt
@@ -25,7 +25,6 @@ import kotlinx.coroutines.launch
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import net.taler.common.Amount
-import net.taler.common.QrCodeManager
 import net.taler.common.Timestamp
 import net.taler.wallet.TAG
 import net.taler.wallet.backend.TalerErrorCode.UNKNOWN
@@ -95,8 +94,7 @@ class PeerManager(
                     put("purse_expiration", 
JSONObject(Json.encodeToString(expiry)))
                 })
             }.onSuccess {
-                val qrCode = QrCodeManager.makeQrCode(it.talerUri)
-                _outgoingPullState.value = OutgoingResponse(it.talerUri, 
qrCode)
+                _outgoingPullState.value = OutgoingResponse(it.transactionId)
             }.onError { error ->
                 Log.e(TAG, "got initiatePeerPullCredit error result $error")
                 _outgoingPullState.value = OutgoingError(error)
@@ -138,9 +136,7 @@ class PeerManager(
                     put("purse_expiration", 
JSONObject(Json.encodeToString(expiry)))
                 })
             }.onSuccess { response ->
-                // TODO bring the user to that transaction and only show QR 
when in Pending/Ready state
-                val qrCode = QrCodeManager.makeQrCode(response.talerUri)
-                _outgoingPushState.value = OutgoingResponse(response.talerUri, 
qrCode)
+                _outgoingPushState.value = 
OutgoingResponse(response.transactionId)
             }.onError { error ->
                 Log.e(TAG, "got initiatePeerPushDebit error result $error")
                 _outgoingPushState.value = OutgoingError(error)
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushDebit.kt 
b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushDebit.kt
index 2587ea9..4c79e5b 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushDebit.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushDebit.kt
@@ -69,7 +69,7 @@ fun ColumnScope.TransactionPeerPushDebitComposable(t: 
TransactionPeerPushDebit)
         label = stringResource(id = R.string.send_peer_purpose),
         info = t.info.summary ?: "",
     )
-    if (t.txState == TransactionState(Pending, Ready)) {
+    if (t.txState == TransactionState(Pending, Ready) && t.talerUri != null) {
         QrCodeUriComposable(
             talerUri = t.talerUri,
             clipBoardLabel = "Push payment",
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
index 681fadb..de47f68 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -254,14 +254,17 @@ sealed class AccountRestriction {
         // for a description of the posix-egrep syntax. Applications
         // may support regexes with additional features, but exchanges
         // must not use such regexes.
+        @SerialName("payto_regex")
         val paytoRegex: String,
 
         // Hint for a human to understand the restriction
         // (that is hopefully easier to comprehend than the regex itself).
+        @SerialName("human_hint")
         val humanHint: String,
 
         // Map from IETF BCP 47 language tags to localized
         // human hints.
+        @SerialName("human_hint_i18n")
         val humanHintI18n: Map<String, String>? = null,
     ): AccountRestriction()
 }
@@ -483,7 +486,7 @@ class TransactionPeerPushDebit(
     override val amountRaw: Amount,
     override val amountEffective: Amount,
     val info: PeerInfoShort,
-    val talerUri: String,
+    val talerUri: String? = null,
     // val completed: Boolean, definitely
 ) : Transaction() {
     override val icon = R.drawable.ic_cash_usd_outline
diff --git a/wallet/src/main/res/navigation/nav_graph.xml 
b/wallet/src/main/res/navigation/nav_graph.xml
index c0bd330..11add30 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -177,6 +177,10 @@
             android:id="@+id/action_nav_peer_pull_to_nav_main"
             app:destination="@id/nav_main"
             app:popUpTo="@id/nav_main" />
+        <action
+            
android:id="@+id/action_nav_peer_pull_to_nav_transactions_detail_peer"
+            app:destination="@id/nav_transactions_detail_peer"
+            app:popUpTo="@id/nav_main" />
     </fragment>
 
     <fragment
@@ -192,6 +196,10 @@
             android:id="@+id/action_nav_peer_push_to_nav_main"
             app:destination="@id/nav_main"
             app:popUpTo="@id/nav_main" />
+        <action
+            
android:id="@+id/action_nav_peer_push_to_nav_transactions_detail_peer"
+            app:destination="@id/nav_transactions_detail_peer"
+            app:popUpTo="@id/nav_main" />
     </fragment>
 
     <fragment

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