[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-android] branch master updated (3ab6f15 -> e9f9b50)
From: |
gnunet |
Subject: |
[taler-taler-android] branch master updated (3ab6f15 -> e9f9b50) |
Date: |
Wed, 12 Aug 2020 18:52:18 +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 3ab6f15 [wallet] upgrade wallet-core and adapt payment API
new 2d23935 [wallet] fix icon tint declaration (CI lint error)
new 038673c [wallet] adapt to new Refund API
new e9f9b50 [wallet] remove remaining deserialization off the UI thread
The 3 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:
wallet/build.gradle | 4 +-
.../src/main/java/net/taler/wallet/MainActivity.kt | 25 ++++++---
.../main/java/net/taler/wallet/MainViewModel.kt | 4 +-
.../net/taler/wallet/exchanges/ExchangeManager.kt | 47 +++++++++-------
.../java/net/taler/wallet/refund/RefundManager.kt | 35 ++++++++----
.../transactions/TransactionDetailFragment.kt | 7 ++-
.../wallet/transactions/TransactionManager.kt | 64 +++++++++-------------
.../net/taler/wallet/transactions/Transactions.kt | 10 +++-
.../net/taler/wallet/withdraw/WithdrawManager.kt | 6 +-
wallet/src/main/res/layout/fragment_error.xml | 2 +-
wallet/src/main/res/values-fr/strings.xml | 2 +-
wallet/src/main/res/values/strings.xml | 2 +-
12 files changed, 116 insertions(+), 92 deletions(-)
diff --git a/wallet/build.gradle b/wallet/build.gradle
index 329e271..da3f9a8 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -24,7 +24,7 @@ plugins {
id "de.undercouch.download"
}
-def walletCoreVersion = "v0.7.1-dev.19"
+def walletCoreVersion = "v0.7.1-dev.20"
static def versionCodeEpoch() {
return (new Date().getTime() / 1000).toInteger()
@@ -48,7 +48,7 @@ android {
minSdkVersion 24
targetSdkVersion 29
versionCode 6
- versionName "0.7.1.dev.19"
+ versionName "0.7.1.dev.20"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "WALLET_CORE_VERSION",
"\"$walletCoreVersion\""
}
diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt
b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
index c7c31ca..838ed2d 100644
--- a/wallet/src/main/java/net/taler/wallet/MainActivity.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
@@ -163,15 +163,7 @@ class MainActivity : AppCompatActivity(),
OnNavigationItemSelectedListener,
}
url.toLowerCase(ROOT).startsWith("taler://refund/") -> {
model.showProgressBar.value = true
- model.refundManager.refund(url).observe(this, Observer {
status ->
- model.showProgressBar.value = false
- val res = when (status) {
- is RefundStatus.Error -> R.string.refund_error
- // TODO once wallet-core exposes currency, navigate to
its transaction list
- is RefundStatus.Success -> R.string.refund_success
- }
- Snackbar.make(nav_view, res, LENGTH_LONG).show()
- })
+ model.refundManager.refund(url).observe(this,
Observer(::onRefundResponse))
}
else -> {
Snackbar.make(
@@ -183,6 +175,21 @@ class MainActivity : AppCompatActivity(),
OnNavigationItemSelectedListener,
}
}
+ private fun onRefundResponse(status: RefundStatus) {
+ model.showProgressBar.value = false
+ when (status) {
+ is RefundStatus.Error -> {
+ Snackbar.make(nav_view, R.string.refund_error,
LENGTH_LONG).show()
+ }
+ is RefundStatus.Success -> {
+ val amount = status.response.amountRefundGranted
+ model.showTransactions(amount.currency)
+ val str = getString(R.string.refund_success, amount.amountStr)
+ Snackbar.make(nav_view, str, LENGTH_LONG).show()
+ }
+ }
+ }
+
private val triggerPaymentReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (nav.currentDestination?.id == R.id.promptPayment) return
diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
index 24a8f1e..b4aa1dc 100644
--- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -102,8 +102,8 @@ class MainViewModel(val app: Application) :
AndroidViewModel(app) {
val paymentManager = PaymentManager(api, viewModelScope, mapper)
val pendingOperationsManager: PendingOperationsManager =
PendingOperationsManager(api)
val transactionManager: TransactionManager = TransactionManager(api,
viewModelScope, mapper)
- val refundManager = RefundManager(api)
- val exchangeManager: ExchangeManager = ExchangeManager(api, mapper)
+ val refundManager = RefundManager(api, viewModelScope)
+ val exchangeManager: ExchangeManager = ExchangeManager(api, viewModelScope)
private val mTransactionsEvent = MutableLiveData<Event<String>>()
val transactionsEvent: LiveData<Event<String>> = mTransactionsEvent
diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt
b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt
index 9d31b5f..8205eb7 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt
@@ -19,17 +19,22 @@ package net.taler.wallet.exchanges
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.module.kotlin.readValue
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.serialization.Serializable
import net.taler.common.Event
import net.taler.common.toEvent
import net.taler.wallet.TAG
import net.taler.wallet.backend.WalletBackendApi
-import org.json.JSONObject
+
+@Serializable
+data class ExchangeListResponse(
+ val exchanges: List<ExchangeItem>
+)
class ExchangeManager(
- private val walletBackendApi: WalletBackendApi,
- private val mapper: ObjectMapper
+ private val api: WalletBackendApi,
+ private val scope: CoroutineScope
) {
private val mProgress = MutableLiveData<Boolean>()
@@ -45,31 +50,31 @@ class ExchangeManager(
private fun list(): LiveData<List<ExchangeItem>> {
mProgress.value = true
- walletBackendApi.sendRequest("listExchanges") { isError, result ->
- if (isError) {
+ scope.launch {
+ val response = api.request("listExchanges",
ExchangeListResponse.serializer())
+ response.onError {
throw AssertionError("Wallet core failed to return exchanges!")
- } else {
- val exchanges: List<ExchangeItem> =
mapper.readValue(result.getString("exchanges"))
- Log.d(TAG, "Exchange list: $exchanges")
+ }.onSuccess {
+ Log.d(TAG, "Exchange list: ${it.exchanges}")
mProgress.value = false
- mExchanges.value = exchanges
+ mExchanges.value = it.exchanges
}
}
return mExchanges
}
- fun add(exchangeUrl: String) {
+ fun add(exchangeUrl: String) = scope.launch {
mProgress.value = true
- val args = JSONObject().apply { put("exchangeBaseUrl", exchangeUrl) }
- walletBackendApi.sendRequest("addExchange", args) { isError, result ->
+ api.request<Unit>("addExchange") {
+ put("exchangeBaseUrl", exchangeUrl)
+ }.onError {
mProgress.value = false
- if (isError) {
- Log.e(TAG, "$result")
- mAddError.value = true.toEvent()
- } else {
- Log.d(TAG, "Exchange $exchangeUrl added")
- list()
- }
+ Log.e(TAG, "Error adding exchange: $it")
+ mAddError.value = true.toEvent()
+ }.onSuccess {
+ mProgress.value = false
+ Log.d(TAG, "Exchange $exchangeUrl added")
+ list()
}
}
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 5593486..fdacb0d 100644
--- a/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
@@ -19,28 +19,43 @@ package net.taler.wallet.refund
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.serialization.Serializable
+import net.taler.common.Amount
import net.taler.wallet.TAG
import net.taler.wallet.backend.WalletBackendApi
-import org.json.JSONObject
sealed class RefundStatus {
object Error : RefundStatus()
- object Success : RefundStatus()
+ data class Success(val response: RefundResponse) : RefundStatus()
}
-class RefundManager(private val walletBackendApi: WalletBackendApi) {
+@Serializable
+data class RefundResponse(
+ val amountEffectivePaid: Amount,
+ val amountRefundGranted: Amount,
+ val amountRefundGone: Amount,
+ val pendingAtExchange: Boolean
+)
+
+class RefundManager(
+ private val api: WalletBackendApi,
+ private val scope: CoroutineScope
+) {
fun refund(refundUri: String): LiveData<RefundStatus> {
val liveData = MutableLiveData<RefundStatus>()
- val args = JSONObject().also { it.put("talerRefundUri", refundUri) }
- walletBackendApi.sendRequest("applyRefund", args) { isError, result ->
- if (isError) {
- Log.e(TAG, "Refund Error: $result")
+ scope.launch {
+ api.request("applyRefund", RefundResponse.serializer()) {
+ put("talerRefundUri", refundUri)
+ }.onError {
+ Log.e(TAG, "Refund Error: $it")
// TODO show error string
liveData.postValue(RefundStatus.Error)
- } else {
- Log.e(TAG, "Refund Success: $result")
- liveData.postValue(RefundStatus.Success)
+ }.onSuccess {
+ Log.e(TAG, "Refund Success: $it")
+ liveData.postValue(RefundStatus.Success(it))
}
}
return liveData
diff --git
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
index 0142978..be83b09 100644
---
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
+++
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailFragment.kt
@@ -55,7 +55,8 @@ class TransactionDetailFragment : Fragment() {
}
override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
+ inflater: LayoutInflater,
+ container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(transaction.detailPageLayout, container, false)
@@ -96,7 +97,9 @@ class TransactionDetailFragment : Fragment() {
private fun bind(t: TransactionWithdrawal) {
effectiveAmountLabel.text = getString(R.string.withdraw_total)
effectiveAmountView.text = t.amountEffective.toString()
- if (t.pending && t.withdrawalDetails is TalerBankIntegrationApi &&
!t.confirmed && t.withdrawalDetails.bankConfirmationUrl != null) {
+ if (t.pending && t.withdrawalDetails is TalerBankIntegrationApi &&
+ !t.confirmed && t.withdrawalDetails.bankConfirmationUrl != null
+ ) {
val i = Intent().apply {
data = Uri.parse(t.withdrawalDetails.bankConfirmationUrl)
}
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 b9f86b3..e9b1b71 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
@@ -17,20 +17,14 @@
package net.taler.wallet.transactions
import androidx.annotation.UiThread
-import androidx.annotation.WorkerThread
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.switchMap
import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.module.kotlin.readValue
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 {
class Error(val msg: String) : TransactionsResult()
@@ -38,7 +32,7 @@ sealed class TransactionsResult {
}
class TransactionManager(
- private val walletBackendApi: WalletBackendApi,
+ private val api: WalletBackendApi,
private val scope: CoroutineScope,
private val mapper: ObjectMapper
) {
@@ -62,44 +56,36 @@ class TransactionManager(
}
@UiThread
- fun loadTransactions(searchQuery: String? = null) {
- val currency = selectedCurrency ?: return
+ fun loadTransactions(searchQuery: String? = null) = scope.launch {
+ val currency = selectedCurrency ?: return@launch
val liveData = mTransactions.getOrPut(currency) { MutableLiveData() }
if (searchQuery == null && allTransactions.containsKey(currency)) {
liveData.value =
TransactionsResult.Success(allTransactions[currency]!!)
}
if (liveData.value == null) mProgress.value = true
- val request = JSONObject(mapOf("currency" to currency))
- searchQuery?.let { request.put("search", it) }
- walletBackendApi.sendRequest("getTransactions", request) { isError,
result ->
- if (isError) {
-
liveData.postValue(TransactionsResult.Error(getErrorString(result)))
- mProgress.postValue(false)
- } else {
- val currencyToUpdate = if (searchQuery == null) currency else
null
- scope.launch(Dispatchers.Default) {
- onTransactionsLoaded(liveData, currencyToUpdate, result)
- }
- }
- }
- }
- @WorkerThread
- private fun onTransactionsLoaded(
- liveData: MutableLiveData<TransactionsResult>,
- currency: String?, // only non-null if we should update all
transactions cache
- result: JSONObject
- ) {
- val transactionsArray = result.getString("transactions")
- val transactions: LinkedList<Transaction> =
mapper.readValue(transactionsArray)
- // TODO remove when fixed in wallet-core
- transactions.sortWith(compareBy({ it.pending }, { it.timestamp.ms }, {
it.transactionId }))
- transactions.reverse() // show latest first
- mProgress.postValue(false)
- liveData.postValue(TransactionsResult.Success(transactions))
- // update all transactions on UiThread if there was a currency
- currency?.let {
- scope.launch(Dispatchers.Main) { allTransactions[currency] =
transactions }
+ api.request<Transactions>("getTransactions", mapper) {
+ if (searchQuery != null) put("search", searchQuery)
+ put("currency", currency)
+ }.onError {
+ liveData.postValue(TransactionsResult.Error(it.userFacingMsg))
+ mProgress.postValue(false)
+ }.onSuccess { result ->
+ val transactions = result.transactions
+ // TODO remove when fixed in wallet-core
+ val comparator = compareBy<Transaction>(
+ { it.pending },
+ { it.timestamp.ms },
+ { it.transactionId }
+ )
+ transactions.sortWith(comparator)
+ transactions.reverse() // show latest first
+
+ mProgress.value = false
+ liveData.value = TransactionsResult.Success(transactions)
+
+ // update all transactions on UiThread if there was a currency
+ if (searchQuery == null) allTransactions[currency] = transactions
}
}
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
index 1ba7e79..d227183 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -36,8 +36,9 @@ import net.taler.wallet.R
import net.taler.wallet.cleanExchange
import net.taler.wallet.transactions.WithdrawalDetails.ManualTransfer
import net.taler.wallet.transactions.WithdrawalDetails.TalerBankIntegrationApi
+import java.util.LinkedList
-data class Transactions(val transactions: List<Transaction>)
+data class Transactions(val transactions: LinkedList<Transaction>)
@JsonTypeInfo(use = NAME, include = PROPERTY, property = "type")
@JsonSubTypes(
@@ -188,9 +189,14 @@ class TransactionRefund(
pending: Boolean,
val refundedTransactionId: String,
val info: TransactionInfo,
- val amountInvalid: Amount,
+ /**
+ * Part of the refund that couldn't be applied because the refund
permissions were expired
+ */
+ val amountInvalid: Amount? = null,
error: TransactionError? = null,
+ @JsonProperty("amountEffective") // TODO remove when fixed in wallet-core
amountRaw: Amount,
+ @JsonProperty("amountRaw") // TODO remove when fixed in wallet-core
amountEffective: Amount
) : Transaction(transactionId, timestamp, pending, error, amountRaw,
amountEffective) {
override val icon = R.drawable.transaction_refund
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 1066550..2aaa5dc 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
@@ -78,9 +78,11 @@ class WithdrawManager(
var exchangeFees: ExchangeFees? = null
private set
- fun withdrawTestkudos() {
+ fun withdrawTestkudos() = scope.launch {
testWithdrawalInProgress.value = true
- api.sendRequest("withdrawTestkudos") { _, _ ->
+ api.request<Unit>("withdrawTestkudos").onError {
+ testWithdrawalInProgress.postValue(false)
+ }.onSuccess {
testWithdrawalInProgress.postValue(false)
}
}
diff --git a/wallet/src/main/res/layout/fragment_error.xml
b/wallet/src/main/res/layout/fragment_error.xml
index 0f7b047..b9f585f 100644
--- a/wallet/src/main/res/layout/fragment_error.xml
+++ b/wallet/src/main/res/layout/fragment_error.xml
@@ -28,7 +28,6 @@
android:layout_margin="16dp"
android:alpha="0.56"
android:src="@drawable/ic_error"
- android:tint="@color/red"
app:layout_constraintBottom_toTopOf="@+id/errorTitle"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
@@ -36,6 +35,7 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintVertical_chainStyle="packed"
+ app:tint="@color/red"
tools:ignore="ContentDescription" />
<TextView
diff --git a/wallet/src/main/res/values-fr/strings.xml
b/wallet/src/main/res/values-fr/strings.xml
index a96e23a..3a54659 100644
--- a/wallet/src/main/res/values-fr/strings.xml
+++ b/wallet/src/main/res/values-fr/strings.xml
@@ -80,7 +80,7 @@
<string name="settings_withdraw_testkudos_summary">Obtenez de l\'argent
pour les tests</string>
<string name="settings_reset_summary">Détruit votre argent</string>
<string name="refund_error">Erreur lors du traitement du
remboursement</string>
- <string name="refund_success">Remboursement reçu</string>
+ <string name="refund_success">Remboursement reçu: %s</string>
<string name="payment_error">Erreur : %s</string>
<string name="google_play_full_desc"
tools:keep="@string/google_play_full_desc">Cette application est un
portefeuille pour GNU Taler. Elle est très expérimentale et n\'est pas encore
prête à être utilisée en production. GNU Taler est un système de paiement
préservant la vie privée. Les clients peuvent rester anonymes, mais les
commerçants ne peuvent pas cacher leurs revenus par des paiements avec GNU
Taler. Cela permet d\'éviter l\'évasion fiscale et le blanchiment d\'argent. Le
prin [...]
<string name="payment_label_amount_total">Montant total :</string>
diff --git a/wallet/src/main/res/values/strings.xml
b/wallet/src/main/res/values/strings.xml
index 1715ab3..a9f6c73 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -168,7 +168,7 @@ GNU Taler is immune against many types of fraud, such as
phishing of credit card
<string name="refund_title">Refund</string>
<string name="refund_error">Error processing refund</string>
- <string name="refund_success">Refund received</string>
+ <string name="refund_success">Refund received: %s</string>
<string name="tip_title">Tip</string>
<string name="wifi_disabled_error">Turn on Wi-Fi to get free Wi-Fi</string>
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-taler-android] branch master updated (3ab6f15 -> e9f9b50),
gnunet <=