gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-android] branch master updated: [wallet] implement prototyp


From: gnunet
Subject: [taler-taler-android] branch master updated: [wallet] implement prototype for handling incoming pay-pull URI
Date: Wed, 07 Sep 2022 21:44:25 +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.

The following commit(s) were added to refs/heads/master by this push:
     new e350d49  [wallet] implement prototype for handling incoming pay-pull 
URI
e350d49 is described below

commit e350d497abe560aeeef88081ae93d73135ece00f
Author: Torsten Grote <t@grobox.de>
AuthorDate: Wed Sep 7 16:28:04 2022 -0300

    [wallet] implement prototype for handling incoming pay-pull URI
---
 .../src/main/java/net/taler/wallet/MainActivity.kt |  4 ++
 .../java/net/taler/wallet/SendFundsFragment.kt     | 12 ++--
 ...lPaymentComposable.kt => IncomingComposable.kt} | 65 +++++++++++-------
 ...tFragment.kt => IncomingPullPaymentFragment.kt} | 10 +--
 ...tFragment.kt => IncomingPushPaymentFragment.kt} | 16 ++---
 .../{PeerIncomingState.kt => IncomingState.kt}     | 25 ++++---
 ...PeerPullFragment.kt => OutgoingPullFragment.kt} | 10 +--
 ...omposable.kt => OutgoingPullIntroComposable.kt} |  4 +-
 ...mposable.kt => OutgoingPullResultComposable.kt} | 28 ++++----
 ...omposable.kt => OutgoingPushIntroComposable.kt} |  4 +-
 ...mposable.kt => OutgoingPushResultComposable.kt} | 28 ++++----
 .../{PeerOutgoingState.kt => OutgoingState.kt}     | 14 ++--
 .../main/java/net/taler/wallet/peer/PeerManager.kt | 77 ++++++++++++++++------
 .../taler/wallet/peer/TransactionPeerPushCredit.kt | 77 ++++++++++++++++++++++
 .../wallet/transactions/TransactionPeerFragment.kt |  3 +-
 .../net/taler/wallet/transactions/Transactions.kt  |  4 +-
 wallet/src/main/res/navigation/nav_graph.xml       | 18 ++++-
 wallet/src/main/res/values/strings.xml             |  5 ++
 18 files changed, 283 insertions(+), 121 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt 
b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
index 2797a69..df974ff 100644
--- a/wallet/src/main/java/net/taler/wallet/MainActivity.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
@@ -257,6 +257,10 @@ class MainActivity : AppCompatActivity(), 
OnNavigationItemSelectedListener,
                     nav.navigate(R.id.action_global_prompt_pull_payment)
                     model.peerManager.checkPeerPullPayment(u)
                 }
