[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-android] 03/04: Split out common code into multiplatform Ko
From: |
gnunet |
Subject: |
[taler-taler-android] 03/04: Split out common code into multiplatform Kotlin library |
Date: |
Thu, 30 Jul 2020 22:12:23 +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.
commit 8815105bf2462787885214a12af927d484226f21
Author: Torsten Grote <t@grobox.de>
AuthorDate: Thu Jul 30 16:40:23 2020 -0300
Split out common code into multiplatform Kotlin library
---
.gitignore | 1 +
.gitlab-ci.yml | 1 +
.idea/gradle.xml | 1 +
anastasis-ui/build.gradle | 2 +-
build.gradle | 4 -
cashier/.gitlab-ci.yml | 1 +
cashier/build.gradle | 2 +-
.../main/java/net/taler/cashier/MainViewModel.kt | 16 ++-
merchant-lib/.gitlab-ci.yml | 1 +
merchant-lib/build.gradle | 2 +-
.../main/java/net/taler/merchantlib/Response.kt | 3 +-
.../java/net/taler/merchantlib/MerchantApiTest.kt | 1 +
merchant-terminal/.gitlab-ci.yml | 1 +
settings.gradle | 3 +
taler-kotlin-android/.gitignore | 1 +
taler-kotlin-android/.gitlab-ci.yml | 12 ++
.../build.gradle | 6 +
.../consumer-rules.pro | 0
.../proguard-rules.pro | 0
.../src/main/AndroidManifest.xml | 0
.../src/main/java/net/taler/common/AmountMixin.kt | 51 +++++++
.../src/main/java/net/taler/common/AndroidUtils.kt | 0
.../main/java/net/taler/common/ByteArrayUtils.kt | 0
.../main/java/net/taler/common/CombinedLiveData.kt | 0
.../main/java/net/taler/common/ContractTerms.kt | 4 +-
.../src/main/java/net/taler/common/Event.kt | 0
.../src/main/java/net/taler/common/NfcManager.kt | 0
.../main/java/net/taler/common/QrCodeManager.kt | 0
.../src/main/java/net/taler/common/SignedAmount.kt | 0
.../src/main/java/net/taler/common/TalerUtils.kt | 3 +-
.../main/res/drawable/selectable_background.xml | 0
.../src/main/res/values-night/colors.xml | 0
.../src/main/res/values/colors.xml | 0
.../src/main/res/values/strings.xml | 0
.../java/net/taler/common/ContractTermsTest.kt | 74 +++++++++++
taler-kotlin-common/.gitlab-ci.yml | 6 +-
taler-kotlin-common/build.gradle | 130 +++++++++---------
.../kotlin}/net/taler/common/Amount.kt | 70 ++--------
.../src/commonMain/kotlin/net/taler/common/Time.kt | 81 ++++++++++++
.../kotlin}/net/taler/common/Version.kt | 0
.../kotlin}/net/taler/common/AmountTest.kt | 147 +++++----------------
.../kotlin/net/taler/common/TestUtils.kt} | 28 +---
.../kotlin}/net/taler/common/VersionTest.kt | 6 +-
.../kotlin/net/taler/common/Time.kt} | 25 +---
.../kotlin/net/taler/common/Time.kt} | 25 +---
.../kotlin/net/taler/common/Time.kt} | 25 +---
wallet/.gitlab-ci.yml | 1 +
wallet/build.gradle | 10 +-
.../main/java/net/taler/wallet/MainViewModel.kt | 5 +
.../net/taler/wallet/exchanges/ExchangeFees.kt | 53 +-------
.../net/taler/wallet/payment/PaymentResponses.kt | 13 +-
51 files changed, 404 insertions(+), 411 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7e4952a..caf9ce6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
*.iml
.gradle
/local.properties
+/.idea/artifacts
/.idea/caches
/.idea/libraries
/.idea/misc.xml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 48f1aec..6dc4426 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -14,6 +14,7 @@ include:
- local: 'merchant-lib/.gitlab-ci.yml'
- local: 'merchant-terminal/.gitlab-ci.yml'
- local: 'taler-kotlin-common/.gitlab-ci.yml'
+ - local: 'taler-kotlin-android/.gitlab-ci.yml'
- local: 'wallet/.gitlab-ci.yml'
after_script:
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 581abbf..01ed15f 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -14,6 +14,7 @@
<option value="$PROJECT_DIR$/cashier" />
<option value="$PROJECT_DIR$/merchant-lib" />
<option value="$PROJECT_DIR$/merchant-terminal" />
+ <option value="$PROJECT_DIR$/taler-kotlin-android" />
<option value="$PROJECT_DIR$/taler-kotlin-common" />
<option value="$PROJECT_DIR$/wallet" />
</set>
diff --git a/anastasis-ui/build.gradle b/anastasis-ui/build.gradle
index 0391c7c..ff0eec5 100644
--- a/anastasis-ui/build.gradle
+++ b/anastasis-ui/build.gradle
@@ -51,7 +51,7 @@ android {
}
dependencies {
- implementation project(":taler-kotlin-common")
+ implementation project(":taler-kotlin-android")
implementation 'com.google.android.material:material:1.2.0-beta01'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
diff --git a/build.gradle b/build.gradle
index 76f687e..442d232 100644
--- a/build.gradle
+++ b/build.gradle
@@ -24,7 +24,3 @@ allprojects {
maven { url 'https://jitpack.io' }
}
}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
diff --git a/cashier/.gitlab-ci.yml b/cashier/.gitlab-ci.yml
index 6a7baed..6b73dee 100644
--- a/cashier/.gitlab-ci.yml
+++ b/cashier/.gitlab-ci.yml
@@ -6,6 +6,7 @@ cashier_test:
changes:
- cashier/**/*
- taler-kotlin-common/**/*
+ - taler-kotlin-android/**/*
- build.gradle
script: ./gradlew :cashier:check :cashier:assembleRelease
artifacts:
diff --git a/cashier/build.gradle b/cashier/build.gradle
index 0d06c60..641a039 100644
--- a/cashier/build.gradle
+++ b/cashier/build.gradle
@@ -54,7 +54,7 @@ android {
}
dependencies {
- implementation project(":taler-kotlin-common")
+ implementation project(":taler-kotlin-android")
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.security:security-crypto:1.0.0-rc02'
implementation 'com.google.android.material:material:1.1.0'
diff --git a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
index c8d9a3b..a4fd35e 100644
--- a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
+++ b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
@@ -40,6 +40,7 @@ import net.taler.common.isOnline
private val TAG = MainViewModel::class.java.simpleName
+private const val VERSION_BANK = "0:0:0"
private const val PREF_NAME = "net.taler.cashier.prefs"
private const val PREF_KEY_BANK_URL = "bankUrl"
private const val PREF_KEY_USERNAME = "username"
@@ -86,20 +87,21 @@ class MainViewModel(private val app: Application) :
AndroidViewModel(app) {
fun checkAndSaveConfig(config: Config) {
mConfigResult.value = null
viewModelScope.launch(Dispatchers.IO) {
- val url = "${config.bankUrl}/accounts/${config.username}/balance"
+ val url = "${config.bankUrl}/config"
Log.d(TAG, "Checking config: $url")
val result = when (val response = makeJsonGetRequest(url, config))
{
is HttpJsonResult.Success -> {
- val balance = response.json.getString("balance")
+ val version = response.json.getString("version")
+ // TODO check if version is compatible
+ val currency = response.json.getString("currency")
try {
- val amount = SignedAmount.fromJSONString(balance)
- mCurrency.postValue(amount.amount.currency)
- prefs.edit().putString(PREF_KEY_CURRENCY,
amount.amount.currency).apply()
+ mCurrency.postValue(currency)
+ prefs.edit().putString(PREF_KEY_CURRENCY,
currency).apply()
// save config
saveConfig(config)
ConfigResult.Success
- } catch (e: AmountParserException) {
- ConfigResult.Error(false, "Invalid Amount: $balance")
+ } catch (e: Exception) {
+ ConfigResult.Error(false, "Invalid Config:
${response.json}")
}
}
is HttpJsonResult.Error -> {
diff --git a/merchant-lib/.gitlab-ci.yml b/merchant-lib/.gitlab-ci.yml
index 62a7516..8f7c7c2 100644
--- a/merchant-lib/.gitlab-ci.yml
+++ b/merchant-lib/.gitlab-ci.yml
@@ -2,6 +2,7 @@ merchant_lib_test:
stage: test
only:
changes:
+ - taler-kotlin-common/**/*
- merchant-lib/**/*
- build.gradle
script: ./gradlew :merchant-lib:check
diff --git a/merchant-lib/build.gradle b/merchant-lib/build.gradle
index 128f4c1..33e8379 100644
--- a/merchant-lib/build.gradle
+++ b/merchant-lib/build.gradle
@@ -45,7 +45,7 @@ android {
}
dependencies {
- api project(":taler-kotlin-common")
+ api project(":taler-kotlin-android")
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
diff --git a/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
b/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
index 9aefa5f..65a12a9 100644
--- a/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
+++ b/merchant-lib/src/main/java/net/taler/merchantlib/Response.kt
@@ -16,7 +16,6 @@
package net.taler.merchantlib
-import android.util.Log
import io.ktor.client.call.receive
import io.ktor.client.features.ClientRequestException
import io.ktor.client.features.ResponseException
@@ -32,7 +31,7 @@ class Response<out T> private constructor(
return try {
success(request())
} catch (e: Throwable) {
- Log.e("merchant-lib", "Error", e)
+ println(e)
failure(e)
}
}
diff --git
a/merchant-lib/src/test/java/net/taler/merchantlib/MerchantApiTest.kt
b/merchant-lib/src/test/java/net/taler/merchantlib/MerchantApiTest.kt
index ea5a12a..deed81e 100644
--- a/merchant-lib/src/test/java/net/taler/merchantlib/MerchantApiTest.kt
+++ b/merchant-lib/src/test/java/net/taler/merchantlib/MerchantApiTest.kt
@@ -113,6 +113,7 @@ class MerchantApiTest {
val unpaidResponse = CheckPaymentResponse.Unpaid(false,
"http://taler.net/foo")
httpClient.giveJsonResponse("http://example.net/instances/testInstance/private/orders/$orderId")
{
"""{
+ "order_status": "unpaid",
"paid": ${unpaidResponse.paid},
"taler_pay_uri": "${unpaidResponse.talerPayUri}"
}""".trimIndent()
diff --git a/merchant-terminal/.gitlab-ci.yml b/merchant-terminal/.gitlab-ci.yml
index 74ac21f..d159902 100644
--- a/merchant-terminal/.gitlab-ci.yml
+++ b/merchant-terminal/.gitlab-ci.yml
@@ -5,6 +5,7 @@ merchant_test:
- merchant-terminal/**/*
- merchant-lib/**/*
- taler-kotlin-common/**/*
+ - taler-kotlin-android/**/*
- build.gradle
script: ./gradlew :merchant-terminal:check :merchant-terminal:assembleRelease
artifacts:
diff --git a/settings.gradle b/settings.gradle
index 14d898d..6175852 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,4 +1,7 @@
include ':cashier', ':merchant-terminal', ':wallet'
include ':taler-kotlin-common'
+include ':taler-kotlin-android'
include ':merchant-lib'
include ':anastasis-ui'
+
+enableFeaturePreview('GRADLE_METADATA')
diff --git a/taler-kotlin-android/.gitignore b/taler-kotlin-android/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/taler-kotlin-android/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/taler-kotlin-android/.gitlab-ci.yml
b/taler-kotlin-android/.gitlab-ci.yml
new file mode 100644
index 0000000..bb5af21
--- /dev/null
+++ b/taler-kotlin-android/.gitlab-ci.yml
@@ -0,0 +1,12 @@
+taler_kotlin_android_test:
+ stage: test
+ only:
+ changes:
+ - taler-kotlin-android/**/*
+ - taler-kotlin-common/**/*
+ - build.gradle
+ script: ./gradlew :taler-kotlin-android:check
+ artifacts:
+ paths:
+ - taler-kotlin-android/build/reports/lint-results.html
+ expire_in: 1 week
diff --git a/taler-kotlin-common/build.gradle
b/taler-kotlin-android/build.gradle
similarity index 95%
copy from taler-kotlin-common/build.gradle
copy to taler-kotlin-android/build.gradle
index dd083b7..d6d6003 100644
--- a/taler-kotlin-common/build.gradle
+++ b/taler-kotlin-android/build.gradle
@@ -43,9 +43,15 @@ android {
}
}
+ packagingOptions {
+ exclude("META-INF/*.kotlin_module")
+ }
+
}
dependencies {
+ api project(":taler-kotlin-common")
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.3.0'
diff --git a/taler-kotlin-common/consumer-rules.pro
b/taler-kotlin-android/consumer-rules.pro
similarity index 100%
rename from taler-kotlin-common/consumer-rules.pro
rename to taler-kotlin-android/consumer-rules.pro
diff --git a/taler-kotlin-common/proguard-rules.pro
b/taler-kotlin-android/proguard-rules.pro
similarity index 100%
rename from taler-kotlin-common/proguard-rules.pro
rename to taler-kotlin-android/proguard-rules.pro
diff --git a/taler-kotlin-common/src/main/AndroidManifest.xml
b/taler-kotlin-android/src/main/AndroidManifest.xml
similarity index 100%
rename from taler-kotlin-common/src/main/AndroidManifest.xml
rename to taler-kotlin-android/src/main/AndroidManifest.xml
diff --git a/taler-kotlin-android/src/main/java/net/taler/common/AmountMixin.kt
b/taler-kotlin-android/src/main/java/net/taler/common/AmountMixin.kt
new file mode 100644
index 0000000..f9b1330
--- /dev/null
+++ b/taler-kotlin-android/src/main/java/net/taler/common/AmountMixin.kt
@@ -0,0 +1,51 @@
+/*
+ * 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 com.fasterxml.jackson.core.JsonGenerator
+import com.fasterxml.jackson.core.JsonParser
+import com.fasterxml.jackson.databind.DeserializationContext
+import com.fasterxml.jackson.databind.JsonMappingException
+import com.fasterxml.jackson.databind.SerializerProvider
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import com.fasterxml.jackson.databind.annotation.JsonSerialize
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer
+import com.fasterxml.jackson.databind.ser.std.StdSerializer
+
+/**
+ * Used to support Jackson serialization along with KotlinX.
+ */
+@JsonSerialize(using = AmountSerializer::class)
+@JsonDeserialize(using = AmountDeserializer::class)
+abstract class AmountMixin
+
+class AmountSerializer : StdSerializer<Amount>(Amount::class.java) {
+ override fun serialize(value: Amount, gen: JsonGenerator, provider:
SerializerProvider) {
+ gen.writeString(value.toJSONString())
+ }
+}
+
+class AmountDeserializer : StdDeserializer<Amount>(Amount::class.java) {
+ override fun deserialize(p: JsonParser, ctxt: DeserializationContext):
Amount {
+ val node = p.codec.readValue(p, String::class.java)
+ try {
+ return Amount.fromJSONString(node)
+ } catch (e: AmountParserException) {
+ throw JsonMappingException(p, "Error parsing Amount", e)
+ }
+ }
+}
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/AndroidUtils.kt
b/taler-kotlin-android/src/main/java/net/taler/common/AndroidUtils.kt
similarity index 100%
rename from taler-kotlin-common/src/main/java/net/taler/common/AndroidUtils.kt
rename to taler-kotlin-android/src/main/java/net/taler/common/AndroidUtils.kt
diff --git
a/taler-kotlin-common/src/main/java/net/taler/common/ByteArrayUtils.kt
b/taler-kotlin-android/src/main/java/net/taler/common/ByteArrayUtils.kt
similarity index 100%
rename from taler-kotlin-common/src/main/java/net/taler/common/ByteArrayUtils.kt
rename to taler-kotlin-android/src/main/java/net/taler/common/ByteArrayUtils.kt
diff --git
a/taler-kotlin-common/src/main/java/net/taler/common/CombinedLiveData.kt
b/taler-kotlin-android/src/main/java/net/taler/common/CombinedLiveData.kt
similarity index 100%
rename from
taler-kotlin-common/src/main/java/net/taler/common/CombinedLiveData.kt
rename to
taler-kotlin-android/src/main/java/net/taler/common/CombinedLiveData.kt
diff --git
a/taler-kotlin-common/src/main/java/net/taler/common/ContractTerms.kt
b/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt
similarity index 96%
rename from taler-kotlin-common/src/main/java/net/taler/common/ContractTerms.kt
rename to taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt
index b891ef7..0d5fe5b 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/ContractTerms.kt
+++ b/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt
@@ -18,7 +18,6 @@ package net.taler.common
import androidx.annotation.RequiresApi
import com.fasterxml.jackson.annotation.JsonIgnore
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY
import com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL
@@ -28,13 +27,14 @@ import kotlinx.serialization.Serializable
import net.taler.common.TalerUtils.getLocalizedString
@Serializable
-@JsonIgnoreProperties(ignoreUnknown = true)
data class ContractTerms(
val summary: String,
@SerialName("summary_i18n")
+ @get:JsonProperty("summary_i18n")
val summaryI18n: Map<String, String>? = null,
val amount: Amount,
@SerialName("fulfillment_url")
+ @get:JsonProperty("fulfillment_url")
val fulfillmentUrl: String,
val products: List<ContractProduct>
)
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/Event.kt
b/taler-kotlin-android/src/main/java/net/taler/common/Event.kt
similarity index 100%
rename from taler-kotlin-common/src/main/java/net/taler/common/Event.kt
rename to taler-kotlin-android/src/main/java/net/taler/common/Event.kt
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/NfcManager.kt
b/taler-kotlin-android/src/main/java/net/taler/common/NfcManager.kt
similarity index 100%
rename from taler-kotlin-common/src/main/java/net/taler/common/NfcManager.kt
rename to taler-kotlin-android/src/main/java/net/taler/common/NfcManager.kt
diff --git
a/taler-kotlin-common/src/main/java/net/taler/common/QrCodeManager.kt
b/taler-kotlin-android/src/main/java/net/taler/common/QrCodeManager.kt
similarity index 100%
rename from taler-kotlin-common/src/main/java/net/taler/common/QrCodeManager.kt
rename to taler-kotlin-android/src/main/java/net/taler/common/QrCodeManager.kt
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
b/taler-kotlin-android/src/main/java/net/taler/common/SignedAmount.kt
similarity index 100%
copy from taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
copy to taler-kotlin-android/src/main/java/net/taler/common/SignedAmount.kt
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/TalerUtils.kt
b/taler-kotlin-android/src/main/java/net/taler/common/TalerUtils.kt
similarity index 97%
rename from taler-kotlin-common/src/main/java/net/taler/common/TalerUtils.kt
rename to taler-kotlin-android/src/main/java/net/taler/common/TalerUtils.kt
index 444caa4..bb2e78a 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/TalerUtils.kt
+++ b/taler-kotlin-android/src/main/java/net/taler/common/TalerUtils.kt
@@ -18,8 +18,7 @@ package net.taler.common
import androidx.annotation.RequiresApi
import androidx.core.os.LocaleListCompat
-import java.util.*
-import kotlin.collections.ArrayList
+import java.util.Locale
object TalerUtils {
diff --git
a/taler-kotlin-common/src/main/res/drawable/selectable_background.xml
b/taler-kotlin-android/src/main/res/drawable/selectable_background.xml
similarity index 100%
rename from taler-kotlin-common/src/main/res/drawable/selectable_background.xml
rename to taler-kotlin-android/src/main/res/drawable/selectable_background.xml
diff --git a/taler-kotlin-common/src/main/res/values-night/colors.xml
b/taler-kotlin-android/src/main/res/values-night/colors.xml
similarity index 100%
rename from taler-kotlin-common/src/main/res/values-night/colors.xml
rename to taler-kotlin-android/src/main/res/values-night/colors.xml
diff --git a/taler-kotlin-common/src/main/res/values/colors.xml
b/taler-kotlin-android/src/main/res/values/colors.xml
similarity index 100%
rename from taler-kotlin-common/src/main/res/values/colors.xml
rename to taler-kotlin-android/src/main/res/values/colors.xml
diff --git a/taler-kotlin-common/src/main/res/values/strings.xml
b/taler-kotlin-android/src/main/res/values/strings.xml
similarity index 100%
rename from taler-kotlin-common/src/main/res/values/strings.xml
rename to taler-kotlin-android/src/main/res/values/strings.xml
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
new file mode 100644
index 0000000..79a7598
--- /dev/null
+++ b/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
@@ -0,0 +1,74 @@
+/*
+ * 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 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 org.junit.Assert.assertEquals
+import org.junit.Test
+
+class ContractTermsTest {
+
+ private val mapper = ObjectMapper()
+ .registerModule(KotlinModule())
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+ .addMixIn(Amount::class.java, AmountMixin::class.java)
+
+ @Test
+ fun test() {
+ val json = """
+ {
+ "amount":"TESTKUDOS:0.5",
+ "extra":{
+ "article_name":"1._The_Free_Software_Definition"
+ },
+
"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},
+ "wire_transfer_deadline":{"t_ms":1596128564000},
+ "products":[],
+
"h_wire":"KV40K023N8EC1F5100TYNS23C4XN68Y1Z3PTJSWFGTMCNYD54KT4S791V2VQ91SZANN86VDAA369M4VEZ0KR6DN71EVRRZA71K681M0",
+ "wire_method":"x-taler-bank",
+ "order_id":"2020.212-01M9VKEAPF76C",
+ "timestamp":{"t_ms":1596128114000},
+ "pay_deadline":{"t_ms":"never"},
+ "max_wire_fee":"TESTKUDOS:1",
+ "max_fee":"TESTKUDOS:1",
+ "wire_fee_amortization":3,
+
"merchant_base_url":"https://backend.test.taler.net/instances/blog/",
+ "merchant":{"name":"Blog","instance":"blog"},
+ "exchanges":[
+ {
+ "url":"https://exchange.test.taler.net/",
+
"master_pub":"DY95EXAHQ2BKM2WK9YHZHYG1R7PPMMJPY14FNGP662DAKE35AKQG"
+ },
+ {
+ "url":"https://exchange.test.taler.net/",
+
"master_pub":"DY95EXAHQ2BKM2WK9YHZHYG1R7PPMMJPY14FNGP662DAKE35AKQG"}
+ ],
+ "auditors":[],
+
"merchant_pub":"8DR9NKSZY1CXFRE47NEYXM0K85C4ZGAYH7Y7VZ22GPNF0BRFNYNG",
+ "nonce":"FK8ZKJRV6VX6YFAG4CDSC6W0DWD084Q09DP81ANF30GRFQYM2KPG"
+ }
+ """.trimIndent()
+ val contractTerms: ContractTerms = mapper.readValue(json)
+ assertEquals("Essay: 1. The Free Software Definition",
contractTerms.summary)
+ }
+
+}
diff --git a/taler-kotlin-common/.gitlab-ci.yml
b/taler-kotlin-common/.gitlab-ci.yml
index 49d3e98..c241e31 100644
--- a/taler-kotlin-common/.gitlab-ci.yml
+++ b/taler-kotlin-common/.gitlab-ci.yml
@@ -4,8 +4,4 @@ taler_kotlin_common_test:
changes:
- taler-kotlin-common/**/*
- build.gradle
- script: ./gradlew :taler-kotlin-common:check
- artifacts:
- paths:
- - taler-kotlin-common/build/reports/lint-results.html
- expire_in: 1 week
+ script: ./gradlew :taler-kotlin-common:jvmTest
diff --git a/taler-kotlin-common/build.gradle b/taler-kotlin-common/build.gradle
index dd083b7..129881d 100644
--- a/taler-kotlin-common/build.gradle
+++ b/taler-kotlin-common/build.gradle
@@ -1,72 +1,82 @@
-/*
- * 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/>
- */
-
plugins {
- id 'com.android.library'
- id 'kotlin-android'
- id 'kotlin-android-extensions'
+ id 'org.jetbrains.kotlin.multiplatform'
id 'kotlinx-serialization'
}
-android {
- compileSdkVersion 29
- //noinspection GradleDependency
- buildToolsVersion "$build_tools_version"
+group 'net.taler'
+version '0.0.1'
- defaultConfig {
- minSdkVersion 24
- targetSdkVersion 29
- versionCode 1
- versionName "0.1"
+apply plugin: 'maven-publish'
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles 'consumer-rules.pro'
+kotlin {
+ jvm()
+ // This is for iPhone simulator
+ // Switch here to iosArm64 (or iosArm32) to build library for iPhone device
+ iosX64("ios") {
+ binaries {
+ framework()
+ }
}
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles
getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ linuxX64("linux")
+ js {
+ browser {
+ }
+ nodejs {
+ }
+ }
+ sourceSets {
+ def serialization_version = "0.20.0"
+ commonMain {
+ dependencies {
+ implementation kotlin('stdlib-common')
+ implementation
"org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version"
+ }
+ }
+ commonTest {
+ dependencies {
+ implementation kotlin('test-common')
+ implementation kotlin('test-annotations-common')
+ }
+ }
+ jvmMain {
+ dependencies {
+ implementation kotlin('stdlib-jdk8')
+ implementation
"org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"
+ }
+ }
+ jvmTest {
+ dependencies {
+ implementation kotlin('test')
+ implementation kotlin('test-junit')
+ }
+ }
+ jsMain {
+ dependencies {
+ implementation kotlin('stdlib-js')
+ implementation
"org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version"
+ }
+ }
+ jsTest {
+ dependencies {
+ implementation kotlin('test-js')
+ }
+ }
+ nativeMain {
+ dependsOn commonMain
+ dependencies {
+ implementation
"org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serialization_version"
+ }
+ }
+ nativeTest {
+ dependsOn commonTest
+ }
+ configure([targets.linux, targets.ios]) {
+ compilations.main.source(sourceSets.nativeMain)
+ compilations.test.source(sourceSets.nativeTest)
}
}
-
}
-dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'androidx.core:core-ktx:1.3.0'
-
- // Navigation
- implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
- implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
-
- // ViewModel and LiveData
- def lifecycle_version = "2.2.0"
- implementation
"androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
-
- // QR codes
- implementation 'com.google.zxing:core:3.4.0' // needs minSdkVersion 24+
-
- // JSON parsing and serialization
- api "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"
- implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.10.2"
-
- lintChecks 'com.github.thirdegg:lint-rules:0.0.4-alpha'
-
- testImplementation 'junit:junit:4.13'
- testImplementation 'org.json:json:20190722'
+configurations {
+ compileClasspath
}
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/Amount.kt
b/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Amount.kt
similarity index 70%
rename from taler-kotlin-common/src/main/java/net/taler/common/Amount.kt
rename to taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Amount.kt
index 992f93b..84d10c5 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/Amount.kt
+++ b/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Amount.kt
@@ -16,23 +16,12 @@
package net.taler.common
-import android.annotation.SuppressLint
-import com.fasterxml.jackson.core.JsonGenerator
-import com.fasterxml.jackson.core.JsonParser
-import com.fasterxml.jackson.databind.DeserializationContext
-import com.fasterxml.jackson.databind.JsonMappingException
-import com.fasterxml.jackson.databind.SerializerProvider
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize
-import com.fasterxml.jackson.databind.annotation.JsonSerialize
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer
-import com.fasterxml.jackson.databind.ser.std.StdSerializer
import kotlinx.serialization.Decoder
import kotlinx.serialization.Encoder
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
-import org.json.JSONObject
-import java.lang.Math.floorDiv
+import kotlin.math.floor
import kotlin.math.pow
import kotlin.math.roundToInt
@@ -40,8 +29,6 @@ class AmountParserException(msg: String? = null, cause:
Throwable? = null) : Exc
class AmountOverflowException(msg: String? = null, cause: Throwable? = null) :
Exception(msg, cause)
@Serializable(with = KotlinXAmountSerializer::class)
-@JsonSerialize(using = AmountSerializer::class)
-@JsonDeserialize(using = AmountDeserializer::class)
data class Amount(
/**
* name of the currency using either a three-character ISO 4217 currency
code,
@@ -70,29 +57,21 @@ data class Amount(
private const val FRACTIONAL_BASE: Int = 100000000 // 1e8
- @Suppress("unused")
- private val REGEX =
Regex("""^[-_*A-Za-z0-9]{1,12}:([0-9]+)\.?([0-9]+)?$""")
private val REGEX_CURRENCY = Regex("""^[-_*A-Za-z0-9]{1,12}$""")
- private val MAX_VALUE = 2.0.pow(52)
+ val MAX_VALUE = 2.0.pow(52).toLong()
private const val MAX_FRACTION_LENGTH = 8
- private const val MAX_FRACTION = 99_999_999
+ const val MAX_FRACTION = 99_999_999
- @Throws(AmountParserException::class)
- @SuppressLint("CheckedExceptions")
fun zero(currency: String): Amount {
return Amount(checkCurrency(currency), 0, 0)
}
- @Throws(AmountParserException::class)
- @SuppressLint("CheckedExceptions")
fun fromJSONString(str: String): Amount {
val split = str.split(":")
if (split.size != 2) throw AmountParserException("Invalid Amount
Format")
return fromString(split[0], split[1])
}
- @Throws(AmountParserException::class)
- @SuppressLint("CheckedExceptions")
fun fromString(currency: String, str: String): Amount {
// value
val valueSplit = str.split(".")
@@ -110,31 +89,23 @@ data class Amount(
return Amount(checkCurrency(currency), value, fraction)
}
- @Throws(AmountParserException::class)
- @SuppressLint("CheckedExceptions")
- fun fromJsonObject(json: JSONObject): Amount {
- val currency = checkCurrency(json.optString("currency"))
- val value = checkValue(json.optString("value").toLongOrNull())
- val fraction =
checkFraction(json.optString("fraction").toIntOrNull())
- return Amount(currency, value, fraction)
- }
+ fun min(currency: String): Amount = Amount(currency, 0, 1)
+ fun max(currency: String): Amount = Amount(currency, MAX_VALUE,
MAX_FRACTION)
+
- @Throws(AmountParserException::class)
- private fun checkCurrency(currency: String): String {
+ internal fun checkCurrency(currency: String): String {
if (!REGEX_CURRENCY.matches(currency))
throw AmountParserException("Invalid currency: $currency")
return currency
}
- @Throws(AmountParserException::class)
- private fun checkValue(value: Long?): Long {
+ internal fun checkValue(value: Long?): Long {
if (value == null || value > MAX_VALUE)
throw AmountParserException("Value $value greater than
$MAX_VALUE")
return value
}
- @Throws(AmountParserException::class)
- private fun checkFraction(fraction: Int?): Int {
+ internal fun checkFraction(fraction: Int?): Int {
if (fraction == null || fraction > MAX_FRACTION)
throw AmountParserException("Fraction $fraction greater than
$MAX_FRACTION")
return fraction
@@ -153,25 +124,23 @@ data class Amount(
"$value.$fractionStr"
}
- @Throws(AmountOverflowException::class)
operator fun plus(other: Amount): Amount {
check(currency == other.currency) { "Can only subtract from same
currency" }
- val resultValue = value + other.value + floorDiv(fraction +
other.fraction, FRACTIONAL_BASE)
+ val resultValue = value + other.value + floor((fraction +
other.fraction).toDouble() / FRACTIONAL_BASE).toLong()
if (resultValue > MAX_VALUE)
throw AmountOverflowException()
val resultFraction = (fraction + other.fraction) % FRACTIONAL_BASE
return Amount(currency, resultValue, resultFraction)
}
- @Throws(AmountOverflowException::class)
operator fun times(factor: Int): Amount {
+ // TODO consider replacing with a faster implementation
if (factor == 0) return zero(currency)
var result = this
for (i in 1 until factor) result += this
return result
}
- @Throws(AmountOverflowException::class)
operator fun minus(other: Amount): Amount {
check(currency == other.currency) { "Can only subtract from same
currency" }
var resultValue = value
@@ -227,20 +196,3 @@ object KotlinXAmountSerializer: KSerializer<Amount> {
return Amount.fromJSONString(decoder.decodeString())
}
}
-
-class AmountSerializer : StdSerializer<Amount>(Amount::class.java) {
- override fun serialize(value: Amount, gen: JsonGenerator, provider:
SerializerProvider) {
- gen.writeString(value.toJSONString())
- }
-}
-
-class AmountDeserializer : StdDeserializer<Amount>(Amount::class.java) {
- override fun deserialize(p: JsonParser, ctxt: DeserializationContext):
Amount {
- val node = p.codec.readValue(p, String::class.java)
- try {
- return Amount.fromJSONString(node)
- } catch (e: AmountParserException) {
- throw JsonMappingException(p, "Error parsing Amount", e)
- }
- }
-}
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
new file mode 100644
index 0000000..962e004
--- /dev/null
+++ b/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Time.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.SerialName
+import kotlinx.serialization.Serializable
+import net.taler.common.Duration.Companion.FOREVER
+import kotlin.math.max
+
+expect fun nowMillis(): Long
+
+@Serializable
+data class Timestamp(
+ @SerialName("t_ms")
+ val ms: Long
+) : Comparable<Timestamp> {
+
+ companion object {
+ const val NEVER: Long = -1 // TODO or UINT64_MAX?
+ fun now(): Timestamp = Timestamp(nowMillis())
+ }
+
+ /**
+ * Returns a copy of this [Timestamp] rounded to seconds.
+ */
+ fun truncateSeconds(): Timestamp {
+ if (ms == NEVER) return Timestamp(ms)
+ return Timestamp((ms / 1000L) * 1000L)
+ }
+
+ operator fun minus(other: Timestamp): Duration = when {
+ ms == NEVER -> Duration(FOREVER)
+ other.ms == NEVER -> throw Error("Invalid argument for timestamp
comparision")
+ ms < other.ms -> Duration(0)
+ else -> Duration(ms - other.ms)
+ }
+
+ operator fun minus(other: Duration): Timestamp = when {
+ ms == NEVER -> this
+ other.ms == FOREVER -> Timestamp(0)
+ else -> Timestamp(max(0, ms - other.ms))
+ }
+
+ override fun compareTo(other: Timestamp): Int {
+ return if (ms == NEVER) {
+ if (other.ms == NEVER) 0
+ else 1
+ } else {
+ if (other.ms == NEVER) -1
+ else ms.compareTo(other.ms)
+ }
+ }
+
+}
+
+@Serializable
+data class Duration(
+ /**
+ * Duration in milliseconds.
+ */
+ @SerialName("d_ms")
+ val ms: Long
+) {
+ companion object {
+ const val FOREVER: Long = -1 // TODO or UINT64_MAX?
+ }
+}
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/Version.kt
b/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Version.kt
similarity index 100%
rename from taler-kotlin-common/src/main/java/net/taler/common/Version.kt
rename to taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Version.kt
diff --git a/taler-kotlin-common/src/test/java/net/taler/common/AmountTest.kt
b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/AmountTest.kt
similarity index 65%
rename from taler-kotlin-common/src/test/java/net/taler/common/AmountTest.kt
rename to
taler-kotlin-common/src/commonTest/kotlin/net/taler/common/AmountTest.kt
index 97d9667..e184307 100644
--- a/taler-kotlin-common/src/test/java/net/taler/common/AmountTest.kt
+++ b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/AmountTest.kt
@@ -16,20 +16,26 @@
package net.taler.common
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.module.kotlin.KotlinModule
-import com.fasterxml.jackson.module.kotlin.readValue
-import org.json.JSONObject
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
-import org.junit.Test
+import kotlin.random.Random
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import kotlin.test.fail
class AmountTest {
+ companion object {
+ fun getRandomAmount() = getRandomAmount(getRandomString(1,
Random.nextInt(1, 12)))
+ fun getRandomAmount(currency: String): Amount {
+ val value = Random.nextLong(0, Amount.MAX_VALUE)
+ val fraction = Random.nextInt(0, Amount.MAX_FRACTION)
+ return Amount(currency, value, fraction)
+ }
+ }
+
@Test
- fun `test fromJSONString() works`() {
+ fun testFromJSONString() {
var str = "TESTKUDOS:23.42"
var amount = Amount.fromJSONString(str)
assertEquals(str, amount.toJSONString())
@@ -56,7 +62,7 @@ class AmountTest {
}
@Test
- fun `test fromJSONString() accepts max values, rejects above`() {
+ fun testFromJSONStringAcceptsMaxValuesRejectsAbove() {
val maxValue = 4503599627370496
val str = "TESTKUDOS123:$maxValue.99999999"
val amount = Amount.fromJSONString(str)
@@ -82,35 +88,7 @@ class AmountTest {
}
@Test
- fun `test JSON deserialization()`() {
- val mapper = ObjectMapper().registerModule(KotlinModule())
- var str = "TESTKUDOS:23.42"
- var amount: Amount = mapper.readValue("\"$str\"")
- assertEquals(str, amount.toJSONString())
- assertEquals("TESTKUDOS", amount.currency)
- assertEquals(23, amount.value)
- assertEquals((0.42 * 1e8).toInt(), amount.fraction)
- assertEquals("23.42 TESTKUDOS", amount.toString())
-
- str = "EUR:500000000.00000001"
- amount = mapper.readValue("\"$str\"")
- assertEquals(str, amount.toJSONString())
- assertEquals("EUR", amount.currency)
- assertEquals(500000000, amount.value)
- assertEquals(1, amount.fraction)
- assertEquals("500000000.00000001 EUR", amount.toString())
-
- str = "EUR:1500000000.00000003"
- amount = mapper.readValue("\"$str\"")
- assertEquals(str, amount.toJSONString())
- assertEquals("EUR", amount.currency)
- assertEquals(1500000000, amount.value)
- assertEquals(3, amount.fraction)
- assertEquals("1500000000.00000003 EUR", amount.toString())
- }
-
- @Test
- fun `test fromJSONString() rejections`() {
+ fun testFromJSONStringRejections() {
assertThrows<AmountParserException> {
Amount.fromJSONString("TESTKUDOS:0,5")
}
@@ -132,71 +110,7 @@ class AmountTest {
}
@Test
- fun `test fromJsonObject() works`() {
- val map = mapOf(
- "currency" to "TESTKUDOS",
- "value" to "23",
- "fraction" to "42000000"
- )
-
- val amount = Amount.fromJsonObject(JSONObject(map))
- assertEquals("TESTKUDOS:23.42", amount.toJSONString())
- assertEquals("TESTKUDOS", amount.currency)
- assertEquals(23, amount.value)
- assertEquals(42000000, amount.fraction)
- assertEquals("23.42 TESTKUDOS", amount.toString())
- }
-
- @Test
- fun `test fromJsonObject() accepts max values, rejects above`() {
- val maxValue = 4503599627370496
- val maxFraction = 99999999
- var map = mapOf(
- "currency" to "TESTKUDOS123",
- "value" to "$maxValue",
- "fraction" to "$maxFraction"
- )
-
- val amount = Amount.fromJsonObject(JSONObject(map))
- assertEquals("TESTKUDOS123:$maxValue.$maxFraction",
amount.toJSONString())
- assertEquals("TESTKUDOS123", amount.currency)
- assertEquals(maxValue, amount.value)
- assertEquals(maxFraction, amount.fraction)
- assertEquals("$maxValue.$maxFraction TESTKUDOS123", amount.toString())
-
- // longer currency not accepted
- assertThrows<AmountParserException>("longer currency was accepted") {
- map = mapOf(
- "currency" to "TESTKUDOS1234",
- "value" to "$maxValue",
- "fraction" to "$maxFraction"
- )
- Amount.fromJsonObject(JSONObject(map))
- }
-
- // max value + 1 not accepted
- assertThrows<AmountParserException>("max value + 1 was accepted") {
- map = mapOf(
- "currency" to "TESTKUDOS123",
- "value" to "${maxValue + 1}",
- "fraction" to "$maxFraction"
- )
- Amount.fromJsonObject(JSONObject(map))
- }
-
- // max fraction + 1 not accepted
- assertThrows<AmountParserException>("max fraction + 1 was accepted") {
- map = mapOf(
- "currency" to "TESTKUDOS123",
- "value" to "$maxValue",
- "fraction" to "${maxFraction + 1}"
- )
- Amount.fromJsonObject(JSONObject(map))
- }
- }
-
- @Test
- fun `test addition`() {
+ fun testAddition() {
assertEquals(
Amount.fromJSONString("EUR:2"),
Amount.fromJSONString("EUR:1") + Amount.fromJSONString("EUR:1")
@@ -218,7 +132,7 @@ class AmountTest {
}
@Test
- fun `test times`() {
+ fun testTimes() {
assertEquals(
Amount.fromJSONString("EUR:2"),
Amount.fromJSONString("EUR:2") * 1
@@ -231,6 +145,12 @@ class AmountTest {
Amount.fromJSONString("EUR:4.5"),
Amount.fromJSONString("EUR:1.5") * 3
)
+ assertEquals(Amount.fromJSONString("EUR:0"),
Amount.fromJSONString("EUR:1.11") * 0)
+ assertEquals(Amount.fromJSONString("EUR:1.11"),
Amount.fromJSONString("EUR:1.11") * 1)
+ assertEquals(Amount.fromJSONString("EUR:2.22"),
Amount.fromJSONString("EUR:1.11") * 2)
+ assertEquals(Amount.fromJSONString("EUR:3.33"),
Amount.fromJSONString("EUR:1.11") * 3)
+ assertEquals(Amount.fromJSONString("EUR:4.44"),
Amount.fromJSONString("EUR:1.11") * 4)
+ assertEquals(Amount.fromJSONString("EUR:5.55"),
Amount.fromJSONString("EUR:1.11") * 5)
assertEquals(
Amount.fromJSONString("EUR:1500000000.00000003"),
Amount.fromJSONString("EUR:500000000.00000001") * 3
@@ -241,7 +161,7 @@ class AmountTest {
}
@Test
- fun `test subtraction`() {
+ fun testSubtraction() {
assertEquals(
Amount.fromJSONString("EUR:0"),
Amount.fromJSONString("EUR:1") - Amount.fromJSONString("EUR:1")
@@ -263,7 +183,7 @@ class AmountTest {
}
@Test
- fun `test isZero()`() {
+ fun testIsZero() {
assertTrue(Amount.zero("EUR").isZero())
assertTrue(Amount.fromJSONString("EUR:0").isZero())
assertTrue(Amount.fromJSONString("EUR:0.0").isZero())
@@ -276,14 +196,17 @@ class AmountTest {
}
@Test
- fun `test comparision`() {
+ fun testComparision() {
assertTrue(Amount.fromJSONString("EUR:0") <=
Amount.fromJSONString("EUR:0"))
assertTrue(Amount.fromJSONString("EUR:0") <=
Amount.fromJSONString("EUR:0.00000001"))
assertTrue(Amount.fromJSONString("EUR:0") <
Amount.fromJSONString("EUR:0.00000001"))
assertTrue(Amount.fromJSONString("EUR:0") <
Amount.fromJSONString("EUR:1"))
- assertTrue(Amount.fromJSONString("EUR:0") ==
Amount.fromJSONString("EUR:0"))
- assertTrue(Amount.fromJSONString("EUR:42") ==
Amount.fromJSONString("EUR:42"))
- assertTrue(Amount.fromJSONString("EUR:42.00000001") ==
Amount.fromJSONString("EUR:42.00000001"))
+ assertEquals(Amount.fromJSONString("EUR:0"),
Amount.fromJSONString("EUR:0"))
+ assertEquals(Amount.fromJSONString("EUR:42"),
Amount.fromJSONString("EUR:42"))
+ assertEquals(
+ Amount.fromJSONString("EUR:42.00000001"),
+ Amount.fromJSONString("EUR:42.00000001")
+ )
assertTrue(Amount.fromJSONString("EUR:42.00000001") >=
Amount.fromJSONString("EUR:42.00000001"))
assertTrue(Amount.fromJSONString("EUR:42.00000002") >=
Amount.fromJSONString("EUR:42.00000001"))
assertTrue(Amount.fromJSONString("EUR:42.00000002") >
Amount.fromJSONString("EUR:42.00000001"))
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TestUtils.kt
similarity index 52%
copy from taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
copy to taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TestUtils.kt
index 03a0d6e..e3a6c17 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
+++ b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TestUtils.kt
@@ -16,25 +16,11 @@
package net.taler.common
-import android.annotation.SuppressLint
+import kotlin.random.Random
-data class SignedAmount(
- val positive: Boolean,
- val amount: Amount
-) {
-
- companion object {
- @Throws(AmountParserException::class)
- @SuppressLint("CheckedExceptions")
- fun fromJSONString(str: String): SignedAmount = when (str.substring(0,
1)) {
- "-" -> SignedAmount(false, Amount.fromJSONString(str.substring(1)))
- "+" -> SignedAmount(true, Amount.fromJSONString(str.substring(1)))
- else -> SignedAmount(true, Amount.fromJSONString(str))
- }
- }
-
- override fun toString(): String {
- return if (positive) "$amount" else "-$amount"
- }
-
-}
\ No newline at end of file
+private val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
+fun getRandomString(minLength: Int = 1, maxLength: Int = Random.nextInt(0,
1337)) =
+ (minLength..maxLength)
+ .map { Random.nextInt(0, charPool.size) }
+ .map(charPool::get)
+ .joinToString("")
diff --git a/taler-kotlin-common/src/test/java/net/taler/common/VersionTest.kt
b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/VersionTest.kt
similarity index 95%
rename from taler-kotlin-common/src/test/java/net/taler/common/VersionTest.kt
rename to
taler-kotlin-common/src/commonTest/kotlin/net/taler/common/VersionTest.kt
index 70f30eb..f4f17ea 100644
--- a/taler-kotlin-common/src/test/java/net/taler/common/VersionTest.kt
+++ b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/VersionTest.kt
@@ -16,9 +16,9 @@
package net.taler.common
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNull
-import org.junit.Test
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertNull
class VersionTest {
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
b/taler-kotlin-common/src/jsMain/kotlin/net/taler/common/Time.kt
similarity index 52%
copy from taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
copy to taler-kotlin-common/src/jsMain/kotlin/net/taler/common/Time.kt
index 03a0d6e..b114022 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
+++ b/taler-kotlin-common/src/jsMain/kotlin/net/taler/common/Time.kt
@@ -16,25 +16,8 @@
package net.taler.common
-import android.annotation.SuppressLint
+import kotlin.js.Date
-data class SignedAmount(
- val positive: Boolean,
- val amount: Amount
-) {
-
- companion object {
- @Throws(AmountParserException::class)
- @SuppressLint("CheckedExceptions")
- fun fromJSONString(str: String): SignedAmount = when (str.substring(0,
1)) {
- "-" -> SignedAmount(false, Amount.fromJSONString(str.substring(1)))
- "+" -> SignedAmount(true, Amount.fromJSONString(str.substring(1)))
- else -> SignedAmount(true, Amount.fromJSONString(str))
- }
- }
-
- override fun toString(): String {
- return if (positive) "$amount" else "-$amount"
- }
-
-}
\ No newline at end of file
+actual fun nowMillis(): Long {
+ return Date().getMilliseconds().toLong()
+}
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
b/taler-kotlin-common/src/jvmMain/kotlin/net/taler/common/Time.kt
similarity index 52%
copy from taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
copy to taler-kotlin-common/src/jvmMain/kotlin/net/taler/common/Time.kt
index 03a0d6e..6cd9040 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
+++ b/taler-kotlin-common/src/jvmMain/kotlin/net/taler/common/Time.kt
@@ -16,25 +16,6 @@
package net.taler.common
-import android.annotation.SuppressLint
-
-data class SignedAmount(
- val positive: Boolean,
- val amount: Amount
-) {
-
- companion object {
- @Throws(AmountParserException::class)
- @SuppressLint("CheckedExceptions")
- fun fromJSONString(str: String): SignedAmount = when (str.substring(0,
1)) {
- "-" -> SignedAmount(false, Amount.fromJSONString(str.substring(1)))
- "+" -> SignedAmount(true, Amount.fromJSONString(str.substring(1)))
- else -> SignedAmount(true, Amount.fromJSONString(str))
- }
- }
-
- override fun toString(): String {
- return if (positive) "$amount" else "-$amount"
- }
-
-}
\ No newline at end of file
+actual fun nowMillis(): Long {
+ return System.currentTimeMillis()
+}
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
b/taler-kotlin-common/src/nativeMain/kotlin/net/taler/common/Time.kt
similarity index 52%
rename from taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
rename to taler-kotlin-common/src/nativeMain/kotlin/net/taler/common/Time.kt
index 03a0d6e..8a4091a 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/SignedAmount.kt
+++ b/taler-kotlin-common/src/nativeMain/kotlin/net/taler/common/Time.kt
@@ -16,25 +16,8 @@
package net.taler.common
-import android.annotation.SuppressLint
+import kotlin.system.getTimeMillis
-data class SignedAmount(
- val positive: Boolean,
- val amount: Amount
-) {
-
- companion object {
- @Throws(AmountParserException::class)
- @SuppressLint("CheckedExceptions")
- fun fromJSONString(str: String): SignedAmount = when (str.substring(0,
1)) {
- "-" -> SignedAmount(false, Amount.fromJSONString(str.substring(1)))
- "+" -> SignedAmount(true, Amount.fromJSONString(str.substring(1)))
- else -> SignedAmount(true, Amount.fromJSONString(str))
- }
- }
-
- override fun toString(): String {
- return if (positive) "$amount" else "-$amount"
- }
-
-}
\ No newline at end of file
+actual fun nowMillis(): Long {
+ return getTimeMillis()
+}
diff --git a/wallet/.gitlab-ci.yml b/wallet/.gitlab-ci.yml
index 56768f7..c417aa9 100644
--- a/wallet/.gitlab-ci.yml
+++ b/wallet/.gitlab-ci.yml
@@ -4,6 +4,7 @@ wallet_test:
changes:
- wallet/**/*
- taler-kotlin-common/**/*
+ - taler-kotlin-android/**/*
- build.gradle
script: ./gradlew :wallet:check :wallet:assembleRelease
artifacts:
diff --git a/wallet/build.gradle b/wallet/build.gradle
index 8cca8dc..1761018 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -23,7 +23,7 @@ plugins {
id "de.undercouch.download"
}
-def walletCoreVersion = "v0.7.1-dev.14"
+def walletCoreVersion = "v0.7.1-dev.16"
static def versionCodeEpoch() {
return (new Date().getTime() / 1000).toInteger()
@@ -47,7 +47,7 @@ android {
minSdkVersion 24
targetSdkVersion 29
versionCode 6
- versionName "0.7.1.dev.14"
+ versionName "0.7.1.dev.16"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "WALLET_CORE_VERSION",
"\"$walletCoreVersion\""
}
@@ -83,6 +83,10 @@ android {
jvmTarget = "1.8"
}
+ packagingOptions {
+ exclude("META-INF/*.kotlin_module")
+ }
+
lintOptions {
abortOnError true
ignoreWarnings false
@@ -93,7 +97,7 @@ android {
}
dependencies {
- implementation project(":taler-kotlin-common")
+ implementation project(":taler-kotlin-android")
implementation project(":anastasis-ui")
implementation 'net.taler:akono:0.1'
diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
index 3d725d0..ffa2dea 100644
--- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -24,10 +24,13 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.viewModelScope
+import com.fasterxml.jackson.databind.DeserializationFeature
import
com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.fasterxml.jackson.module.kotlin.readValue
+import net.taler.common.Amount
+import net.taler.common.AmountMixin
import net.taler.common.Event
import net.taler.common.assertUiThread
import net.taler.common.toEvent
@@ -91,6 +94,8 @@ class MainViewModel(val app: Application) :
AndroidViewModel(app) {
private val mapper = ObjectMapper()
.registerModule(KotlinModule())
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
+ .addMixIn(Amount::class.java, AmountMixin::class.java)
+ .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)
val withdrawManager = WithdrawManager(walletBackendApi, mapper)
val paymentManager = PaymentManager(walletBackendApi, mapper)
diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFees.kt
b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFees.kt
index ae90b98..a026283 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFees.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFees.kt
@@ -18,7 +18,6 @@ package net.taler.wallet.exchanges
import net.taler.common.Amount
import net.taler.common.Timestamp
-import org.json.JSONObject
data class CoinFee(
val coin: Amount,
@@ -42,54 +41,4 @@ data class ExchangeFees(
val earliestDepositExpiration: Timestamp,
val coinFees: List<CoinFee>,
val wireFees: List<WireFee>
-) {
- companion object {
- fun fromExchangeWithdrawDetailsJson(json: JSONObject): ExchangeFees {
- val earliestDepositExpiration =
- json.getJSONObject("earliestDepositExpiration").getLong("t_ms")
- val selectedDenoms = json.getJSONObject("selectedDenoms")
- val denoms = selectedDenoms.getJSONArray("selectedDenoms")
- val coinFees = ArrayList<CoinFee>(denoms.length())
- for (i in 0 until denoms.length()) {
- val denom = denoms.getJSONObject(i)
- val d = denom.getJSONObject("denom")
- val coinFee = CoinFee(
- coin = Amount.fromJsonObject(d.getJSONObject("value")),
- quantity = denom.getInt("count"),
- feeDeposit =
Amount.fromJsonObject(d.getJSONObject("feeDeposit")),
- feeRefresh =
Amount.fromJsonObject(d.getJSONObject("feeRefresh")),
- feeRefund =
Amount.fromJsonObject(d.getJSONObject("feeRefund")),
- feeWithdraw =
Amount.fromJsonObject(d.getJSONObject("feeWithdraw"))
- )
- coinFees.add(coinFee)
- }
-
- val wireFeesJson = json.getJSONObject("wireFees")
- val feesForType = wireFeesJson.getJSONObject("feesForType")
- val bankFees = feesForType.getJSONArray("x-taler-bank")
- val wireFees = ArrayList<WireFee>(bankFees.length())
- for (i in 0 until bankFees.length()) {
- val fee = bankFees.getJSONObject(i)
- val startStamp =
- fee.getJSONObject("startStamp").getLong("t_ms")
- val endStamp =
- fee.getJSONObject("endStamp").getLong("t_ms")
- val wireFee = WireFee(
- start = Timestamp(startStamp),
- end = Timestamp(endStamp),
- wireFee =
Amount.fromJsonObject(fee.getJSONObject("wireFee")),
- closingFee =
Amount.fromJsonObject(fee.getJSONObject("closingFee"))
- )
- wireFees.add(wireFee)
- }
-
- return ExchangeFees(
- withdrawFee =
Amount.fromJsonObject(json.getJSONObject("withdrawFee")),
- overhead =
Amount.fromJsonObject(json.getJSONObject("overhead")),
- earliestDepositExpiration =
Timestamp(earliestDepositExpiration),
- coinFees = coinFees,
- wireFees = wireFees
- )
- }
- }
-}
+)
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt
b/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt
index 4c5b010..d2f8e6c 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PaymentResponses.kt
@@ -16,23 +16,12 @@
package net.taler.wallet.payment
-import com.fasterxml.jackson.annotation.JsonSubTypes
-import com.fasterxml.jackson.annotation.JsonSubTypes.Type
import com.fasterxml.jackson.annotation.JsonTypeInfo
-import com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME
import com.fasterxml.jackson.annotation.JsonTypeName
import net.taler.common.ContractTerms
-import net.taler.wallet.payment.PreparePayResponse.AlreadyConfirmedResponse
-import net.taler.wallet.payment.PreparePayResponse.InsufficientBalanceResponse
-import net.taler.wallet.payment.PreparePayResponse.PaymentPossibleResponse
-@JsonTypeInfo(use = NAME, include = PROPERTY, property = "status")
-@JsonSubTypes(
- Type(value = PaymentPossibleResponse::class, name = "payment-possible"),
- Type(value = AlreadyConfirmedResponse::class, name = "already-confirmed"),
- Type(value = InsufficientBalanceResponse::class, name =
"insufficient-balance")
-)
+@JsonTypeInfo(use = NAME, property = "status")
sealed class PreparePayResponse(open val proposalId: String) {
@JsonTypeName("payment-possible")
data class PaymentPossibleResponse(
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.