taler-android

Android apps for GNU Taler (wallet, PoS, cashier)
Log | Files | Refs | README | LICENSE

commit 5bd7a283d3d223d5b4a8db45e62e88c362490287
parent 5e855250787aea09c8e854545fc0539ca5ac0e86
Author: Iván Ávalos <avalos@disroot.org>
Date:   Thu, 23 Jul 2026 21:42:53 +0200

[wallet] fix #11361 (default expiration)

Diffstat:
Mtaler-kotlin-android/src/main/java/net/taler/common/Time.kt | 2++
Mwallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt | 47+++++++++++++++++++++++++++++------------------
Mwallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt | 2++
Mwallet/src/main/java/net/taler/wallet/peer/PeerManager.kt | 13+++----------
4 files changed, 36 insertions(+), 28 deletions(-)

diff --git a/taler-kotlin-android/src/main/java/net/taler/common/Time.kt b/taler-kotlin-android/src/main/java/net/taler/common/Time.kt @@ -86,6 +86,8 @@ data class RelativeTime( ) { val ms: Long = us / 1000L + fun toHours(): Long = ms / (60 * 60 * 1000L) + companion object { internal const val FOREVER: Long = -1 fun forever(): RelativeTime = fromMillis(FOREVER) diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt @@ -48,6 +48,7 @@ import androidx.compose.ui.unit.dp import kotlinx.serialization.json.JsonPrimitive import net.taler.common.Amount import net.taler.common.CurrencySpecification +import net.taler.common.RelativeTime import net.taler.wallet.BottomInsetsSpacer import net.taler.wallet.R import net.taler.wallet.backend.TalerErrorCode @@ -121,6 +122,10 @@ fun OutgoingPushIntroComposable( amount.useDebounce { feeResult = getFees(it) ?: None() + (feeResult as? Success)?.let { res -> + option = ExpirationOption.CUSTOM + hours = res.defaultExpiration.toHours() + } } val amountFocusRequester = remember { FocusRequester() } @@ -247,21 +252,23 @@ fun OutgoingPushIntroComposable( }, ) - Text( - modifier = Modifier.padding(top = 8.dp, start = 16.dp, end = 16.dp), - text = stringResource(R.string.send_peer_expiration_period), - style = MaterialTheme.typography.bodyMedium, - ) + if (devMode) { + Text( + modifier = Modifier.padding(top = 8.dp, start = 16.dp, end = 16.dp), + text = stringResource(R.string.send_peer_expiration_period), + style = MaterialTheme.typography.bodyMedium, + ) - ExpirationComposable( - modifier = Modifier.padding( - vertical = 8.dp, - horizontal = 16.dp, - ), - option = option, - hours = hours, - onOptionChange = { option = it } - ) { hours = it } + ExpirationComposable( + modifier = Modifier.padding( + vertical = 8.dp, + horizontal = 16.dp, + ), + option = option, + hours = hours, + onOptionChange = { option = it } + ) { hours = it } + } (feeResult as? Success)?.let { if (amount.scope is ScopeInfo.Global) { @@ -318,7 +325,8 @@ fun PeerPushComposableCreatingPreview() { getFees = { Success( amountEffective = Amount.fromJSONString("KUDOS:10"), amountRaw = Amount.fromJSONString("KUDOS:12"), - exchangeBaseUrl = "https://exchange.demo.taler.net" + exchangeBaseUrl = "https://exchange.demo.taler.net", + defaultExpiration = RelativeTime.fromMillis(10 * 24 * 60 * 60 * 1000), ) }, onSend = { _, _, _ -> }, ) @@ -344,7 +352,8 @@ fun PeerPushComposableCheckingPreview() { amountEffective = Amount.fromJSONString("KUDOS:10"), amountRaw = Amount.fromJSONString("KUDOS:12"), maxDepositAmountEffective = Amount.fromJSONString("KUDOS:12"), - exchangeBaseUrl = "https://exchange.demo.taler.net" + exchangeBaseUrl = "https://exchange.demo.taler.net", + defaultExpiration = RelativeTime.fromMillis(10 * 24 * 60 * 60 * 1000), ) }, onSend = { _, _, _ -> }, ) @@ -372,7 +381,8 @@ fun PeerPushComposableCheckedPreview() { amountEffective = Amount.fromJSONString("KUDOS:10"), amountRaw = Amount.fromJSONString("KUDOS:12"), maxDepositAmountEffective = Amount.fromJSONString("KUDOS:12"), - exchangeBaseUrl = "https://exchange.demo.taler.net" + exchangeBaseUrl = "https://exchange.demo.taler.net", + defaultExpiration = RelativeTime.fromMillis(10 * 24 * 60 * 60 * 1000), ) }, onSend = { _, _, _ -> }, ) @@ -399,7 +409,8 @@ fun PeerPushComposableErrorPreview() { amountEffective = Amount.fromJSONString("KUDOS:10"), amountRaw = Amount.fromJSONString("KUDOS:12"), maxDepositAmountEffective = Amount.fromJSONString("KUDOS:12"), - exchangeBaseUrl = "https://exchange.demo.taler.net" + exchangeBaseUrl = "https://exchange.demo.taler.net", + defaultExpiration = RelativeTime.fromMillis(10 * 24 * 60 * 60 * 1000), ) }, onSend = { _, _, _ -> }, ) diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingState.kt @@ -19,6 +19,7 @@ package net.taler.wallet.peer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import net.taler.common.Amount +import net.taler.common.RelativeTime import net.taler.common.Timestamp import net.taler.wallet.backend.TalerErrorInfo import net.taler.wallet.exchanges.ExchangeTosStatus @@ -76,6 +77,7 @@ sealed class CheckPeerPushDebitResponse { val amountEffective: Amount, val exchangeBaseUrl: String, val maxExpirationDate: Timestamp, + val defaultExpiration: RelativeTime, ) : CheckPeerPushDebitResponse() @Serializable diff --git a/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt b/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt @@ -27,6 +27,7 @@ import kotlinx.coroutines.launch import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import net.taler.common.Amount +import net.taler.common.RelativeTime import net.taler.common.Timestamp import net.taler.wallet.main.TAG import net.taler.wallet.backend.BackendManager @@ -65,6 +66,7 @@ sealed class CheckFeeResult { val amountRaw: Amount, val amountEffective: Amount, val exchangeBaseUrl: String, + val defaultExpiration: RelativeTime, override val maxDepositAmountEffective: Amount? = null, override val maxDepositAmountRaw: Amount? = null, ): CheckFeeResult() @@ -179,16 +181,6 @@ class PeerManager( maxDepositAmountRaw = max?.rawAmount, ) - if (amount.isZero() && exchangeBaseUrl != null) { - return CheckFeeResult.Success( - amountRaw = amount, - amountEffective = amount, - maxDepositAmountEffective = max?.effectiveAmount, - maxDepositAmountRaw = max?.rawAmount, - exchangeBaseUrl = exchangeBaseUrl, - ) - } - api.request("checkPeerPushDebitV2", CheckPeerPushDebitResponse.serializer()) { exchangeBaseUrl?.let { put("exchangeBaseUrl", it) } restrictScope?.let { put("restrictScope", JSONObject(BackendManager.json.encodeToString(it))) } @@ -201,6 +193,7 @@ class PeerManager( maxDepositAmountEffective = max?.effectiveAmount, maxDepositAmountRaw = max?.rawAmount, exchangeBaseUrl = r.exchangeBaseUrl, + defaultExpiration = r.defaultExpiration, ) is CheckPeerPushDebitInsufficientBalanceResponse -> CheckFeeResult.InsufficientBalance(