[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-android] branch master updated (35f7ed5 -> 78096ab)
From: |
gnunet |
Subject: |
[taler-taler-android] branch master updated (35f7ed5 -> 78096ab) |
Date: |
Wed, 05 Aug 2020 20:49:46 +0200 |
This is an automated email from the git hooks/post-receive script.
torsten-grote pushed a change to branch master
in repository taler-android.
from 35f7ed5 [pos] Implement new refund API (untested since there is no
wallet support)
new b1acd03 [wallet] show more user-friendly error messages for operations
new 78096ab [wallet] support Timestamp with "never"
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../main/java/net/taler/common/TimestampMixin.kt | 12 ++++++
.../java/net/taler/common/ContractTermsTest.kt | 5 ++-
.../src/commonMain/kotlin/net/taler/common/Time.kt | 29 ++++++++++++-
.../commonTest/kotlin/net/taler/common/TimeTest.kt | 49 ++++++++++++++++++++++
wallet/src/main/java/net/taler/wallet/Utils.kt | 17 ++++++++
.../net/taler/wallet/payment/PaymentManager.kt | 8 ++--
.../wallet/pending/PendingOperationsManager.kt | 2 +-
.../java/net/taler/wallet/refund/RefundManager.kt | 1 +
.../wallet/transactions/TransactionManager.kt | 5 ++-
.../wallet/transactions/TransactionsFragment.kt | 4 +-
.../net/taler/wallet/withdraw/WithdrawManager.kt | 4 +-
wallet/src/main/res/values-fr/strings.xml | 2 +-
wallet/src/main/res/values/strings.xml | 2 +-
13 files changed, 125 insertions(+), 15 deletions(-)
create mode 100644
taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TimeTest.kt
diff --git
a/taler-kotlin-android/src/main/java/net/taler/common/TimestampMixin.kt
b/taler-kotlin-android/src/main/java/net/taler/common/TimestampMixin.kt
index 28dbe7f..6c1bebf 100644
--- a/taler-kotlin-android/src/main/java/net/taler/common/TimestampMixin.kt
+++ b/taler-kotlin-android/src/main/java/net/taler/common/TimestampMixin.kt
@@ -17,11 +17,23 @@
package net.taler.common
import com.fasterxml.jackson.annotation.JsonProperty
+import com.fasterxml.jackson.core.JsonParser
+import com.fasterxml.jackson.databind.DeserializationContext
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer
/**
* Used to support Jackson serialization along with KotlinX.
*/
abstract class TimestampMixin(
+ @get:JsonDeserialize(using = NeverDeserializer::class)
@get:JsonProperty("t_ms")
val ms: Long
)
+
+class NeverDeserializer : StdDeserializer<Long>(Long::class.java) {
+ override fun deserialize(p: JsonParser, ctxt: DeserializationContext):
Long {
+ return if (p.text == "never") -1
+ else p.longValue
+ }
+}
diff --git
a/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
b/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
index 79a7598..077ff51 100644
--- a/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
+++ b/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.fasterxml.jackson.module.kotlin.readValue
+import net.taler.common.Timestamp.Companion.NEVER
import org.junit.Assert.assertEquals
import org.junit.Test
@@ -29,6 +30,7 @@ class ContractTermsTest {
.registerModule(KotlinModule())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.addMixIn(Amount::class.java, AmountMixin::class.java)
+ .addMixIn(Timestamp::class.java, TimestampMixin::class.java)
@Test
fun test() {
@@ -40,7 +42,7 @@ class ContractTermsTest {
},
"fulfillment_url":"https://shop.test.taler.net/essay/1._The_Free_Software_Definition",
"summary":"Essay: 1. The Free Software Definition",
- "refund_deadline":{"t_ms":1596128414000},
+ "refund_deadline":{"t_ms":"never"},
"wire_transfer_deadline":{"t_ms":1596128564000},
"products":[],
"h_wire":"KV40K023N8EC1F5100TYNS23C4XN68Y1Z3PTJSWFGTMCNYD54KT4S791V2VQ91SZANN86VDAA369M4VEZ0KR6DN71EVRRZA71K681M0",
@@ -69,6 +71,7 @@ class ContractTermsTest {
""".trimIndent()
val contractTerms: ContractTerms = mapper.readValue(json)
assertEquals("Essay: 1. The Free Software Definition",
contractTerms.summary)
+ assertEquals(Timestamp(NEVER), contractTerms.refundDeadline)
}
}
diff --git a/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Time.kt
b/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Time.kt
index 962e004..37b6606 100644
--- a/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Time.kt
+++ b/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Time.kt
@@ -18,6 +18,12 @@ package net.taler.common
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
+import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.JsonPrimitive
+import kotlinx.serialization.json.JsonTransformingSerializer
+import kotlinx.serialization.json.contentOrNull
+import kotlinx.serialization.json.longOrNull
import net.taler.common.Duration.Companion.FOREVER
import kotlin.math.max
@@ -26,11 +32,12 @@ expect fun nowMillis(): Long
@Serializable
data class Timestamp(
@SerialName("t_ms")
+ @Serializable(NeverSerializer::class)
val ms: Long
) : Comparable<Timestamp> {
companion object {
- const val NEVER: Long = -1 // TODO or UINT64_MAX?
+ const val NEVER: Long = -1
fun now(): Timestamp = Timestamp(nowMillis())
}
@@ -73,9 +80,27 @@ data class Duration(
* Duration in milliseconds.
*/
@SerialName("d_ms")
+ @Serializable(ForeverSerializer::class)
val ms: Long
) {
companion object {
- const val FOREVER: Long = -1 // TODO or UINT64_MAX?
+ const val FOREVER: Long = -1
}
}
+
+abstract class MinusOneSerializer(private val keyword: String) :
+ JsonTransformingSerializer<Long>(Long.serializer(), keyword) {
+
+ override fun readTransform(element: JsonElement): JsonElement {
+ return if (element.contentOrNull == keyword) return JsonPrimitive(-1)
+ else super.readTransform(element)
+ }
+
+ override fun writeTransform(element: JsonElement): JsonElement {
+ return if (element.longOrNull == -1L) return JsonPrimitive(keyword)
+ else element
+ }
+}
+
+object NeverSerializer : MinusOneSerializer("never")
+object ForeverSerializer : MinusOneSerializer("forever")
diff --git
a/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TimeTest.kt
b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TimeTest.kt
new file mode 100644
index 0000000..3ee0a99
--- /dev/null
+++ b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TimeTest.kt
@@ -0,0 +1,49 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.common
+
+import kotlinx.serialization.UnstableDefault
+import kotlinx.serialization.json.Json.Default.parse
+import kotlinx.serialization.json.Json.Default.stringify
+import net.taler.common.Timestamp.Companion.NEVER
+import kotlin.random.Random
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+// TODO test other functionality of Timestamp and Duration
+@UnstableDefault
+class TimeTest {
+
+ @Test
+ fun testSerialize() {
+ for (i in 0 until 42) {
+ val t = Random.nextLong()
+ assertEquals("""{"t_ms":$t}""", stringify(Timestamp.serializer(),
Timestamp(t)))
+ }
+ assertEquals("""{"t_ms":"never"}""", stringify(Timestamp.serializer(),
Timestamp(NEVER)))
+ }
+
+ @Test
+ fun testDeserialize() {
+ for (i in 0 until 42) {
+ val t = Random.nextLong()
+ assertEquals(Timestamp(t), parse(Timestamp.serializer(), """{
"t_ms": $t }"""))
+ }
+ assertEquals(Timestamp(NEVER), parse(Timestamp.serializer(), """{
"t_ms": "never" }"""))
+ }
+
+}
diff --git a/wallet/src/main/java/net/taler/wallet/Utils.kt
b/wallet/src/main/java/net/taler/wallet/Utils.kt
index e299245..ea01552 100644
--- a/wallet/src/main/java/net/taler/wallet/Utils.kt
+++ b/wallet/src/main/java/net/taler/wallet/Utils.kt
@@ -30,6 +30,7 @@ import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.annotation.RequiresApi
import com.google.zxing.integration.android.IntentIntegrator
+import org.json.JSONObject
fun scanQrCode(activity: Activity) {
IntentIntegrator(activity).apply {
@@ -90,6 +91,22 @@ private fun connectToWifiDeprecated(context: Context, ssid:
String) {
}
}
+fun getErrorString(json: JSONObject): String {
+ return StringBuilder().apply {
+ append(json.getString("talerErrorCode"))
+ append(" ")
+ append(json.getString("message"))
+ json.optJSONObject("details")?.let { details ->
+ details.optJSONObject("errorResponse")?.let { errorResponse ->
+ append("\n\n")
+ append(errorResponse.optString("code"))
+ append(" ")
+ append(errorResponse.optString("hint"))
+ }
+ }
+ }.toString()
+}
+
fun cleanExchange(exchange: String) = exchange.let {
if (it.startsWith("https://")) it.substring(8) else it
}.trimEnd('/')
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
index 2427afb..db21da4 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
@@ -26,6 +26,7 @@ import net.taler.common.Amount
import net.taler.common.ContractTerms
import net.taler.wallet.TAG
import net.taler.wallet.backend.WalletBackendApi
+import net.taler.wallet.getErrorString
import net.taler.wallet.payment.PayStatus.AlreadyPaid
import net.taler.wallet.payment.PayStatus.InsufficientBalance
import net.taler.wallet.payment.PreparePayResponse.AlreadyConfirmedResponse
@@ -71,7 +72,7 @@ class PaymentManager(
val args = JSONObject(mapOf("talerPayUri" to url))
walletBackendApi.sendRequest("preparePay", args) { isError, result ->
if (isError) {
- handleError("preparePay", result.toString(2))
+ handleError("preparePay", getErrorString(result))
return@sendRequest
}
val response: PreparePayResponse =
mapper.readValue(result.toString())
@@ -84,6 +85,7 @@ class PaymentManager(
}
}
+ // TODO validate product images (or leave to wallet-core?)
private fun getContractTerms(json: JSONObject): ContractTerms {
val terms: ContractTerms =
mapper.readValue(json.getString("contractTermsRaw"))
// validate product images
@@ -101,7 +103,7 @@ class PaymentManager(
val args = JSONObject(mapOf("proposalId" to proposalId))
walletBackendApi.sendRequest("confirmPay", args) { isError, result ->
if (isError) {
- handleError("preparePay", result.toString())
+ handleError("preparePay", getErrorString(result))
return@sendRequest
}
mPayStatus.postValue(PayStatus.Success(currency))
@@ -124,7 +126,7 @@ class PaymentManager(
walletBackendApi.sendRequest("abortProposal", args) { isError, result
->
if (isError) {
- handleError("abortProposal", result.toString(2))
+ handleError("abortProposal", getErrorString(result))
Log.e(TAG, "received error response to abortProposal")
return@sendRequest
}
diff --git
a/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt
b/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt
index 7027687..df778ed 100644
--- a/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt
@@ -34,7 +34,7 @@ class PendingOperationsManager(private val walletBackendApi:
WalletBackendApi) {
internal fun getPending() {
walletBackendApi.sendRequest("getPendingOperations") { isError, result
->
if (isError) {
- Log.i(TAG, "got getPending error result: $result")
+ Log.i(TAG, "got getPending error result:
${result.toString(2)}")
return@sendRequest
}
Log.i(TAG, "got getPending result")
diff --git a/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
b/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
index 21c634e..5593486 100644
--- a/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
@@ -36,6 +36,7 @@ class RefundManager(private val walletBackendApi:
WalletBackendApi) {
walletBackendApi.sendRequest("applyRefund", args) { isError, result ->
if (isError) {
Log.e(TAG, "Refund Error: $result")
+ // TODO show error string
liveData.postValue(RefundStatus.Error)
} else {
Log.e(TAG, "Refund Success: $result")
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
index bd37b37..8ec3914 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
@@ -27,12 +27,13 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.taler.wallet.backend.WalletBackendApi
+import net.taler.wallet.getErrorString
import org.json.JSONObject
import java.util.HashMap
import java.util.LinkedList
sealed class TransactionsResult {
- object Error : TransactionsResult()
+ class Error(val msg: String) : TransactionsResult()
class Success(val transactions: List<Transaction>) : TransactionsResult()
}
@@ -72,7 +73,7 @@ class TransactionManager(
searchQuery?.let { request.put("search", it) }
walletBackendApi.sendRequest("getTransactions", request) { isError,
result ->
if (isError) {
- liveData.postValue(TransactionsResult.Error)
+
liveData.postValue(TransactionsResult.Error(getErrorString(result)))
mProgress.postValue(false)
} else {
val currencyToUpdate = if (searchQuery == null) currency else
null
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
index 2ae58c3..8d47a3f 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -160,9 +160,9 @@ class TransactionsFragment : Fragment(),
OnTransactionClickListener, ActionMode.
}
private fun onTransactionsResult(result: TransactionsResult) = when
(result) {
- TransactionsResult.Error -> {
+ is TransactionsResult.Error -> {
list.fadeOut()
- emptyState.text = getString(R.string.transactions_error)
+ emptyState.text = getString(R.string.transactions_error,
result.msg)
emptyState.fadeIn()
}
is TransactionsResult.Success -> {
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
index e14a747..6fb9390 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
@@ -26,6 +26,7 @@ import net.taler.wallet.TAG
import net.taler.wallet.backend.WalletBackendApi
import net.taler.wallet.exchanges.ExchangeFees
import net.taler.wallet.exchanges.ExchangeItem
+import net.taler.wallet.getErrorString
import net.taler.wallet.withdraw.WithdrawStatus.ReceivedDetails
import org.json.JSONObject
@@ -196,8 +197,7 @@ class WithdrawManager(
@UiThread
private fun handleError(operation: String, result: JSONObject) {
Log.e(TAG, "Error $operation ${result.toString(2)}")
- val message = if (result.has("message")) result.getString("message")
else null
- withdrawStatus.value = WithdrawStatus.Error(message)
+ withdrawStatus.value = WithdrawStatus.Error(getErrorString(result))
}
}
diff --git a/wallet/src/main/res/values-fr/strings.xml
b/wallet/src/main/res/values-fr/strings.xml
index c4cac45..a96e23a 100644
--- a/wallet/src/main/res/values-fr/strings.xml
+++ b/wallet/src/main/res/values-fr/strings.xml
@@ -26,7 +26,7 @@
<string name="balances_inbound_label">entrant</string>
<string name="transactions_title">Transactions</string>
<string name="transactions_empty">Vous n\'avez aucune transaction</string>
- <string name="transactions_error">Impossible de charger les
transactions</string>
+ <string name="transactions_error">Impossible de charger les
transactions\n\n%s</string>
<string name="transactions_detail_title">Transaction</string>
<string name="transactions_detail_title_balance">Solde : %s</string>
<string name="transactions_delete">Supprimer</string>
diff --git a/wallet/src/main/res/values/strings.xml
b/wallet/src/main/res/values/strings.xml
index 1e629a6..1715ab3 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -70,7 +70,7 @@ GNU Taler is immune against many types of fraud, such as
phishing of credit card
<string name="transactions_title">Transactions</string>
<string name="transactions_empty">You don\'t have any transactions</string>
<string name="transactions_empty_search">No transactions found. Try a
different search.</string>
- <string name="transactions_error">Could not load transactions</string>
+ <string name="transactions_error">Could not load
transactions\n\n%s</string>
<string name="transactions_detail_title">Transaction</string>
<string name="transactions_detail_title_balance">Balance: %s</string>
<string name="transactions_delete">Delete</string>
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-android] branch master updated (35f7ed5 -> 78096ab),
gnunet <=