gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-android] 01/02: Allow fractional withdrawals with cashier a


From: gnunet
Subject: [taler-taler-android] 01/02: Allow fractional withdrawals with cashier app
Date: Tue, 24 Mar 2020 13:23:36 +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 864160280872fdb400c2e0e61aaaa1b858fba3f8
Author: Torsten Grote <address@hidden>
AuthorDate: Tue Mar 24 09:08:00 2020 -0300

    Allow fractional withdrawals with cashier app
---
 build.gradle                                       |  2 +-
 .../main/java/net/taler/cashier/BalanceFragment.kt | 12 ++++++----
 .../src/main/java/net/taler/cashier/HttpHelper.kt  |  4 ++--
 .../taler/cashier/withdraw/TransactionFragment.kt  |  2 +-
 .../net/taler/cashier/withdraw/WithdrawManager.kt  | 24 ++++++++++---------
 .../main/res/layout-w550dp/fragment_balance.xml    |  2 +-
 cashier/src/main/res/layout/fragment_balance.xml   |  2 +-
 .../src/main/java/net/taler/common/Amount.kt       | 27 ++++++++++++++++++----
 .../src/test/java/net/taler/common/AmountTest.kt   | 21 +++++++++++++++++
 9 files changed, 69 insertions(+), 27 deletions(-)