+                action.startsWith("pay-push/") -> {
+                    nav.navigate(R.id.action_global_prompt_push_payment)
+                    model.peerManager.checkPeerPushPayment(u)
+                }
                 else -> {
                     showError(R.string.error_unsupported_uri, "From: 
$from\nURI: $u")
                 }
diff --git a/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt 
b/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt
index 27f2c96..290c91b 100644
--- a/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt
@@ -28,9 +28,9 @@ import androidx.navigation.findNavController
 import com.google.android.material.composethemeadapter.MdcTheme
 import net.taler.common.Amount
 import net.taler.wallet.compose.collectAsStateLifecycleAware
-import net.taler.wallet.peer.PeerOutgoingIntro
-import net.taler.wallet.peer.PeerPushIntroComposable
-import net.taler.wallet.peer.PeerPushResultComposable
+import net.taler.wallet.peer.OutgoingIntro
+import net.taler.wallet.peer.OutgoingPushIntroComposable
+import net.taler.wallet.peer.OutgoingPushResultComposable
 
 class SendFundsFragment : Fragment() {
     private val model: MainViewModel by activityViewModels()
@@ -45,12 +45,12 @@ class SendFundsFragment : Fragment() {
             MdcTheme {
                 Surface {
                     val state = 
peerManager.pushState.collectAsStateLifecycleAware()
-                    if (state.value is PeerOutgoingIntro) {
+                    if (state.value is OutgoingIntro) {
                         val currency = transactionManager.selectedCurrency
                             ?: error("No currency selected")
-                        PeerPushIntroComposable(currency, 
this@SendFundsFragment::onSend)
+                        OutgoingPushIntroComposable(currency, 
this@SendFundsFragment::onSend)
                     } else {
-                        PeerPushResultComposable(state.value) {
+                        OutgoingPushResultComposable(state.value) {
                             findNavController().popBackStack()
                         }
                     }
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/PeerPullPaymentComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/IncomingComposable.kt
similarity index 80%
rename from 
wallet/src/main/java/net/taler/wallet/peer/PeerPullPaymentComposable.kt
rename to wallet/src/main/java/net/taler/wallet/peer/IncomingComposable.kt
index fff74ea..0095bc4 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerPullPaymentComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/IncomingComposable.kt
@@ -17,6 +17,7 @@
 package net.taler.wallet.peer
 
 import android.annotation.SuppressLint
+import androidx.annotation.StringRes
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.Row
@@ -49,10 +50,26 @@ import net.taler.common.Amount
 import net.taler.wallet.R
 import net.taler.wallet.backend.TalerErrorInfo
 
+data class IncomingData(
+    @StringRes val intro: Int,
+    @StringRes val button: Int,
+)
+
+val incomingPush = IncomingData(
+    intro = R.string.receive_peer_payment_intro,
+    button = R.string.receive_peer_payment_title,
+)
+
+val incomingPull = IncomingData(
+    intro = R.string.pay_peer_intro,
+    button = R.string.payment_button_confirm,
+)
+
 @Composable
-fun PeerPullPaymentComposable(
-    state: State<PeerIncomingState>,
-    onAccept: (PeerIncomingTerms) -> Unit,
+fun IncomingComposable(
+    state: State<IncomingState>,
+    data: IncomingData,
+    onAccept: (IncomingTerms) -> Unit,
 ) {
     val scrollState = rememberScrollState()
     Column(
@@ -64,15 +81,16 @@ fun PeerPullPaymentComposable(
             modifier = Modifier
                 .padding(16.dp)
                 .align(CenterHorizontally),
-            text = stringResource(id = R.string.pay_peer_intro))
+            text = stringResource(id = data.intro),
+        )
         when (val s = state.value) {
-            PeerIncomingChecking -> PeerPullCheckingComposable()
-            is PeerIncomingTerms -> PeerPullTermsComposable(s, onAccept)
-            is PeerIncomingAccepting -> PeerPullTermsComposable(s, onAccept)
-            PeerIncomingAccepted -> {
+            IncomingChecking -> PeerPullCheckingComposable()
+            is IncomingTerms -> PeerPullTermsComposable(s, onAccept, data)
+            is IncomingAccepting -> PeerPullTermsComposable(s, onAccept, data)
+            IncomingAccepted -> {
                 // we navigate away, don't show anything
             }
-            is PeerIncomingError -> PeerPullErrorComposable(s)
+            is IncomingError -> PeerPullErrorComposable(s)
         }
     }
 }
@@ -88,8 +106,9 @@ fun ColumnScope.PeerPullCheckingComposable() {
 
 @Composable
 fun ColumnScope.PeerPullTermsComposable(
-    terms: PeerIncomingTerms,
-    onAccept: (PeerIncomingTerms) -> Unit,
+    terms: IncomingTerms,
+    onAccept: (IncomingTerms) -> Unit,
+    data: IncomingData,
 ) {
     Text(
         modifier = Modifier
@@ -126,7 +145,7 @@ fun ColumnScope.PeerPullTermsComposable(
                     style = MaterialTheme.typography.body1,
                 )
             }
-            if (terms is PeerIncomingAccepting) {
+            if (terms is IncomingAccepting) {
                 CircularProgressIndicator(
                     modifier = Modifier
                         .padding(end = 64.dp)
@@ -144,7 +163,7 @@ fun ColumnScope.PeerPullTermsComposable(
                     onClick = { onAccept(terms) },
                 ) {
                     Text(
-                        text = stringResource(id = 
R.string.payment_button_confirm),
+                        text = stringResource(id = data.button),
                     )
                 }
             }
@@ -153,7 +172,7 @@ fun ColumnScope.PeerPullTermsComposable(
 }
 
 @Composable
-fun ColumnScope.PeerPullErrorComposable(s: PeerIncomingError) {
+fun ColumnScope.PeerPullErrorComposable(s: IncomingError) {
     Text(
         modifier = Modifier
             .align(CenterHorizontally)
@@ -169,8 +188,8 @@ fun ColumnScope.PeerPullErrorComposable(s: 
PeerIncomingError) {
 fun PeerPullCheckingPreview() {
     Surface {
         @SuppressLint("UnrememberedMutableState")
-        val s = mutableStateOf(PeerIncomingChecking)
-        PeerPullPaymentComposable(s) {}
+        val s = mutableStateOf(IncomingChecking)
+        IncomingComposable(s, incomingPush) {}
     }
 }
 
@@ -178,7 +197,7 @@ fun PeerPullCheckingPreview() {
 @Composable
 fun PeerPullTermsPreview() {
     Surface {
-        val terms = PeerIncomingTerms(
+        val terms = IncomingTerms(
             amount = Amount.fromDouble("TESTKUDOS", 42.23),
             contractTerms = PeerContractTerms(
                 summary = "This is a long test summary that can be more than 
one line long for sure",
@@ -189,7 +208,7 @@ fun PeerPullTermsPreview() {
 
         @SuppressLint("UnrememberedMutableState")
         val s = mutableStateOf(terms)
-        PeerPullPaymentComposable(s) {}
+        IncomingComposable(s, incomingPush) {}
     }
 }
 
@@ -197,7 +216,7 @@ fun PeerPullTermsPreview() {
 @Composable
 fun PeerPullAcceptingPreview() {
     Surface {
-        val terms = PeerIncomingTerms(
+        val terms = IncomingTerms(
             amount = Amount.fromDouble("TESTKUDOS", 42.23),
             contractTerms = PeerContractTerms(
                 summary = "This is a long test summary that can be more than 
one line long for sure",
@@ -207,8 +226,8 @@ fun PeerPullAcceptingPreview() {
         )
 
         @SuppressLint("UnrememberedMutableState")
-        val s = mutableStateOf(PeerIncomingAccepting(terms))
-        PeerPullPaymentComposable(s) {}
+        val s = mutableStateOf(IncomingAccepting(terms))
+        IncomingComposable(s, incomingPush) {}
     }
 }
 
@@ -217,7 +236,7 @@ fun PeerPullAcceptingPreview() {
 fun PeerPullPayErrorPreview() {
     Surface {
         @SuppressLint("UnrememberedMutableState")
-        val s = mutableStateOf(PeerIncomingError(TalerErrorInfo(42, "hint", 
"msg")))
-        PeerPullPaymentComposable(s) {}
+        val s = mutableStateOf(IncomingError(TalerErrorInfo(42, "hint", 
"msg")))
+        IncomingComposable(s, incomingPush) {}
     }
 }
diff --git a/wallet/src/main/java/net/taler/wallet/peer/PullPaymentFragment.kt 
b/wallet/src/main/java/net/taler/wallet/peer/IncomingPullPaymentFragment.kt
similarity index 87%
copy from wallet/src/main/java/net/taler/wallet/peer/PullPaymentFragment.kt
copy to 
wallet/src/main/java/net/taler/wallet/peer/IncomingPullPaymentFragment.kt
index 71b1bcc..cd2f39b 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PullPaymentFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/IncomingPullPaymentFragment.kt
@@ -31,7 +31,7 @@ import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
 import net.taler.wallet.compose.collectAsStateLifecycleAware
 
-class PullPaymentFragment : Fragment() {
+class IncomingPullPaymentFragment : Fragment() {
     private val model: MainViewModel by activityViewModels()
     private val peerManager get() = model.peerManager
 
@@ -41,8 +41,8 @@ class PullPaymentFragment : Fragment() {
         savedInstanceState: Bundle?,
     ): View {
         lifecycleScope.launchWhenResumed {
-            peerManager.paymentState.collect {
-                if (it is PeerIncomingAccepted) {
+            peerManager.incomingPullState.collect {
+                if (it is IncomingAccepted) {
                     
findNavController().navigate(R.id.action_promptPullPayment_to_nav_main)
                 }
             }
@@ -51,8 +51,8 @@ class PullPaymentFragment : Fragment() {
             setContent {
                 MdcTheme {
                     Surface {
-                        val state = 
peerManager.paymentState.collectAsStateLifecycleAware()
-                        PeerPullPaymentComposable(state) { terms ->
+                        val state = 
peerManager.incomingPullState.collectAsStateLifecycleAware()
+                        IncomingComposable(state, incomingPull) { terms ->
                             peerManager.acceptPeerPullPayment(terms)
                         }
                     }
diff --git a/wallet/src/main/java/net/taler/wallet/peer/PullPaymentFragment.kt 
b/wallet/src/main/java/net/taler/wallet/peer/IncomingPushPaymentFragment.kt
similarity index 81%
rename from wallet/src/main/java/net/taler/wallet/peer/PullPaymentFragment.kt
rename to 
wallet/src/main/java/net/taler/wallet/peer/IncomingPushPaymentFragment.kt
index 71b1bcc..8429ecc 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PullPaymentFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/IncomingPushPaymentFragment.kt
@@ -31,7 +31,7 @@ import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
 import net.taler.wallet.compose.collectAsStateLifecycleAware
 
-class PullPaymentFragment : Fragment() {
+class IncomingPushPaymentFragment : Fragment() {
     private val model: MainViewModel by activityViewModels()
     private val peerManager get() = model.peerManager
 
@@ -41,9 +41,9 @@ class PullPaymentFragment : Fragment() {
         savedInstanceState: Bundle?,
     ): View {
         lifecycleScope.launchWhenResumed {
-            peerManager.paymentState.collect {
-                if (it is PeerIncomingAccepted) {
-                    
findNavController().navigate(R.id.action_promptPullPayment_to_nav_main)
+            peerManager.incomingPushState.collect {
+                if (it is IncomingAccepted) {
+                    
findNavController().navigate(R.id.action_promptPushPayment_to_nav_main)
                 }
             }
         }
@@ -51,9 +51,9 @@ class PullPaymentFragment : Fragment() {
             setContent {
                 MdcTheme {
                     Surface {
-                        val state = 
peerManager.paymentState.collectAsStateLifecycleAware()
-                        PeerPullPaymentComposable(state) { terms ->
-                            peerManager.acceptPeerPullPayment(terms)
+                        val state = 
peerManager.incomingPushState.collectAsStateLifecycleAware()
+                        IncomingComposable(state, incomingPush) { terms ->
+                            peerManager.acceptPeerPushPayment(terms)
                         }
                     }
                 }
@@ -63,6 +63,6 @@ class PullPaymentFragment : Fragment() {
 
     override fun onStart() {
         super.onStart()
-        activity?.setTitle(R.string.pay_peer_title)
+        activity?.setTitle(R.string.receive_peer_payment_title)
     }
 }
diff --git a/wallet/src/main/java/net/taler/wallet/peer/PeerIncomingState.kt 
b/wallet/src/main/java/net/taler/wallet/peer/IncomingState.kt
similarity index 72%
rename from wallet/src/main/java/net/taler/wallet/peer/PeerIncomingState.kt
rename to wallet/src/main/java/net/taler/wallet/peer/IncomingState.kt
index c021c2f..7ca38c4 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerIncomingState.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/IncomingState.kt
@@ -20,21 +20,21 @@ import kotlinx.serialization.Serializable
 import net.taler.common.Amount
 import net.taler.wallet.backend.TalerErrorInfo
 
-sealed class PeerIncomingState
-object PeerIncomingChecking : PeerIncomingState()
-open class PeerIncomingTerms(
+sealed class IncomingState
+object IncomingChecking : IncomingState()
+open class IncomingTerms(
     val amount: Amount,
     val contractTerms: PeerContractTerms,
     val id: String,
-) : PeerIncomingState()
+) : IncomingState()
 
-class PeerIncomingAccepting(s: PeerIncomingTerms) :
-    PeerIncomingTerms(s.amount, s.contractTerms, s.id)
+class IncomingAccepting(s: IncomingTerms) :
+    IncomingTerms(s.amount, s.contractTerms, s.id)
 
-object PeerIncomingAccepted : PeerIncomingState()
-data class PeerIncomingError(
+object IncomingAccepted : IncomingState()
+data class IncomingError(
     val info: TalerErrorInfo,
-) : PeerIncomingState()
+) : IncomingState()
 
 @Serializable
 data class PeerContractTerms(
@@ -48,3 +48,10 @@ data class CheckPeerPullPaymentResponse(
     val contractTerms: PeerContractTerms,
     val peerPullPaymentIncomingId: String,
 )
+
+@Serializable
+data class CheckPeerPushPaymentResponse(
+    val amount: Amount,
+    val contractTerms: PeerContractTerms,
+    val peerPushPaymentIncomingId: String,
+)
diff --git a/wallet/src/main/java/net/taler/wallet/peer/PeerPullFragment.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt
similarity index 90%
rename from wallet/src/main/java/net/taler/wallet/peer/PeerPullFragment.kt
rename to wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt
index be79e9d..b1593ff 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerPullFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt
@@ -32,7 +32,7 @@ import net.taler.wallet.R
 import net.taler.wallet.compose.collectAsStateLifecycleAware
 import net.taler.wallet.exchanges.ExchangeItem
 
-class PeerPullFragment : Fragment() {
+class OutgoingPullFragment : Fragment() {
     private val model: MainViewModel by activityViewModels()
     private val exchangeManager get() = model.exchangeManager
     private val peerManager get() = model.peerManager
@@ -51,16 +51,16 @@ class PeerPullFragment : Fragment() {
                 MdcTheme {
                     Surface {
                         val state = 
peerManager.pullState.collectAsStateLifecycleAware()
-                        if (state.value is PeerOutgoingIntro) {
+                        if (state.value is OutgoingIntro) {
                             val exchangeState =
                                 
exchangeFlow.collectAsStateLifecycleAware(initial = null)
-                            PeerPullIntroComposable(
+                            OutgoingPullIntroComposable(
                                 amount = amount,
                                 exchangeState = exchangeState,
-                                onCreateInvoice = 
this@PeerPullFragment::onCreateInvoice,
+                                onCreateInvoice = 
this@OutgoingPullFragment::onCreateInvoice,
                             )
                         } else {
-                            PeerPullResultComposable(state.value) {
+                            OutgoingPullResultComposable(state.value) {
                                 findNavController().popBackStack()
                             }
                         }
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/PeerPullIntroComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt
similarity index 97%
rename from 
wallet/src/main/java/net/taler/wallet/peer/PeerPullIntroComposable.kt
rename to 
wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt
index 02f2c7c..a338836 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerPullIntroComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt
@@ -50,7 +50,7 @@ import net.taler.wallet.cleanExchange
 import net.taler.wallet.exchanges.ExchangeItem
 
 @Composable
-fun PeerPullIntroComposable(
+fun OutgoingPullIntroComposable(
     amount: Amount,
     exchangeState: State<ExchangeItem?>,
     onCreateInvoice: (amount: Amount, exchange: ExchangeItem) -> Unit,
@@ -124,6 +124,6 @@ fun PreviewReceiveFundsIntro() {
         @SuppressLint("UnrememberedMutableState")
         val exchangeFlow =
             mutableStateOf(ExchangeItem("https://example.org";, "TESTKUDOS", 
emptyList()))
-        PeerPullIntroComposable(Amount.fromDouble("TESTKUDOS", 42.23), 
exchangeFlow) { _, _ -> }
+        OutgoingPullIntroComposable(Amount.fromDouble("TESTKUDOS", 42.23), 
exchangeFlow) { _, _ -> }
     }
 }
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/PeerPullResultComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt
similarity index 85%
rename from 
wallet/src/main/java/net/taler/wallet/peer/PeerPullResultComposable.kt
rename to 
wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt
index d37ca4b..2c4001f 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerPullResultComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt
@@ -55,7 +55,7 @@ import net.taler.wallet.compose.getQrCodeSize
 import org.json.JSONObject
 
 @Composable
-fun PeerPullResultComposable(state: PeerOutgoingState, onClose: () -> Unit) {
+fun OutgoingPullResultComposable(state: OutgoingState, onClose: () -> Unit) {
     val scrollState = rememberScrollState()
     Column(
         modifier = Modifier
@@ -68,10 +68,10 @@ fun PeerPullResultComposable(state: PeerOutgoingState, 
onClose: () -> Unit) {
             text = stringResource(id = 
R.string.receive_peer_invoice_instruction),
         )
         when (state) {
-            PeerOutgoingIntro -> error("Result composable with 
PullPaymentIntro")
-            is PeerOutgoingCreating -> PeerPullCreatingComposable()
-            is PeerOutgoingResponse -> PeerPullResponseComposable(state)
-            is PeerOutgoingError -> PeerPullErrorComposable(state)
+            OutgoingIntro -> error("Result composable with PullPaymentIntro")
+            is OutgoingCreating -> PeerPullCreatingComposable()
+            is OutgoingResponse -> PeerPullResponseComposable(state)
+            is OutgoingError -> PeerPullErrorComposable(state)
         }
         Button(modifier = Modifier
             .padding(16.dp)
@@ -94,7 +94,7 @@ private fun ColumnScope.PeerPullCreatingComposable() {
 }
 
 @Composable
-private fun ColumnScope.PeerPullResponseComposable(state: 
PeerOutgoingResponse) {
+private fun ColumnScope.PeerPullResponseComposable(state: OutgoingResponse) {
     val qrCodeSize = getQrCodeSize()
     Image(
         modifier = Modifier
@@ -135,7 +135,7 @@ private fun ColumnScope.PeerPullResponseComposable(state: 
PeerOutgoingResponse)
 }
 
 @Composable
-private fun ColumnScope.PeerPullErrorComposable(state: PeerOutgoingError) {
+private fun ColumnScope.PeerPullErrorComposable(state: OutgoingError) {
     Text(
         modifier = Modifier
             .align(CenterHorizontally)
@@ -150,7 +150,7 @@ private fun ColumnScope.PeerPullErrorComposable(state: 
PeerOutgoingError) {
 @Composable
 fun PeerPullCreatingPreview() {
     Surface {
-        PeerPullResultComposable(PeerOutgoingCreating) {}
+        OutgoingPullResultComposable(OutgoingCreating) {}
     }
 }
 
@@ -159,8 +159,8 @@ fun PeerPullCreatingPreview() {
 fun PeerPullResponsePreview() {
     Surface {
         val talerUri = 
"https://example.org/foo/bar/can/be/very/long/url/so/fit/it/on/screen";
-        val response = PeerOutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
-        PeerPullResultComposable(response) {}
+        val response = OutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
+        OutgoingPullResultComposable(response) {}
     }
 }
 
@@ -169,8 +169,8 @@ fun PeerPullResponsePreview() {
 fun PeerPullResponseLandscapePreview() {
     Surface {
         val talerUri = 
"https://example.org/foo/bar/can/be/very/long/url/so/fit/it/on/screen";
-        val response = PeerOutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
-        PeerPullResultComposable(response) {}
+        val response = OutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
+        OutgoingPullResultComposable(response) {}
     }
 }
 
@@ -179,7 +179,7 @@ fun PeerPullResponseLandscapePreview() {
 fun PeerPullErrorPreview() {
     Surface {
         val json = JSONObject().apply { put("foo", "bar") }
-        val response = PeerOutgoingError(TalerErrorInfo(42, "hint", "message", 
json))
-        PeerPullResultComposable(response) {}
+        val response = OutgoingError(TalerErrorInfo(42, "hint", "message", 
json))
+        OutgoingPullResultComposable(response) {}
     }
 }
diff --git a/wallet/src/main/java/net/taler/wallet/peer/PeerPushComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt
similarity index 98%
rename from wallet/src/main/java/net/taler/wallet/peer/PeerPushComposable.kt
rename to 
wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt
index 1399fbb..72c8862 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerPushComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt
@@ -47,7 +47,7 @@ import net.taler.wallet.R
 import net.taler.wallet.getAmount
 
 @Composable
-fun PeerPushIntroComposable(
+fun OutgoingPushIntroComposable(
     currency: String,
     onSend: (amount: Amount, summary: String) -> Unit,
 ) {
@@ -134,6 +134,6 @@ fun PeerPushIntroComposable(
 @Composable
 fun PeerPushIntroComposablePreview() {
     Surface {
-        PeerPushIntroComposable("TESTKUDOS") { _, _ -> }
+        OutgoingPushIntroComposable("TESTKUDOS") { _, _ -> }
     }
 }
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/PeerPushResultComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt
similarity index 85%
rename from 
wallet/src/main/java/net/taler/wallet/peer/PeerPushResultComposable.kt
rename to 
wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt
index b33fc4f..6d8b5dc 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerPushResultComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt
@@ -55,7 +55,7 @@ import net.taler.wallet.compose.getQrCodeSize
 import org.json.JSONObject
 
 @Composable
-fun PeerPushResultComposable(state: PeerOutgoingState, onClose: () -> Unit) {
+fun OutgoingPushResultComposable(state: OutgoingState, onClose: () -> Unit) {
     val scrollState = rememberScrollState()
     Column(
         modifier = Modifier
@@ -68,10 +68,10 @@ fun PeerPushResultComposable(state: PeerOutgoingState, 
onClose: () -> Unit) {
             text = stringResource(id = R.string.send_peer_payment_instruction),
         )
         when (state) {
-            PeerOutgoingIntro -> error("Result composable with 
PullPaymentIntro")
-            is PeerOutgoingCreating -> PeerPushCreatingComposable()
-            is PeerOutgoingResponse -> PeerPushResponseComposable(state)
-            is PeerOutgoingError -> PeerPushErrorComposable(state)
+            OutgoingIntro -> error("Result composable with PullPaymentIntro")
+            is OutgoingCreating -> PeerPushCreatingComposable()
+            is OutgoingResponse -> PeerPushResponseComposable(state)
+            is OutgoingError -> PeerPushErrorComposable(state)
         }
         Button(modifier = Modifier
             .padding(16.dp)
@@ -94,7 +94,7 @@ private fun ColumnScope.PeerPushCreatingComposable() {
 }
 
 @Composable
-private fun ColumnScope.PeerPushResponseComposable(state: 
PeerOutgoingResponse) {
+private fun ColumnScope.PeerPushResponseComposable(state: OutgoingResponse) {
     val qrCodeSize = getQrCodeSize()
     Image(
         modifier = Modifier
@@ -135,7 +135,7 @@ private fun ColumnScope.PeerPushResponseComposable(state: 
PeerOutgoingResponse)
 }
 
 @Composable
-private fun ColumnScope.PeerPushErrorComposable(state: PeerOutgoingError) {
+private fun ColumnScope.PeerPushErrorComposable(state: OutgoingError) {
     Text(
         modifier = Modifier
             .align(CenterHorizontally)
@@ -150,7 +150,7 @@ private fun ColumnScope.PeerPushErrorComposable(state: 
PeerOutgoingError) {
 @Composable
 fun PeerPushCreatingPreview() {
     Surface {
-        PeerPushResultComposable(PeerOutgoingCreating) {}
+        OutgoingPushResultComposable(OutgoingCreating) {}
     }
 }
 
@@ -159,8 +159,8 @@ fun PeerPushCreatingPreview() {
 fun PeerPushResponsePreview() {
     Surface {
         val talerUri = 
"https://example.org/foo/bar/can/be/very/long/url/so/fit/it/on/screen";
-        val response = PeerOutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
-        PeerPushResultComposable(response) {}
+        val response = OutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
+        OutgoingPushResultComposable(response) {}
     }
 }
 
@@ -169,8 +169,8 @@ fun PeerPushResponsePreview() {
 fun PeerPushResponseLandscapePreview() {
     Surface {
         val talerUri = 
"https://example.org/foo/bar/can/be/very/long/url/so/fit/it/on/screen";
-        val response = PeerOutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
-        PeerPushResultComposable(response) {}
+        val response = OutgoingResponse(talerUri, 
QrCodeManager.makeQrCode(talerUri))
+        OutgoingPushResultComposable(response) {}
     }
 }
 
@@ -179,7 +179,7 @@ fun PeerPushResponseLandscapePreview() {
 fun PeerPushErrorPreview() {
     Surface {
         val json = JSONObject().apply { put("foo", "bar") }
-        val response = PeerOutgoingError(TalerErrorInfo(42, "hint", "message", 
json))
-        PeerPushResultComposable(response) {}
+        val response = OutgoingError(TalerErrorInfo(42, "hint", "message", 
json))
+        OutgoingPushResultComposable(response) {}
     }
 }
diff --git a/wallet/src/main/java/net/taler/wallet/peer/PeerOutgoingState.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt
similarity index 83%
rename from wallet/src/main/java/net/taler/wallet/peer/PeerOutgoingState.kt
rename to wallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt
index 0b6b2a8..0e01056 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerOutgoingState.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt
@@ -20,17 +20,17 @@ import android.graphics.Bitmap
 import kotlinx.serialization.Serializable
 import net.taler.wallet.backend.TalerErrorInfo
 
-sealed class PeerOutgoingState
-object PeerOutgoingIntro : PeerOutgoingState()
-object PeerOutgoingCreating : PeerOutgoingState()
-data class PeerOutgoingResponse(
+sealed class OutgoingState
+object OutgoingIntro : OutgoingState()
+object OutgoingCreating : OutgoingState()
+data class OutgoingResponse(
     val talerUri: String,
     val qrCode: Bitmap,
-) : PeerOutgoingState()
+) : OutgoingState()
 
-data class PeerOutgoingError(
+data class OutgoingError(
     val info: TalerErrorInfo,
-) : PeerOutgoingState()
+) : OutgoingState()
 
 @Serializable
 data class InitiatePeerPullPaymentResponse(
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 5bfd030..b02b2b6 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt
@@ -34,17 +34,20 @@ class PeerManager(
     private val scope: CoroutineScope,
 ) {
 
-    private val _pullState = 
MutableStateFlow<PeerOutgoingState>(PeerOutgoingIntro)
-    val pullState: StateFlow<PeerOutgoingState> = _pullState
+    private val _outgoingPullState = 
MutableStateFlow<OutgoingState>(OutgoingIntro)
+    val pullState: StateFlow<OutgoingState> = _outgoingPullState
 
-    private val _pushState = 
MutableStateFlow<PeerOutgoingState>(PeerOutgoingIntro)
-    val pushState: StateFlow<PeerOutgoingState> = _pushState
+    private val _outgoingPushState = 
MutableStateFlow<OutgoingState>(OutgoingIntro)
+    val pushState: StateFlow<OutgoingState> = _outgoingPushState
 
-    private val _paymentState = 
MutableStateFlow<PeerIncomingState>(PeerIncomingChecking)
-    val paymentState: StateFlow<PeerIncomingState> = _paymentState
+    private val _incomingPullState = 
MutableStateFlow<IncomingState>(IncomingChecking)
+    val incomingPullState: StateFlow<IncomingState> = _incomingPullState
+
+    private val _incomingPushState = 
MutableStateFlow<IncomingState>(IncomingChecking)
+    val incomingPushState: StateFlow<IncomingState> = _incomingPushState
 
     fun initiatePullPayment(amount: Amount, exchange: ExchangeItem) {
-        _pullState.value = PeerOutgoingCreating
+        _outgoingPullState.value = OutgoingCreating
         scope.launch(Dispatchers.IO) {
             api.request("initiatePeerPullPayment", 
InitiatePeerPullPaymentResponse.serializer()) {
                 put("exchangeBaseUrl", exchange.exchangeBaseUrl)
@@ -54,20 +57,20 @@ class PeerManager(
                 })
             }.onSuccess {
                 val qrCode = QrCodeManager.makeQrCode(it.talerUri)
-                _pullState.value = PeerOutgoingResponse(it.talerUri, qrCode)
+                _outgoingPullState.value = OutgoingResponse(it.talerUri, 
qrCode)
             }.onError { error ->
                 Log.e(TAG, "got initiatePeerPullPayment error result $error")
-                _pullState.value = PeerOutgoingError(error)
+                _outgoingPullState.value = OutgoingError(error)
             }
         }
     }
 
     fun resetPullPayment() {
-        _pullState.value = PeerOutgoingIntro
+        _outgoingPullState.value = OutgoingIntro
     }
 
     fun initiatePeerPushPayment(amount: Amount, summary: String) {
-        _pushState.value = PeerOutgoingCreating
+        _outgoingPushState.value = OutgoingCreating
         scope.launch(Dispatchers.IO) {
             api.request("initiatePeerPushPayment", 
InitiatePeerPushPaymentResponse.serializer()) {
                 put("amount", amount.toJSONString())
@@ -76,46 +79,78 @@ class PeerManager(
                 })
             }.onSuccess { response ->
                 val qrCode = QrCodeManager.makeQrCode(response.talerUri)
-                _pushState.value = PeerOutgoingResponse(response.talerUri, 
qrCode)
+                _outgoingPushState.value = OutgoingResponse(response.talerUri, 
qrCode)
             }.onError { error ->
                 Log.e(TAG, "got initiatePeerPushPayment error result $error")
-                _pushState.value = PeerOutgoingError(error)
+                _outgoingPushState.value = OutgoingError(error)
             }
         }
     }
 
     fun resetPushPayment() {
-        _pushState.value = PeerOutgoingIntro
+        _outgoingPushState.value = OutgoingIntro
     }
 
     fun checkPeerPullPayment(talerUri: String) {
-        _paymentState.value = PeerIncomingChecking
+        _incomingPullState.value = IncomingChecking
         scope.launch(Dispatchers.IO) {
             api.request("checkPeerPullPayment", 
CheckPeerPullPaymentResponse.serializer()) {
                 put("talerUri", talerUri)
             }.onSuccess { response ->
-                _paymentState.value = PeerIncomingTerms(
+                _incomingPullState.value = IncomingTerms(
                     amount = response.amount,
                     contractTerms = response.contractTerms,
                     id = response.peerPullPaymentIncomingId,
                 )
             }.onError { error ->
                 Log.e(TAG, "got checkPeerPushPayment error result $error")
-                _paymentState.value = PeerIncomingError(error)
+                _incomingPullState.value = IncomingError(error)
             }
         }
     }
 
-    fun acceptPeerPullPayment(terms: PeerIncomingTerms) {
-        _paymentState.value = PeerIncomingAccepting(terms)
+    fun acceptPeerPullPayment(terms: IncomingTerms) {
+        _incomingPullState.value = IncomingAccepting(terms)
         scope.launch(Dispatchers.IO) {
             api.request<Unit>("acceptPeerPullPayment") {
                 put("peerPullPaymentIncomingId", terms.id)
             }.onSuccess {
-                _paymentState.value = PeerIncomingAccepted
+                _incomingPullState.value = IncomingAccepted
+            }.onError { error ->
+                Log.e(TAG, "got checkPeerPushPayment error result $error")
+                _incomingPullState.value = IncomingError(error)
+            }
+        }
+    }
+
+    fun checkPeerPushPayment(talerUri: String) {
+        _incomingPushState.value = IncomingChecking
+        scope.launch(Dispatchers.IO) {
+            api.request("checkPeerPushPayment", 
CheckPeerPushPaymentResponse.serializer()) {
+                put("talerUri", talerUri)
+            }.onSuccess { response ->
+                _incomingPushState.value = IncomingTerms(
+                    amount = response.amount,
+                    contractTerms = response.contractTerms,
+                    id = response.peerPushPaymentIncomingId,
+                )
+            }.onError { error ->
+                Log.e(TAG, "got checkPeerPushPayment error result $error")
+                _incomingPushState.value = IncomingError(error)
+            }
+        }
+    }
+
+    fun acceptPeerPushPayment(terms: IncomingTerms) {
+        _incomingPushState.value = IncomingAccepting(terms)
+        scope.launch(Dispatchers.IO) {
+            api.request<Unit>("acceptPeerPushPayment") {
+                put("peerPushPaymentIncomingId", terms.id)
+            }.onSuccess {
+                _incomingPushState.value = IncomingAccepted
             }.onError { error ->
                 Log.e(TAG, "got checkPeerPushPayment error result $error")
-                _paymentState.value = PeerIncomingError(error)
+                _incomingPushState.value = IncomingError(error)
             }
         }
     }
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushCredit.kt 
b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushCredit.kt
new file mode 100644
index 0000000..b986f57
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushCredit.kt
@@ -0,0 +1,77 @@
+/*
+ * 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 androidx.compose.material.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import net.taler.common.Amount
+import net.taler.common.Timestamp
+import net.taler.wallet.R
+import net.taler.wallet.transactions.AmountType
+import net.taler.wallet.transactions.PeerInfoShort
+import net.taler.wallet.transactions.TransactionAmountComposable
+import net.taler.wallet.transactions.TransactionInfoComposable
+import net.taler.wallet.transactions.TransactionPeerComposable
+import net.taler.wallet.transactions.TransactionPeerPushCredit
+
+@Composable
+fun TransactionPeerPushCreditComposable(t: TransactionPeerPushCredit) {
+    TransactionAmountComposable(
+        label = stringResource(id = 
R.string.send_peer_payment_amount_received),
+        amount = t.amountEffective,
+        amountType = AmountType.Positive,
+    )
+    TransactionAmountComposable(
+        label = stringResource(id = R.string.send_peer_payment_amount_sent),
+        amount = t.amountRaw,
+        amountType = AmountType.Neutral,
+    )
+    val fee = t.amountRaw - t.amountEffective
+    if (!fee.isZero()) {
+        TransactionAmountComposable(
+            label = stringResource(id = R.string.withdraw_fees),
+            amount = fee,
+            amountType = AmountType.Negative,
+        )
+    }
+    TransactionInfoComposable(
+        label = stringResource(id = R.string.withdraw_manual_ready_subject),
+        info = t.info.summary ?: "",
+    )
+}
+
+@Preview
+@Composable
+fun TransactionPeerPushCreditPreview() {
+    val t = TransactionPeerPushCredit(
+        transactionId = "transactionId",
+        timestamp = Timestamp(System.currentTimeMillis() - 360 * 60 * 1000),
+        pending = true,
+        exchangeBaseUrl = "https://exchange.example.org/";,
+        amountRaw = Amount.fromDouble("TESTKUDOS", 42.23),
+        amountEffective = Amount.fromDouble("TESTKUDOS", 42.1337),
+        info = PeerInfoShort(
+            expiration = Timestamp(System.currentTimeMillis() + 60 * 60 * 
1000),
+            summary = "test invoice",
+        ),
+    )
+    Surface {
+        TransactionPeerComposable(t) {}
+    }
+}
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt
index 9b0c208..749ec30 100644
--- 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt
+++ 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt
@@ -50,6 +50,7 @@ import net.taler.common.toAbsoluteTime
 import net.taler.wallet.R
 import net.taler.wallet.peer.TransactionPeerPullCreditComposable
 import net.taler.wallet.peer.TransactionPeerPullDebitComposable
+import net.taler.wallet.peer.TransactionPeerPushCreditComposable
 import net.taler.wallet.peer.TransactionPeerPushDebitComposable
 
 class TransactionPeerFragment : TransactionDetailFragment() {
@@ -89,7 +90,7 @@ fun TransactionPeerComposable(t: Transaction, onDelete: () -> 
Unit) {
         )
         when (t) {
             is TransactionPeerPullCredit -> 
TransactionPeerPullCreditComposable(t)
-            is TransactionPeerPushCredit -> TODO()
+            is TransactionPeerPushCredit -> 
TransactionPeerPushCreditComposable(t)
             is TransactionPeerPullDebit -> 
TransactionPeerPullDebitComposable(t)
             is TransactionPeerPushDebit -> 
TransactionPeerPushDebitComposable(t)
             else -> error("unexpected transaction: ${t::class.simpleName}")
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 6ef6c88..97ac5ea 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -361,7 +361,7 @@ class TransactionPeerPushCredit(
     @Transient
     override val amountType = AmountType.Positive
     override fun getTitle(context: Context): String {
-        return context.getString(R.string.transaction_peer_push_debit)
+        return context.getString(R.string.transaction_peer_push_credit)
     }
-    override val generalTitleRes = R.string.withdraw_title
+    override val generalTitleRes = R.string.transaction_peer_push_credit
 }
diff --git a/wallet/src/main/res/navigation/nav_graph.xml 
b/wallet/src/main/res/navigation/nav_graph.xml
index 3170216..f9060c5 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -131,7 +131,7 @@
 
     <fragment
         android:id="@+id/nav_peer_pull"
-        android:name="net.taler.wallet.peer.PeerPullFragment"
+        android:name="net.taler.wallet.peer.OutgoingPullFragment"
         android:label="@string/receive_peer_title">
         <argument
             android:name="amount"
@@ -142,7 +142,7 @@
 
     <fragment
         android:id="@+id/promptPullPayment"
-        android:name="net.taler.wallet.peer.PullPaymentFragment"
+        android:name="net.taler.wallet.peer.IncomingPullPaymentFragment"
         android:label="@string/pay_peer_title">
         <action
             android:id="@+id/action_promptPullPayment_to_nav_main"
@@ -150,6 +150,16 @@
             app:popUpTo="@id/nav_main" />
     </fragment>
 
+    <fragment
+        android:id="@+id/promptPushPayment"
+        android:name="net.taler.wallet.peer.IncomingPushPaymentFragment"
+        android:label="@string/receive_peer_payment_title">
+        <action
+            android:id="@+id/action_promptPushPayment_to_nav_main"
+            app:destination="@id/nav_main"
+            app:popUpTo="@id/nav_main" />
+    </fragment>
+
     <fragment
         android:id="@+id/nav_transactions"
         android:name="net.taler.wallet.transactions.TransactionsFragment"
@@ -289,6 +299,10 @@
         android:id="@+id/action_global_prompt_pull_payment"
         app:destination="@id/promptPullPayment" />
 
+    <action
+        android:id="@+id/action_global_prompt_push_payment"
+        app:destination="@id/promptPushPayment" />
+
     <action
         android:id="@+id/action_global_pending_operations"
         app:destination="@id/nav_pending_operations" />
diff --git a/wallet/src/main/res/values/strings.xml 
b/wallet/src/main/res/values/strings.xml
index 8601b14..ab8984c 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -99,6 +99,7 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
     <string name="transaction_peer_push_debit">Push payment</string>
     <string name="transaction_peer_pull_credit">Invoice</string>
     <string name="transaction_peer_pull_debit">Invoice paid</string>
+    <string name="transaction_peer_push_credit">Push payment</string>
 
     <string name="payment_title">Payment</string>
     <string name="payment_fee">+%s payment fee</string>
@@ -127,9 +128,13 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
     <string name="send_peer_create_button">Send funds now</string>
     <string name="send_peer_warning">Warning: Funds will leave the wallet 
immediately.</string>
     <string name="send_peer_payment_instruction">Let the payee scan this QR 
code to receive:</string>
+    <string name="send_peer_payment_amount_received">Amount received</string>
+    <string name="send_peer_payment_amount_sent">Amount sent</string>
 
     <string name="pay_peer_title">Pay invoice</string>
     <string name="pay_peer_intro">Do you want to pay this invoice?</string>
+    <string name="receive_peer_payment_title">Receive payment</string>
+    <string name="receive_peer_payment_intro">Do you want to receive this 
payment?</string>
 
     <string name="withdraw_initiated">Withdrawal initiated</string>
     <string name="withdraw_title">Withdrawal</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]