gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-android] 01/02: [wallet] Add support for expiration of peer


From: gnunet
Subject: [taler-taler-android] 01/02: [wallet] Add support for expiration of peer payments
Date: Tue, 21 Mar 2023 16:16:11 +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 1c979ef1d0efd8bdaed7dda292825c41f1d48893
Author: Iván Ávalos <avalos@disroot.org>
AuthorDate: Thu Feb 23 11:30:29 2023 -0600

    [wallet] Add support for expiration of peer payments
    
    bug 0007439
---
 .../net/taler/wallet/compose/NumericInputField.kt  |  71 ++++++++++++
 .../java/net/taler/wallet/compose/SelectionChip.kt |  48 ++++++++
 .../net/taler/wallet/peer/ExpirationComposable.kt  | 128 +++++++++++++++++++++
 .../net/taler/wallet/peer/OutgoingPullFragment.kt  |   4 +-
 .../wallet/peer/OutgoingPullIntroComposable.kt     |  24 +++-
 .../net/taler/wallet/peer/OutgoingPushFragment.kt  |   4 +-
 .../wallet/peer/OutgoingPushIntroComposable.kt     |  44 +++++--
 .../main/java/net/taler/wallet/peer/PeerManager.kt |  10 +-
 wallet/src/main/res/values/strings.xml             |   7 ++
 9 files changed, 316 insertions(+), 24 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/compose/NumericInputField.kt 
b/wallet/src/main/java/net/taler/wallet/compose/NumericInputField.kt
new file mode 100644
index 0000000..c9d2fc5
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/compose/NumericInputField.kt
@@ -0,0 +1,71 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2023 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.compose
+
+import androidx.compose.foundation.layout.Row
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.Remove
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.OutlinedTextField
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun NumericInputField(
+    modifier: Modifier = Modifier,
+    value: Long,
+    onValueChange: (Long) -> Unit,
+    readOnly: Boolean = true,
+    label: @Composable () -> Unit,
+    minValue: Long? = 0L,
+    maxValue: Long? = null,
+) {
+    OutlinedTextField(
+        modifier = modifier,
+        value = value.toString(),
+        readOnly = readOnly,
+        onValueChange = {
+            val dd = it.toLongOrNull() ?: 0
+            onValueChange(dd)
+        },
+        trailingIcon = {
+            Row {
+                IconButton(
+                    content = { Icon(Icons.Default.Remove, "add1") },
+                    onClick = {
+                        if (minValue != null && value - 1 >= minValue) {
+                            onValueChange(value - 1)
+                        }
+                    },
+                )
+                IconButton(
+                    content = { Icon(Icons.Default.Add, "add1") },
+                    onClick = {
+                        if (maxValue != null && value + 1 <= maxValue) {
+                            onValueChange(value + 1)
+                        }
+                    },
+                )
+            }
+        },
+        label = label,
+    )
+}
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/compose/SelectionChip.kt 
b/wallet/src/main/java/net/taler/wallet/compose/SelectionChip.kt
new file mode 100644
index 0000000..454bbfa
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/compose/SelectionChip.kt
@@ -0,0 +1,48 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2023 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.compose
+
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.SuggestionChip
+import androidx.compose.material3.SuggestionChipDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun <T> SelectionChip(
+    label: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    selected: Boolean,
+    value: T,
+    onSelected: (T) -> Unit,
+) {
+    val theme = MaterialTheme.colorScheme
+    SuggestionChip(
+        label = label,
+        modifier = modifier,
+        onClick = {
+            onSelected(value)
+        },
+        colors = SuggestionChipDefaults.suggestionChipColors(
+            containerColor = if (selected) theme.primaryContainer else 
Color.Transparent,
+            labelColor = if (selected) theme.onPrimaryContainer else 
theme.onSurface
+        )
+    )
+}
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/peer/ExpirationComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/ExpirationComposable.kt
new file mode 100644
index 0000000..4393e47
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/peer/ExpirationComposable.kt
@@ -0,0 +1,128 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2023 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.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+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 net.taler.wallet.R
+import net.taler.wallet.compose.NumericInputField
+import net.taler.wallet.compose.SelectionChip
+import net.taler.wallet.compose.TalerSurface
+
+enum class ExpirationOption(val hours: Long) {
+    DAYS_1(24),
+    DAYS_7(24 * 7),
+    DAYS_30(24 * 30),
+    CUSTOM(-1)
+}
+
+@Composable
+fun ExpirationComposable(
+    modifier: Modifier = Modifier,
+    option: ExpirationOption,
+    hours: Long,
+    onOptionChange: (ExpirationOption) -> Unit,
+    onHoursChange: (Long) -> Unit,
+) {
+    val options = listOf(
+        ExpirationOption.DAYS_1 to 
stringResource(R.string.send_peer_expiration_1d),
+        ExpirationOption.DAYS_7 to 
stringResource(R.string.send_peer_expiration_7d),
+        ExpirationOption.DAYS_30 to 
stringResource(R.string.send_peer_expiration_30d),
+        ExpirationOption.CUSTOM to 
stringResource(R.string.send_peer_expiration_custom),
+    )
+    Column(
+        modifier = modifier,
+    ) {
+        LazyRow(
+            modifier = Modifier.fillMaxWidth(),
+            horizontalArrangement = Arrangement.SpaceBetween,
+        ) {
+            items(items = options, key = { it.first }) {
+                SelectionChip(
+                    label = { Text(it.second) },
+                    modifier = Modifier.padding(horizontal = 4.dp),
+                    selected = it.first == option,
+                    value = it.first,
+                    onSelected = { o ->
+                        onOptionChange(o)
+                        if (o != ExpirationOption.CUSTOM) {
+                            onHoursChange(o.hours)
+                        }
+                    },
+                )
+            }
+        }
+
+        if (option == ExpirationOption.CUSTOM) {
+            val d = hours / 24L
+            val h = hours - d * 24L
+            Row(
+                modifier = Modifier.fillMaxWidth(),
+            ) {
+                NumericInputField(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .weight(1f)
+                        .padding(end = 4.dp),
+                    value = d,
+                    onValueChange = {
+                        onHoursChange(it * 24 + h)
+                    },
+                    label = { 
Text(stringResource(R.string.send_peer_expiration_days)) },
+                    maxValue = 365,
+                )
+                NumericInputField(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .weight(1f)
+                        .padding(start = 4.dp),
+                    value = h,
+                    onValueChange = {
+                        onHoursChange(d * 24 + it)
+                    },
+                    label = { 
Text(stringResource(R.string.send_peer_expiration_hours)) },
+                    maxValue = 23,
+                )
+            }
+        }
+    }
+}
+
+@Preview
+@Composable
+fun ExpirationComposablePreview() {
+    TalerSurface {
+        var option = ExpirationOption.CUSTOM
+        var hours = 25L
+        ExpirationComposable(
+            option = option,
+            hours = hours,
+            onOptionChange = { option = it }
+        ) { hours = it }
+    }
+}
\ 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 79030f1..565aeb1 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullFragment.kt
@@ -76,7 +76,7 @@ class OutgoingPullFragment : Fragment() {
         if (!requireActivity().isChangingConfigurations) 
peerManager.resetPullPayment()
     }
 
