diff options
author | Torsten Grote <t@grobox.de> | 2022-09-23 15:05:38 -0300 |
---|---|---|
committer | Torsten Grote <t@grobox.de> | 2022-09-23 15:05:38 -0300 |
commit | baca5eceb08055d35ef96d6d6586fbba55511d40 (patch) | |
tree | 26eaa30bde4d6d38775546bd5da811240d682e4e | |
parent | 54789b6adc3a7716c31b3d634b2afe55d95d9724 (diff) | |
download | taler-android-baca5eceb08055d35ef96d6d6586fbba55511d40.tar.gz taler-android-baca5eceb08055d35ef96d6d6586fbba55511d40.tar.bz2 taler-android-baca5eceb08055d35ef96d6d6586fbba55511d40.zip |
[wallet] Implement beginning of deposits
9 files changed, 177 insertions, 14 deletions
diff --git a/wallet/src/main/AndroidManifest.xml b/wallet/src/main/AndroidManifest.xml index 69670c3..68bc321 100644 --- a/wallet/src/main/AndroidManifest.xml +++ b/wallet/src/main/AndroidManifest.xml @@ -63,6 +63,7 @@ <data android:scheme="TALER" tools:ignore="AppLinkUrlError" /> + <data android:scheme="payto" /> </intent-filter> </activity> diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt b/wallet/src/main/java/net/taler/wallet/MainActivity.kt index 5597564..cb48c30 100644 --- a/wallet/src/main/java/net/taler/wallet/MainActivity.kt +++ b/wallet/src/main/java/net/taler/wallet/MainActivity.kt @@ -203,9 +203,6 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, } } } else { - if (!scheme.startsWith("taler", ignoreCase = true)) { - return actionFound - } actionFound.postValue(uri.toString()) } @@ -225,8 +222,8 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener, val action = normalizedURL.substring( if (normalizedURL.startsWith("taler://", ignoreCase = true)) { "taler://".length - } else if (normalizedURL.startsWith("taler+http://", - ignoreCase = true) && model.devMode.value == true + } else if (normalizedURL.startsWith("taler+http://", ignoreCase = true) && + model.devMode.value == true ) { "taler+http://".length } else { diff --git a/wallet/src/main/java/net/taler/wallet/UriInputFragment.kt b/wallet/src/main/java/net/taler/wallet/UriInputFragment.kt index 8ad1fb7..00ec404 100644 --- a/wallet/src/main/java/net/taler/wallet/UriInputFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/UriInputFragment.kt @@ -59,7 +59,8 @@ class UriInputFragment : Fragment() { } } ui.okButton.setOnClickListener { - if (ui.uriView.text?.startsWith("taler://", ignoreCase = true) == true) { + if (ui.uriView.text?.startsWith("taler://", ignoreCase = true) == true || + ui.uriView.text?.startsWith("payto://", ignoreCase = true) == true) { ui.uriLayout.error = null val i = Intent(ACTION_VIEW, Uri.parse(ui.uriView.text.toString())) startActivity(i) 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 ae091df..b8918c1 100644 --- a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt +++ b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt @@ -22,11 +22,12 @@ 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.common.ContractTerms import net.taler.wallet.TAG -import net.taler.wallet.backend.WalletBackendApi import net.taler.wallet.backend.TalerErrorInfo +import net.taler.wallet.backend.WalletBackendApi import net.taler.wallet.payment.PayStatus.AlreadyPaid import net.taler.wallet.payment.PayStatus.InsufficientBalance import net.taler.wallet.payment.PreparePayResponse.AlreadyConfirmedResponse @@ -119,9 +120,28 @@ class PaymentManager( mPayStatus.value = PayStatus.None } + @UiThread + fun makeDeposit(url: String, amount: Amount) = scope.launch { + // TODO + api.request("createDepositGroup", CreateDepositGroupResponse.serializer()) { + put("depositPaytoUri", url) + put("amount", amount.toJSONString()) + }.onError { + Log.e(TAG, "Error createDepositGroup $it") + }.onSuccess { + Log.e(TAG, "createDepositGroup $it") + } + } + private fun handleError(operation: String, error: TalerErrorInfo) { Log.e(TAG, "got $operation error result $error") mPayStatus.value = PayStatus.Error(error.userFacingMsg) } } + +@Serializable +data class CreateDepositGroupResponse( + val depositGroupId: String, + val transactionId: String, +) diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDepositFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDepositFragment.kt new file mode 100644 index 0000000..f721090 --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDepositFragment.kt @@ -0,0 +1,105 @@ +/* + * This file is part of GNU Taler + * (C) 2022 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.wallet.transactions + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment.Companion.CenterHorizontally +import androidx.compose.ui.Alignment.Companion.CenterVertically +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.google.android.material.composethemeadapter.MdcTheme +import net.taler.common.toAbsoluteTime +import net.taler.wallet.R + +class TransactionDepositFragment : TransactionDetailFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View = ComposeView(requireContext()).apply { + setContent { + MdcTheme { + Surface { + val t = transaction ?: error("No transaction") + TransactionDepositComposable(t as TransactionDeposit) { + onDeleteButtonClicked(t) + } + } + } + } + } +} + +@Composable +fun TransactionDepositComposable(t: TransactionDeposit, onDelete: () -> Unit) { + val scrollState = rememberScrollState() + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(scrollState), + horizontalAlignment = CenterHorizontally, + ) { + val context = LocalContext.current + Text( + modifier = Modifier.padding(16.dp), + text = t.timestamp.ms.toAbsoluteTime(context).toString(), + style = MaterialTheme.typography.body1, + ) + // TODO + Button( + modifier = Modifier.padding(16.dp), + colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(R.color.red)), + onClick = onDelete, + ) { + Row(verticalAlignment = CenterVertically) { + Icon( + painter = painterResource(id = R.drawable.ic_delete), + contentDescription = null, + tint = Color.White, + ) + Text( + modifier = Modifier.padding(start = 8.dp), + text = stringResource(R.string.transactions_delete), + color = Color.White, + ) + } + } + } +} 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 d1020e2..bbae22b 100644 --- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt +++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt @@ -89,7 +89,7 @@ class TransactionManager( } } - fun deleteTransaction(transactionId: String) = scope.launch { + fun deleteTransaction(transactionId: String) = scope.launch { api.request<Unit>("deleteTransaction") { put("transactionId", transactionId) }.onError { 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 97ac5ea..dcb524e 100644 --- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt +++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt @@ -75,7 +75,7 @@ class TransactionWithdrawal( val withdrawalDetails: WithdrawalDetails, override val error: TalerErrorInfo? = null, override val amountRaw: Amount, - override val amountEffective: Amount + override val amountEffective: Amount, ) : Transaction() { override val icon = R.drawable.transaction_withdrawal @@ -102,7 +102,7 @@ sealed class WithdrawalDetails { * * Already contains the amount and message. */ - val exchangePaytoUris: List<String> + val exchangePaytoUris: List<String>, ) : WithdrawalDetails() @Serializable @@ -133,7 +133,7 @@ class TransactionPayment( val status: PaymentStatus, override val error: TalerErrorInfo? = null, override val amountRaw: Amount, - override val amountEffective: Amount + override val amountEffective: Amount, ) : Transaction() { override val icon = R.drawable.ic_cash_usd_outline override val detailPageNav = R.id.action_nav_transactions_detail_payment @@ -192,7 +192,7 @@ class TransactionRefund( val amountInvalid: Amount? = null, override val error: TalerErrorInfo? = null, override val amountRaw: Amount, - override val amountEffective: Amount + override val amountEffective: Amount, ) : Transaction() { override val icon = R.drawable.transaction_refund override val detailPageNav = R.id.action_nav_transactions_detail_refund @@ -216,7 +216,7 @@ class TransactionTip( val merchantBaseUrl: String, override val error: TalerErrorInfo? = null, override val amountRaw: Amount, - override val amountEffective: Amount + override val amountEffective: Amount, ) : Transaction() { override val icon = R.drawable.transaction_tip_accepted // TODO different when declined override val detailPageNav = 0 @@ -239,7 +239,7 @@ class TransactionRefresh( val exchangeBaseUrl: String, override val error: TalerErrorInfo? = null, override val amountRaw: Amount, - override val amountEffective: Amount + override val amountEffective: Amount, ) : Transaction() { override val icon = R.drawable.transaction_refresh override val detailPageNav = R.id.action_nav_transactions_detail_refresh @@ -254,6 +254,30 @@ class TransactionRefresh( } @Serializable +@SerialName("deposit") +class TransactionDeposit( + override val transactionId: String, + override val timestamp: Timestamp, + override val pending: Boolean, + override val error: TalerErrorInfo? = null, + override val amountRaw: Amount, + override val amountEffective: Amount, + val targetPaytoUri: String, + val depositGroupId: String, +) : Transaction() { + override val icon = R.drawable.ic_cash_usd_outline + override val detailPageNav = R.id.action_nav_transactions_detail_deposit + + @Transient + override val amountType = AmountType.Negative + override fun getTitle(context: Context): String { + return context.getString(R.string.transaction_deposit) + } + + override val generalTitleRes = R.string.transaction_deposit +} + +@Serializable data class PeerInfoShort( val expiration: Timestamp? = null, val summary: String? = null, @@ -282,6 +306,7 @@ class TransactionPeerPullDebit( override fun getTitle(context: Context): String { return context.getString(R.string.transaction_peer_pull_debit) } + override val generalTitleRes = R.string.transaction_peer_pull_debit } @@ -309,6 +334,7 @@ class TransactionPeerPullCredit( override fun getTitle(context: Context): String { return context.getString(R.string.transaction_peer_pull_credit) } + override val generalTitleRes = R.string.transaction_peer_pull_credit } @@ -337,6 +363,7 @@ class TransactionPeerPushDebit( override fun getTitle(context: Context): String { return context.getString(R.string.transaction_peer_push_debit) } + override val generalTitleRes = R.string.payment_title } @@ -363,5 +390,6 @@ class TransactionPeerPushCredit( override fun getTitle(context: Context): String { return context.getString(R.string.transaction_peer_push_credit) } + override val generalTitleRes = R.string.transaction_peer_push_credit } diff --git a/wallet/src/main/res/navigation/nav_graph.xml b/wallet/src/main/res/navigation/nav_graph.xml index f9060c5..96ca49f 100644 --- a/wallet/src/main/res/navigation/nav_graph.xml +++ b/wallet/src/main/res/navigation/nav_graph.xml @@ -199,6 +199,12 @@ tools:layout="@layout/fragment_transaction_withdrawal" /> <fragment + android:id="@+id/nav_transactions_detail_deposit" + android:name="net.taler.wallet.transactions.TransactionDepositFragment" + android:label="@string/transactions_detail_title" + tools:layout="@layout/fragment_transaction_withdrawal" /> + + <fragment android:id="@+id/nav_transactions_detail_peer" android:name="net.taler.wallet.transactions.TransactionPeerFragment" android:label="@string/transactions_detail_title" @@ -323,4 +329,8 @@ android:id="@+id/action_nav_transactions_detail_refresh" app:destination="@id/nav_transactions_detail_refresh" /> + <action + android:id="@+id/action_nav_transactions_detail_deposit" + app:destination="@id/nav_transactions_detail_deposit" /> + </navigation> diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml index 52700b8..6d5f554 100644 --- a/wallet/src/main/res/values/strings.xml +++ b/wallet/src/main/res/values/strings.xml @@ -96,6 +96,7 @@ GNU Taler is immune against many types of fraud, such as phishing of credit card <string name="transaction_refund_from">Refund from %s</string> <string name="transaction_pending">PENDING</string> <string name="transaction_refresh">Coin expiry change fee</string> + <string name="transaction_deposit">Deposit</string> <string name="transaction_peer_push_debit">Push payment</string> <string name="transaction_peer_pull_credit">Invoice</string> <string name="transaction_peer_pull_debit">Invoice paid</string> |