diff --git a/build.gradle b/build.gradle
index b1f47dd..57a780b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
 buildscript {
-    ext.kotlin_version = '1.3.70'
+    ext.kotlin_version = '1.3.71'
     ext.nav_version = "2.2.1"
     ext.build_tools_version = "29.0.2"
     repositories {
diff --git a/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt 
b/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
index fffb21b..c4802ee 100644
--- a/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
@@ -33,6 +33,7 @@ import kotlinx.android.synthetic.main.fragment_balance.*
 import 
net.taler.cashier.BalanceFragmentDirections.Companion.actionBalanceFragmentToTransactionFragment
 import net.taler.cashier.withdraw.LastTransaction
 import net.taler.cashier.withdraw.WithdrawStatus
+import net.taler.common.Amount
 import net.taler.common.SignedAmount
 import net.taler.common.fadeIn
 import net.taler.common.fadeOut
@@ -142,14 +143,15 @@ class BalanceFragment : Fragment() {
         amountView.error = null
     }
 
-    private fun getAmountFromView(): Int {
+    private fun getAmountFromView(): Amount {
         val str = amountView.editText!!.text.toString()
-        if (str.isBlank()) return 0
-        return Integer.parseInt(str)
+        val currency = viewModel.currency.value!!
+        if (str.isBlank()) return Amount.zero(currency)
+        return Amount.fromString(currency, str)
     }
 
-    private fun onAmountConfirmed(amount: Int) {
-        if (amount <= 0) {
+    private fun onAmountConfirmed(amount: Amount) {
+        if (amount.isZero()) {
             amountView.error = getString(R.string.withdraw_error_zero)
         } else if (!withdrawManager.hasSufficientBalance(amount)) {
             amountView.error = 
getString(R.string.withdraw_error_insufficient_balance)
diff --git a/cashier/src/main/java/net/taler/cashier/HttpHelper.kt 
b/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
index 06b06db..43ba4d8 100644
--- a/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
+++ b/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
@@ -57,11 +57,11 @@ object HttpHelper {
     private val MEDIA_TYPE_JSON = MediaType.parse("$MIME_TYPE_JSON; 
charset=utf-8")
 
     @WorkerThread
-    fun makeJsonPostRequest(url: String, body: String, config: Config): 
HttpJsonResult {
+    fun makeJsonPostRequest(url: String, body: JSONObject, config: Config): 
HttpJsonResult {
         val request = Request.Builder()
             .addHeader("Accept", MIME_TYPE_JSON)
             .url(url)
-            .post(RequestBody.create(MEDIA_TYPE_JSON, body))
+            .post(RequestBody.create(MEDIA_TYPE_JSON, body.toString()))
             .build()
         val response = try {
             getHttpClient(config.username, config.password)
diff --git 
a/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt 
b/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
index 8857bfa..e433540 100644
--- a/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
@@ -54,7 +54,7 @@ class TransactionFragment : Fragment() {
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         withdrawManager.withdrawAmount.observe(viewLifecycleOwner, Observer { 
amount ->
-            amountView.text = amount
+            amountView.text = amount?.toString()
         })
         withdrawManager.withdrawResult.observe(viewLifecycleOwner, Observer { 
result ->
             onWithdrawResultReceived(result)
diff --git 
a/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt 
b/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
index 88df6b7..317d1bf 100644
--- a/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
+++ b/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
@@ -34,6 +34,7 @@ import net.taler.cashier.HttpJsonResult.Error
 import net.taler.cashier.HttpJsonResult.Success
 import net.taler.cashier.MainViewModel
 import net.taler.cashier.R
+import net.taler.common.Amount
 import net.taler.common.QrCodeManager.makeQrCode
 import org.json.JSONObject
 import java.util.concurrent.TimeUnit.MINUTES
@@ -59,8 +60,8 @@ class WithdrawManager(
 
     private var withdrawStatusCheck: Job? = null
 
-    private val mWithdrawAmount = MutableLiveData<String>()
-    val withdrawAmount: LiveData<String> = mWithdrawAmount
+    private val mWithdrawAmount = MutableLiveData<Amount>()
+    val withdrawAmount: LiveData<Amount> = mWithdrawAmount
 
     private val mWithdrawResult = MutableLiveData<WithdrawResult>()
     val withdrawResult: LiveData<WithdrawResult> = mWithdrawResult
@@ -72,22 +73,23 @@ class WithdrawManager(
     val lastTransaction: LiveData<LastTransaction> = mLastTransaction
 
     @UiThread
-    fun hasSufficientBalance(amount: Int): Boolean {
+    fun hasSufficientBalance(amount: Amount): Boolean {
         val balanceResult = viewModel.balance.value
         if (balanceResult !is BalanceResult.Success) return false
-        return balanceResult.amount.positive && amount <= 
balanceResult.amount.amount.value
+        return balanceResult.amount.positive && amount <= 
balanceResult.amount.amount
     }
 
     @UiThread
-    fun withdraw(amount: Int) {
-        check(amount > 0) { "Withdraw amount was <= 0" }
+    fun withdraw(amount: Amount) {
+        check(!amount.isZero()) { "Withdraw amount was 0" }
         check(currency != null) { "Currency is null" }
         mWithdrawResult.value = null
-        mWithdrawAmount.value = "$amount $currency"
+        mWithdrawAmount.value = amount
         scope.launch(Dispatchers.IO) {
             val url = 
"${config.bankUrl}/accounts/${config.username}/withdrawals"
             Log.d(TAG, "Starting withdrawal at $url")
-            val body = JSONObject(mapOf("amount" to 
"${currency}:${amount}")).toString()
+            val map = mapOf("amount" to amount.toJSONString())
+            val body = JSONObject(map)
             when (val result = makeJsonPostRequest(url, body, config)) {
                 is Success -> {
                     val talerUri = result.json.getString("taler_withdraw_uri")
@@ -178,7 +180,7 @@ class WithdrawManager(
     private fun abort(withdrawalId: String) = scope.launch(Dispatchers.IO) {
         val url = 
"${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}/abort"
         Log.d(TAG, "Aborting withdrawal at $url")
-        makeJsonPostRequest(url, "", config)
+        makeJsonPostRequest(url, JSONObject(), config)
     }
 
     @UiThread
@@ -188,7 +190,7 @@ class WithdrawManager(
             val url =
                 
"${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}/confirm"
             Log.d(TAG, "Confirming withdrawal at $url")
-            when (val result = makeJsonPostRequest(url, "", config)) {
+            when (val result = makeJsonPostRequest(url, JSONObject(), config)) 
{
                 is Success -> {
                     // no-op still waiting for [timer] to confirm our 
confirmation
                 }
@@ -226,6 +228,6 @@ sealed class WithdrawStatus {
 }
 
 data class LastTransaction(
-    val withdrawAmount: String,
+    val withdrawAmount: Amount,
     val withdrawStatus: WithdrawStatus
 )
diff --git a/cashier/src/main/res/layout-w550dp/fragment_balance.xml 
b/cashier/src/main/res/layout-w550dp/fragment_balance.xml
index d04698b..40fa6af 100644
--- a/cashier/src/main/res/layout-w550dp/fragment_balance.xml
+++ b/cashier/src/main/res/layout-w550dp/fragment_balance.xml
@@ -184,7 +184,7 @@
             android:layout_height="wrap_content"
             android:ems="6"
             android:imeOptions="actionGo"
-            android:inputType="number"
+            android:inputType="number|numberDecimal"
             android:maxLength="4" />
 
     </com.google.android.material.textfield.TextInputLayout>
diff --git a/cashier/src/main/res/layout/fragment_balance.xml 
b/cashier/src/main/res/layout/fragment_balance.xml
index 5dafc59..b50cfa9 100644
--- a/cashier/src/main/res/layout/fragment_balance.xml
+++ b/cashier/src/main/res/layout/fragment_balance.xml
@@ -185,7 +185,7 @@
             android:layout_height="wrap_content"
             android:ems="6"
             android:imeOptions="actionGo"
-            android:inputType="number"
+            android:inputType="number|numberDecimal"
             android:maxLength="4" />
 
     </com.google.android.material.textfield.TextInputLayout>
diff --git a/taler-kotlin-common/src/main/java/net/taler/common/Amount.kt 
b/taler-kotlin-common/src/main/java/net/taler/common/Amount.kt
index 48bd643..49b699f 100644
--- a/taler-kotlin-common/src/main/java/net/taler/common/Amount.kt
+++ b/taler-kotlin-common/src/main/java/net/taler/common/Amount.kt
@@ -64,7 +64,7 @@ data class Amount(
      * of 50_000_000 would correspond to 50 cents.
      */
     val fraction: Int
-) {
+) : Comparable<Amount> {
 
     companion object {
 
@@ -88,10 +88,14 @@ data class Amount(
         fun fromJSONString(str: String): Amount {
             val split = str.split(":")
             if (split.size != 2) throw AmountParserException("Invalid Amount 
Format")
-            // currency
-            val currency = checkCurrency(split[0])
+            return fromString(split[0], split[1])
+        }
+
+        @Throws(AmountParserException::class)
+        @SuppressLint("CheckedExceptions")
+        fun fromString(currency: String, str: String): Amount {
             // value
-            val valueSplit = split[1].split(".")
+            val valueSplit = str.split(".")
             val value = checkValue(valueSplit[0].toLongOrNull())
             // fraction
             val fraction: Int = if (valueSplit.size > 1) {
@@ -103,7 +107,7 @@ data class Amount(
                     ?.roundToInt()
                 checkFraction(fraction)
             } else 0
-            return Amount(currency, value, fraction)
+            return Amount(checkCurrency(currency), value, fraction)
         }
 
         @Throws(AmountParserException::class)
@@ -197,4 +201,17 @@ data class Amount(
         return "$amountStr $currency"
     }
 
+    override fun compareTo(other: Amount): Int {
+        check(currency == other.currency) { "Can only compare amounts with the 
same currency" }
+        when {
+            value == other.value -> {
+                if (fraction < other.fraction) return -1
+                if (fraction > other.fraction) return 1
+                return 0
+            }
+            value < other.value -> return -1
+            else -> return 1
+        }
+    }
+
 }
diff --git a/taler-kotlin-common/src/test/java/net/taler/common/AmountTest.kt 
b/taler-kotlin-common/src/test/java/net/taler/common/AmountTest.kt
index c09da3c..97d9667 100644
--- a/taler-kotlin-common/src/test/java/net/taler/common/AmountTest.kt
+++ b/taler-kotlin-common/src/test/java/net/taler/common/AmountTest.kt
@@ -275,6 +275,27 @@ class AmountTest {
         assertFalse(Amount.fromJSONString("EUR:0001.0").isZero())
     }
 
+    @Test
+    fun `test comparision`() {
+        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"))
+        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"))
+        assertTrue(Amount.fromJSONString("EUR:0.00000002") > 
Amount.fromJSONString("EUR:0.00000001"))
+        assertTrue(Amount.fromJSONString("EUR:0.00000001") > 
Amount.fromJSONString("EUR:0"))
+        assertTrue(Amount.fromJSONString("EUR:2") > 
Amount.fromJSONString("EUR:1"))
+
+        assertThrows<IllegalStateException>("could compare amounts with 
different currencies") {
+            Amount.fromJSONString("EUR:0.5") < 
Amount.fromJSONString("USD:0.50000001")
+        }
+    }
+
     private inline fun <reified T : Throwable> assertThrows(
         msg: String? = null,
         function: () -> Any

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]