-    private fun onCreateInvoice(amount: Amount, summary: String, exchange: 
ExchangeItem) {
-        peerManager.initiatePeerPullCredit(amount, summary, exchange)
+    private fun onCreateInvoice(amount: Amount, summary: String, hours: Long, 
exchange: ExchangeItem) {
+        peerManager.initiatePeerPullCredit(amount, summary, hours, exchange)
     }
 }
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt
index a7cd2a8..a8f24fd 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullIntroComposable.kt
@@ -50,6 +50,7 @@ import net.taler.wallet.exchanges.ExchangeItem
 import net.taler.wallet.transactions.AmountType
 import net.taler.wallet.transactions.TransactionAmountComposable
 import net.taler.wallet.transactions.TransactionInfoComposable
+import net.taler.wallet.peer.ExpirationOption.DAYS_1
 import kotlin.random.Random
 
 @OptIn(ExperimentalMaterial3Api::class)
@@ -57,7 +58,7 @@ import kotlin.random.Random
 fun OutgoingPullIntroComposable(
     amount: Amount,
     state: OutgoingState,
-    onCreateInvoice: (amount: Amount, subject: String, exchange: ExchangeItem) 
-> Unit,
+    onCreateInvoice: (amount: Amount, subject: String, hours: Long, exchange: 
ExchangeItem) -> Unit,
 ) {
     val scrollState = rememberScrollState()
     Column(
@@ -72,7 +73,6 @@ fun OutgoingPullIntroComposable(
         OutlinedTextField(
             modifier = Modifier
                 .fillMaxWidth()
-                .padding(top = 16.dp, start = 16.dp, end = 16.dp)
                 .focusRequester(focusRequester),
             singleLine = true,
             value = subject,
@@ -96,7 +96,7 @@ fun OutgoingPullIntroComposable(
         Text(
             modifier = Modifier
                 .fillMaxWidth()
-                .padding(top = 5.dp, end = 16.dp),
+                .padding(top = 5.dp),
             color = if (subject.isBlank()) MaterialTheme.colorScheme.error 
else Color.Unspecified,
             text = stringResource(R.string.char_count, subject.length, 
MAX_LENGTH_SUBJECT),
             textAlign = TextAlign.End,
@@ -119,6 +119,19 @@ fun OutgoingPullIntroComposable(
             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(DAYS_1) }
+        var hours by rememberSaveable { mutableStateOf(1L) }
+        ExpirationComposable(
+            modifier = Modifier.padding(top = 8.dp, bottom = 16.dp),
+            option = option,
+            hours = hours,
+            onOptionChange = { option = it }
+        ) { hours = it }
         Button(
             modifier = Modifier.padding(16.dp),
             enabled = subject.isNotBlank() && state is OutgoingChecked,
@@ -126,6 +139,7 @@ fun OutgoingPullIntroComposable(
                 onCreateInvoice(
                     amount,
                     subject,
+                    hours,
                     exchangeItem ?: error("clickable without exchange")
                 )
             },
@@ -142,7 +156,7 @@ fun PreviewReceiveFundsCheckingIntro() {
         OutgoingPullIntroComposable(
             Amount.fromDouble("TESTKUDOS", 42.23),
             if (Random.nextBoolean()) OutgoingIntro else OutgoingChecking,
-        ) { _, _, _ -> }
+        ) { _, _, _, _ -> }
     }
 }
 
@@ -156,6 +170,6 @@ fun PreviewReceiveFundsCheckedIntro() {
         OutgoingPullIntroComposable(
             Amount.fromDouble("TESTKUDOS", 42.23),
             OutgoingChecked(amountRaw, amountEffective, exchangeItem)
-        ) { _, _, _ -> }
+        ) { _, _, _, _ -> }
     }
 }
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 7019757..0aa029b 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushFragment.kt
@@ -74,7 +74,7 @@ class OutgoingPushFragment : Fragment() {
         if (!requireActivity().isChangingConfigurations) 
peerManager.resetPushPayment()
     }
 
-    private fun onSend(amount: Amount, summary: String) {
-        peerManager.initiatePeerPushDebit(amount, summary)
+    private fun onSend(amount: Amount, summary: String, hours: Long) {
+        peerManager.initiatePeerPushDebit(amount, summary, hours)
     }
 }
diff --git 
a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt 
b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt
index 33e8390..63542a8 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushIntroComposable.kt
@@ -16,7 +16,6 @@
 
 package net.taler.wallet.peer
 
-import androidx.compose.foundation.layout.Arrangement.spacedBy
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
@@ -29,12 +28,16 @@ import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.Surface
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
 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.CenterHorizontally
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextAlign
@@ -42,6 +45,7 @@ import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import net.taler.common.Amount
 import net.taler.wallet.R
+import net.taler.wallet.peer.ExpirationOption.DAYS_1
 import kotlin.random.Random
 
 @OptIn(ExperimentalMaterial3Api::class)
@@ -49,7 +53,7 @@ import kotlin.random.Random
 fun OutgoingPushIntroComposable(
     state: OutgoingState,
     amount: Amount,
-    onSend: (amount: Amount, summary: String) -> Unit,
+    onSend: (amount: Amount, summary: String, hours: Long) -> Unit,
 ) {
     val scrollState = rememberScrollState()
     Column(
@@ -58,9 +62,9 @@ fun OutgoingPushIntroComposable(
             .padding(16.dp)
             .verticalScroll(scrollState),
         horizontalAlignment = CenterHorizontally,
-        verticalArrangement = spacedBy(16.dp),
     ) {
         Text(
+            modifier = Modifier.padding(vertical = 16.dp),
             text = amount.toString(),
             softWrap = false,
             style = MaterialTheme.typography.titleLarge,
@@ -68,6 +72,7 @@ fun OutgoingPushIntroComposable(
         if (state is OutgoingChecked) {
             val fee = state.amountEffective - state.amountRaw
             Text(
+                modifier = Modifier.padding(vertical = 16.dp),
                 text = stringResource(id = R.string.payment_fee, fee),
                 softWrap = false,
                 color = MaterialTheme.colorScheme.error,
@@ -75,8 +80,11 @@ fun OutgoingPushIntroComposable(
         }
 
         var subject by rememberSaveable { mutableStateOf("") }
+        val focusRequester = remember { FocusRequester() }
         OutlinedTextField(
-            modifier = Modifier.fillMaxWidth(),
+            modifier = Modifier
+                .fillMaxWidth()
+                .focusRequester(focusRequester),
             singleLine = true,
             value = subject,
             onValueChange = { input ->
@@ -93,21 +101,37 @@ fun OutgoingPushIntroComposable(
                 )
             }
         )
+        LaunchedEffect(Unit) {
+            focusRequester.requestFocus()
+        }
         Text(
             modifier = Modifier
-                .fillMaxWidth(),
+                .fillMaxWidth()
+                .padding(top = 5.dp),
             color = if (subject.isBlank()) MaterialTheme.colorScheme.error 
else Color.Unspecified,
             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(DAYS_1) }
+        var hours by rememberSaveable { mutableStateOf(DAYS_1.hours) }
+        ExpirationComposable(
+            modifier = Modifier.padding(top = 8.dp, bottom = 16.dp),
+            option = option,
+            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)
-            },
+            onClick = { onSend(amount, subject, hours) },
         ) {
             Text(text = stringResource(R.string.send_peer_create_button))
         }
@@ -119,7 +143,7 @@ fun OutgoingPushIntroComposable(
 fun PeerPushIntroComposableCheckingPreview() {
     Surface {
         val state = if (Random.nextBoolean()) OutgoingIntro else 
OutgoingChecking
-        OutgoingPushIntroComposable(state, Amount.fromDouble("TESTKUDOS", 
42.23)) { _, _ -> }
+        OutgoingPushIntroComposable(state, Amount.fromDouble("TESTKUDOS", 
42.23)) { _, _, _ -> }
     }
 }
 
@@ -130,6 +154,6 @@ fun PeerPushIntroComposableCheckedPreview() {
         val amountEffective = Amount.fromDouble("TESTKUDOS", 42.42)
         val amountRaw = Amount.fromDouble("TESTKUDOS", 42.23)
         val state = OutgoingChecked(amountRaw, amountEffective)
-        OutgoingPushIntroComposable(state, amountEffective) { _, _ -> }
+        OutgoingPushIntroComposable(state, amountEffective) { _, _, _ -> }
     }
 }
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 f031d44..f7796bb 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt
@@ -34,7 +34,7 @@ import net.taler.wallet.backend.WalletBackendApi
 import net.taler.wallet.exchanges.ExchangeItem
 import net.taler.wallet.exchanges.ExchangeManager
 import org.json.JSONObject
-import java.util.concurrent.TimeUnit.DAYS
+import java.util.concurrent.TimeUnit.HOURS
 
 const val MAX_LENGTH_SUBJECT = 100
 
@@ -82,10 +82,10 @@ class PeerManager(
         }
     }
 
-    fun initiatePeerPullCredit(amount: Amount, summary: String, exchange: 
ExchangeItem) {
+    fun initiatePeerPullCredit(amount: Amount, summary: String, 
expirationHours: Long, exchange: ExchangeItem) {
         _outgoingPullState.value = OutgoingCreating
         scope.launch(Dispatchers.IO) {
-            val expiry = Timestamp.fromMillis(System.currentTimeMillis() + 
DAYS.toMillis(3))
+            val expiry = Timestamp.fromMillis(System.currentTimeMillis() + 
HOURS.toMillis(expirationHours))
             api.request("initiatePeerPullCredit", 
InitiatePeerPullPaymentResponse.serializer()) {
                 put("exchangeBaseUrl", exchange.exchangeBaseUrl)
                 put("partialContractTerms", JSONObject().apply {
@@ -125,10 +125,10 @@ class PeerManager(
         }
     }
 
-    fun initiatePeerPushDebit(amount: Amount, summary: String) {
+    fun initiatePeerPushDebit(amount: Amount, summary: String, 
expirationHours: Long) {
         _outgoingPushState.value = OutgoingCreating
         scope.launch(Dispatchers.IO) {
-            val expiry = Timestamp.fromMillis(System.currentTimeMillis() + 
DAYS.toMillis(3))
+            val expiry = Timestamp.fromMillis(System.currentTimeMillis() + 
HOURS.toMillis(expirationHours))
             api.request("initiatePeerPushDebit", 
InitiatePeerPullCreditResponse.serializer()) {
                 put("amount", amount.toJSONString())
                 put("partialContractTerms", JSONObject().apply {
diff --git a/wallet/src/main/res/values/strings.xml 
b/wallet/src/main/res/values/strings.xml
index 52dacfe..c313248 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -151,6 +151,13 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
     <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="send_peer_expiration_period">Expires in</string>
+    <string name="send_peer_expiration_1d">1 day</string>
+    <string name="send_peer_expiration_7d">7 days</string>
+    <string name="send_peer_expiration_30d">30 days</string>
+    <string name="send_peer_expiration_custom">Custom</string>
+    <string name="send_peer_expiration_days">Days</string>
+    <string name="send_peer_expiration_hours">Hours</string>
     <string name="send_peer_purpose">Purpose</string>
 
     <string name="pay_peer_title">Pay invoice</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]