gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-android] branch master updated: accept tips


From: gnunet
Subject: [taler-taler-android] branch master updated: accept tips
Date: Fri, 01 Jul 2022 23:06:40 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository taler-android.

The following commit(s) were added to refs/heads/master by this push:
     new c3c4372  accept tips
c3c4372 is described below

commit c3c43726de9858f42fee9d4051ab3d3245b47099
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Jul 1 18:05:51 2022 -0300

    accept tips
---
 .../src/main/java/net/taler/wallet/MainActivity.kt |   5 +
 .../main/java/net/taler/wallet/MainViewModel.kt    |   2 +
 .../taler/wallet/tip/AlreadyAcceptedFragment.kt    |  49 ++++
 .../java/net/taler/wallet/tip/PromptTipFragment.kt | 160 +++++++++++++
 .../main/java/net/taler/wallet/tip/TipManager.kt   | 124 ++++++++++
 .../main/java/net/taler/wallet/tip/TipResponses.kt |  63 +++++
 .../net/taler/wallet/transactions/Transactions.kt  |   7 +-
 .../main/res/layout/fragment_already_accepted.xml  |  52 +++++
 wallet/src/main/res/layout/fragment_prompt_tip.xml | 257 +++++++++++++++++++++
 wallet/src/main/res/navigation/nav_graph.xml       |  24 ++
 wallet/src/main/res/values/strings.xml             |   8 +
 .../java/net/taler/wallet/tip/TipResponsesTest.kt  |  93 ++++++++
 12 files changed, 840 insertions(+), 4 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt 
b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
index 3b8be4f..40da9a2 100644
--- a/wallet/src/main/java/net/taler/wallet/MainActivity.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
@@ -166,6 +166,11 @@ class MainActivity : AppCompatActivity(), 
OnNavigationItemSelectedListener,
                 nav.navigate(R.id.action_nav_main_to_promptPayment)
                 model.paymentManager.preparePay(url)
             }
+            action.startsWith("tip/") -> {
+                Log.v(TAG, "navigating!")
+                nav.navigate(R.id.action_nav_main_to_promptTip)
+                model.tipManager.prepareTip(url)
+            }
             action.startsWith("withdraw/") -> {
                 Log.v(TAG, "navigating!")
                 // there's more than one entry point, so use global action
diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt 
b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
index 7bb6ad9..5041037 100644
--- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -36,6 +36,7 @@ import net.taler.wallet.exchanges.ExchangeManager
 import net.taler.wallet.payment.PaymentManager
 import net.taler.wallet.pending.PendingOperationsManager
 import net.taler.wallet.refund.RefundManager
+import net.taler.wallet.tip.TipManager
 import net.taler.wallet.transactions.TransactionManager
 import net.taler.wallet.withdraw.WithdrawManager
 import org.json.JSONObject
@@ -86,6 +87,7 @@ class MainViewModel(val app: Application) : 
AndroidViewModel(app) {
     }
 
     val withdrawManager = WithdrawManager(api, viewModelScope)
+    val tipManager = TipManager(api, viewModelScope)
     val paymentManager = PaymentManager(api, viewModelScope)
     val pendingOperationsManager: PendingOperationsManager = 
PendingOperationsManager(api)
     val transactionManager: TransactionManager = TransactionManager(api, 
viewModelScope)
diff --git 
a/wallet/src/main/java/net/taler/wallet/tip/AlreadyAcceptedFragment.kt 
b/wallet/src/main/java/net/taler/wallet/tip/AlreadyAcceptedFragment.kt
new file mode 100644
index 0000000..d76b6a1
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/tip/AlreadyAcceptedFragment.kt
@@ -0,0 +1,49 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.tip
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.findNavController
+import net.taler.wallet.databinding.FragmentAlreadyAcceptedBinding
+
+/**
+ * Display the message that the user already paid for the order
+ * that the merchant is proposing.
+ */
+class AlreadyAcceptedFragment : Fragment() {
+
+    private lateinit var ui: FragmentAlreadyAcceptedBinding
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        ui = FragmentAlreadyAcceptedBinding.inflate(inflater, container, false)
+        return ui.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        ui.backButton.setOnClickListener {
+            findNavController().navigateUp()
+        }
+    }
+
+}
diff --git a/wallet/src/main/java/net/taler/wallet/tip/PromptTipFragment.kt 
b/wallet/src/main/java/net/taler/wallet/tip/PromptTipFragment.kt
new file mode 100644
index 0000000..a5c504c
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/tip/PromptTipFragment.kt
@@ -0,0 +1,160 @@
+/*
+ * 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.wallet.tip
+
+import android.graphics.Bitmap
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.GONE
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.google.android.material.snackbar.Snackbar
+import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
+import net.taler.common.Amount
+import net.taler.common.ContractTerms
+import net.taler.common.fadeIn
+import net.taler.common.fadeOut
+import net.taler.wallet.MainViewModel
+import net.taler.wallet.R
+import net.taler.wallet.cleanExchange
+import net.taler.wallet.databinding.FragmentPromptPaymentBinding
+import net.taler.wallet.databinding.FragmentPromptTipBinding
+import net.taler.wallet.withdraw.ExchangeSelection
+
+/**
+ * Show a tip and ask the user to accept/decline.
+ */
+class PromptTipFragment : Fragment() {
+
+    private val model: MainViewModel by activityViewModels()
+    private val tipManager by lazy { model.tipManager }
+
+    private lateinit var ui: FragmentPromptTipBinding
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?,
+    ): View {
+        ui = FragmentPromptTipBinding.inflate(inflater, container, false)
+        ui.introView.fadeIn()
+        return ui.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        tipManager.tipStatus.observe(viewLifecycleOwner, 
::onPaymentStatusChanged)
+
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        if (!requireActivity().isChangingConfigurations) {
+            // tipManager.abortTip()
+        }
+    }
+
+    private fun showLoading(show: Boolean) {
+        model.showProgressBar.value = show
+        if (show) {
+            ui.progressBar.fadeIn()
+        } else {
+            ui.progressBar.fadeOut()
+        }
+    }
+
+    private fun onPaymentStatusChanged(payStatus: TipStatus?) {
+        when (payStatus) {
+            is TipStatus.Prepared -> {
+                showLoading(false)
+                showContent(payStatus.tipAmountRaw, 
payStatus.tipAmountEffective, payStatus.exchangeBaseUrl, 
payStatus.merchantBaseUrl)
+                //showOrder(payStatus.contractTerms, payStatus.amountRaw, fees)
+                ui.confirmWithdrawButton.isEnabled = true
+                ui.confirmWithdrawButton.setOnClickListener {
+                    model.showProgressBar.value = true
+                    tipManager.confirmTip(
+                        payStatus.walletTipId,
+                        payStatus.tipAmountRaw.currency
+                    )
+                    ui.confirmWithdrawButton.fadeOut()
+                    ui.progressBar.fadeIn()
+                }
+            }
+            is TipStatus.AlreadyAccepted -> {
+                showLoading(false)
+                tipManager.resetTipStatus()
+                
findNavController().navigate(R.id.action_promptTip_to_alreadyAccepted)
+            }
+            is TipStatus.Success -> {
+                showLoading(false)
+                tipManager.resetTipStatus()
+                findNavController().navigate(R.id.action_promptTip_to_nav_main)
+                model.showTransactions(payStatus.currency)
+                Snackbar.make(requireView(), R.string.tip_received, 
LENGTH_LONG).show()
+            }
+            is TipStatus.Error -> {
+                showLoading(false)
+                ui.introView.text = getString(R.string.payment_error, 
payStatus.error)
+                ui.introView.fadeIn()
+            }
+            is TipStatus.None -> {
+                // No payment active.
+                showLoading(false)
+            }
+            is TipStatus.Loading -> {
+                // Wait until loaded ...
+                showLoading(true)
+            }
+        }
+    }
+
+    private fun showContent(
+        amountRaw: Amount,
+        amountEffective: Amount,
+        exchange: String,
+        merchant: String,
+    ) {
+        model.showProgressBar.value = false
+        ui.progressBar.fadeOut()
+
+        ui.introView.fadeIn()
+        ui.effectiveAmountView.text = amountEffective.toString()
+        ui.effectiveAmountView.fadeIn()
+
+        ui.chosenAmountLabel.fadeIn()
+        ui.chosenAmountView.text = amountRaw.toString()
+        ui.chosenAmountView.fadeIn()
+
+        ui.feeLabel.fadeIn()
+        ui.feeView.text =
+            getString(R.string.amount_negative, (amountRaw - 
amountEffective).toString())
+        ui.feeView.fadeIn()
+
+        ui.exchangeIntroView.fadeIn()
+        ui.withdrawExchangeUrl.text = cleanExchange(exchange)
+        ui.withdrawExchangeUrl.fadeIn()
+
+        ui.merchantIntroView.fadeIn()
+        ui.withdrawMerchantUrl.text = cleanExchange(merchant)
+        ui.withdrawMerchantUrl.fadeIn()
+
+        ui.withdrawCard.fadeIn()
+    }
+
+}
diff --git a/wallet/src/main/java/net/taler/wallet/tip/TipManager.kt 
b/wallet/src/main/java/net/taler/wallet/tip/TipManager.kt
new file mode 100644
index 0000000..855feb0
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/tip/TipManager.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.wallet.tip
+
+import android.util.Log
+import androidx.annotation.UiThread
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import net.taler.common.Amount
+import net.taler.common.Timestamp
+import net.taler.wallet.TAG
+import net.taler.wallet.backend.WalletBackendApi
+import net.taler.wallet.backend.TalerErrorInfo
+import net.taler.wallet.tip.PrepareTipResponse.TipPossibleResponse
+import net.taler.wallet.tip.PrepareTipResponse.AlreadyAcceptedResponse
+
+sealed class TipStatus {
+    object None : TipStatus()
+    object Loading : TipStatus()
+    data class Prepared(
+        val walletTipId: String,
+        val merchantBaseUrl: String,
+        val exchangeBaseUrl: String,
+        val expirationTimestamp: Timestamp,
+        val tipAmountRaw: Amount,
+        val tipAmountEffective: Amount,
+    ) : TipStatus()
+
+    data class AlreadyAccepted(
+        val walletTipId: String,
+    ) : TipStatus()
+
+    // TODO bring user to fulfilment URI
+    data class Error(val error: String) : TipStatus()
+    data class Success(val currency: String) : TipStatus()
+}
+
+class TipManager(
+    private val api: WalletBackendApi,
+    private val scope: CoroutineScope,
+) {
+
+    private val mTipStatus = MutableLiveData<TipStatus>(TipStatus.None)
+    internal val tipStatus: LiveData<TipStatus> = mTipStatus
+
+    @UiThread
+    fun prepareTip(url: String) = scope.launch {
+        mTipStatus.value = TipStatus.Loading
+        api.request("prepareTip", PrepareTipResponse.serializer()) {
+            put("talerTipUri", url)
+        }.onError {
+            handleError("prepareTip", it)
+        }.onSuccess { response ->
+            mTipStatus.value = when (response) {
+                is TipPossibleResponse -> response.toTipStatusPrepared()
+                is AlreadyAcceptedResponse -> TipStatus.AlreadyAccepted(
+                    response.walletTipId
+                )
+            }
+        }
+    }
+
+    fun confirmTip(tipId: String, currency: String) = scope.launch {
+        api.request("acceptTip", ConfirmTipResult.serializer()) {
+            put("walletTipId", tipId)
+        }.onError {
+            handleError("acceptTip", it)
+        }.onSuccess {
+            mTipStatus.postValue(TipStatus.Success(currency))
+        }
+    }
+
+/*
+    @UiThread
+    fun abortTip() {
+        val ps = tipStatus.value
+        if (ps is TipStatus.Prepared) {
+            abortProposal(ps.walletTipId)
+        }
+        resetTipStatus()
+    }
+*/
+
+/*
+    internal fun abortProposal(proposalId: String) = scope.launch {
+        Log.i(TAG, "aborting proposal")
+        api.request<Unit>("abortProposal") {
+            put("proposalId", proposalId)
+        }.onError {
+            Log.e(TAG, "received error response to abortProposal")
+            handleError("abortProposal", it)
+        }.onSuccess {
+            mTipStatus.postValue(TipStatus.None)
+        }
+    }
+*/
+
+    @UiThread
+    fun resetTipStatus() {
+        mTipStatus.value = TipStatus.None
+    }
+
+    private fun handleError(operation: String, error: TalerErrorInfo) {
+        Log.e(TAG, "got $operation error result $error")
+        mTipStatus.value = TipStatus.Error(error.userFacingMsg)
+    }
+
+}
diff --git a/wallet/src/main/java/net/taler/wallet/tip/TipResponses.kt 
b/wallet/src/main/java/net/taler/wallet/tip/TipResponses.kt
new file mode 100644
index 0000000..aa2da15
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/tip/TipResponses.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.wallet.tip
+
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.JsonClassDiscriminator
+import net.taler.common.Amount
+import net.taler.common.ContractTerms
+import net.taler.common.Timestamp
+import net.taler.wallet.backend.TalerErrorInfo
+
+@OptIn(ExperimentalSerializationApi::class)
+@Serializable
+@JsonClassDiscriminator("accepted")
+sealed class PrepareTipResponse {
+
+    @Serializable
+    @SerialName("false")
+    data class TipPossibleResponse(
+        val walletTipId: String,
+        val merchantBaseUrl: String,
+        val exchangeBaseUrl: String,
+        val expirationTimestamp: Timestamp,
+        val tipAmountRaw: Amount,
+        val tipAmountEffective: Amount,
+    ) : PrepareTipResponse() {
+        fun toTipStatusPrepared() = TipStatus.Prepared(
+            walletTipId = walletTipId,
+            merchantBaseUrl = merchantBaseUrl,
+            exchangeBaseUrl = exchangeBaseUrl,
+            expirationTimestamp = expirationTimestamp,
+            tipAmountEffective = tipAmountEffective,
+            tipAmountRaw =  tipAmountRaw
+        )
+    }
+
+    @Serializable
+    @SerialName("true")
+    data class AlreadyAcceptedResponse(
+        val walletTipId: String,
+    ) : PrepareTipResponse()
+}
+
+@Serializable
+class ConfirmTipResult {
+
+}
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 cca370e..ca01501 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -212,9 +212,8 @@ class TransactionTip(
     override val transactionId: String,
     override val timestamp: Timestamp,
     override val pending: Boolean,
-    // TODO status: TipStatus,
-    val exchangeBaseUrl: String,
-    val merchant: ContractMerchant,
+    val frozen: Boolean,
+    val merchantBaseUrl: String,
     override val error: TalerErrorInfo? = null,
     override val amountRaw: Amount,
     override val amountEffective: Amount
@@ -225,7 +224,7 @@ class TransactionTip(
     @Transient
     override val amountType = AmountType.Positive
     override fun getTitle(context: Context): String {
-        return context.getString(R.string.transaction_tip_from, merchant.name)
+        return context.getString(R.string.transaction_tip_from, 
merchantBaseUrl)
     }
 
     override val generalTitleRes = R.string.tip_title
diff --git a/wallet/src/main/res/layout/fragment_already_accepted.xml 
b/wallet/src/main/res/layout/fragment_already_accepted.xml
new file mode 100644
index 0000000..b1a7bb1
--- /dev/null
+++ b/wallet/src/main/res/layout/fragment_already_accepted.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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/>
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
+    xmlns:app="http://schemas.android.com/apk/res-auto";
+    xmlns:tools="http://schemas.android.com/tools";
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_margin="15dp"
+    android:orientation="vertical"
+    tools:context=".tip.AlreadyAcceptedFragment">
+
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="50dp"
+        android:layout_gravity="center"
+        android:text="@string/tip_already_accepted"
+        android:textAlignment="center"
+        android:textColor="@android:color/holo_green_dark"
+        app:autoSizeTextType="uniform" />
+
+
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <Button
+        android:id="@+id/backButton"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/button_back" />
+
+</LinearLayout>
diff --git a/wallet/src/main/res/layout/fragment_prompt_tip.xml 
b/wallet/src/main/res/layout/fragment_prompt_tip.xml
new file mode 100644
index 0000000..d96ef60
--- /dev/null
+++ b/wallet/src/main/res/layout/fragment_prompt_tip.xml
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ 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/>
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android";
+    xmlns:app="http://schemas.android.com/apk/res-auto";
+    xmlns:tools="http://schemas.android.com/tools";
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".tip.PromptTipFragment">
+
+    <TextView
+        android:id="@+id/introView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginBottom="8dp"
+        android:gravity="center"
+        android:text="@string/tip_total"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toTopOf="@+id/effectiveAmountView"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_chainStyle="packed"
+        tools:visibility="visible" />
+
+    <TextView
+        android:id="@+id/effectiveAmountView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="16dp"
+        android:gravity="center"
+        android:textColor="@color/green"
+        android:textSize="24sp"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toTopOf="@+id/chosenAmountLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/introView"
+        tools:text="9.8 TESTKUDOS"
+        tools:visibility="visible" />
+
+    <TextView
+        android:id="@+id/chosenAmountLabel"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="32dp"
+        android:layout_marginEnd="16dp"
+        android:gravity="center"
+        android:text="@string/amount_chosen"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toTopOf="@+id/chosenAmountView"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/effectiveAmountView"
+        tools:visibility="visible" />
+
+    <TextView
+        android:id="@+id/chosenAmountView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="16dp"
+        android:gravity="center"
+        android:textSize="20sp"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toTopOf="@+id/feeLabel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/chosenAmountLabel"
+        tools:text="10 TESTKUDOS"
+        tools:visibility="visible" />
+
+    <TextView
+        android:id="@+id/feeLabel"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="32dp"
+        android:layout_marginEnd="16dp"
+        android:gravity="center"
+        android:text="@string/tip_fees"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toTopOf="@+id/feeView"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/chosenAmountView"
+        tools:visibility="visible" />
+
+    <TextView
+        android:id="@+id/feeView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="16dp"
+        android:gravity="center"
+        android:textColor="@color/red"
+        android:textSize="20sp"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toTopOf="@+id/exchangeIntroView"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/feeLabel"
+        tools:text="-0.2 TESTKUDOS"
+        tools:visibility="visible" />
+
+    <TextView
+        android:id="@+id/exchangeIntroView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="32dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginBottom="8dp"
+        android:gravity="center"
+        android:text="@string/tip_exchange"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toTopOf="@+id/withdrawExchangeUrl"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/feeView"
+        tools:visibility="visible" />
+
+    <TextView
+        android:id="@+id/withdrawExchangeUrl"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginBottom="8dp"
+        android:layout_marginEnd="8dp"
+        android:gravity="center"
+        android:textSize="24sp"
+        android:visibility="invisible"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintBottom_toTopOf="@+id/merchantIntroView"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/exchangeIntroView"
+        tools:text="demo.taler.net"
+        tools:visibility="visible" />
+
+    <TextView
+        android:id="@+id/merchantIntroView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginBottom="8dp"
+        android:gravity="center"
+        android:text="@string/tip_merchant_url"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toTopOf="@+id/withdrawMerchantUrl"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/withdrawExchangeUrl"
+        tools:visibility="visible" />
+
+
+    <TextView
+        android:id="@+id/withdrawMerchantUrl"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="8dp"
+        android:gravity="center"
+        android:textSize="24sp"
+        android:visibility="invisible"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintBottom_toTopOf="@+id/withdrawCard"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.502"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/merchantIntroView"
+        tools:text="merchant.demo.taler.net"
+        tools:visibility="visible" />
+
+    <ProgressBar
+        android:id="@+id/progressBar"
+        style="?android:attr/progressBarStyleLarge"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/withdrawCard"
+        style="@style/BottomCard"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        tools:visibility="visible">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="8dp">
+
+            <Button
+                android:id="@+id/confirmWithdrawButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:backgroundTint="@color/green"
+                android:enabled="false"
+                android:text="@string/tip_button_confirm"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintHorizontal_bias="1.0"
+                app:layout_constraintStart_toStartOf="parent"
+                tools:enabled="true"
+                tools:text="@string/tip_button_confirm" />
+
+            <ProgressBar
+                android:id="@+id/confirmProgressBar"
+                style="?android:attr/progressBarStyle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="invisible"
+                
app:layout_constraintBottom_toBottomOf="@+id/confirmWithdrawButton"
+                app:layout_constraintEnd_toEndOf="@+id/confirmWithdrawButton"
+                
app:layout_constraintStart_toStartOf="@+id/confirmWithdrawButton"
+                app:layout_constraintTop_toTopOf="@+id/confirmWithdrawButton"
+                tools:visibility="visible" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/wallet/src/main/res/navigation/nav_graph.xml 
b/wallet/src/main/res/navigation/nav_graph.xml
index 469a399..b3f96c5 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -34,6 +34,24 @@
         <action
             android:id="@+id/action_nav_main_to_nav_uri_input"
             app:destination="@id/nav_uri_input" />
+        <action
+            android:id="@+id/action_nav_main_to_promptTip"
+            app:destination="@id/promptTip" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/promptTip"
+        android:name="net.taler.wallet.tip.PromptTipFragment"
+        android:label="Review Tip"
+        tools:layout="@layout/fragment_prompt_tip">
+        <action
+            android:id="@+id/action_promptTip_to_nav_main"
+            app:destination="@id/nav_main"
+            app:popUpTo="@id/nav_main" />
+        <action
+            android:id="@+id/action_promptTip_to_alreadyAccepted"
+            app:destination="@id/alreadyAccepted"
+            app:popUpTo="@id/nav_main" />
     </fragment>
 
     <fragment
@@ -130,6 +148,12 @@
         android:label="@string/transactions_detail_title"
         tools:layout="@layout/fragment_transaction_withdrawal" />
 
+    <fragment
+        android:id="@+id/alreadyAccepted"
+        android:name="net.taler.wallet.tip.AlreadyAcceptedFragment"
+        android:label="@string/tip_already_accepted"
+        tools:layout="@layout/fragment_already_accepted" />
+
     <fragment
         android:id="@+id/alreadyPaid"
         android:name="net.taler.wallet.payment.AlreadyPaidFragment"
diff --git a/wallet/src/main/res/values/strings.xml 
b/wallet/src/main/res/values/strings.xml
index 592070c..efaa7dd 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -187,6 +187,14 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
     <string name="refund_success">Refund received: %s</string>
 
     <string name="tip_title">Tip</string>
+    <string name="tip_already_accepted">This tip is already accepted.</string>
+    <string name="tip_total">Total</string>
+    <string name="tip_fees">Fee</string>
+    <string name="tip_exchange">Exchange</string>
+    <string name="tip_merchant_url">Merchant URL</string>
+    <string name="tip_button_confirm">Accept tip</string>
+    <string name="tip_received">Tip received</string>
+
     <string name="wifi_disabled_error">Turn on Wi-Fi to get free Wi-Fi</string>
     <string name="wifi_connect_error">Could not connect to free Wi-Fi: 
%s</string>
 
diff --git a/wallet/src/test/java/net/taler/wallet/tip/TipResponsesTest.kt 
b/wallet/src/test/java/net/taler/wallet/tip/TipResponsesTest.kt
new file mode 100644
index 0000000..9267f11
--- /dev/null
+++ b/wallet/src/test/java/net/taler/wallet/tip/TipResponsesTest.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.wallet.payment
+
+import kotlinx.serialization.json.Json
+import net.taler.common.Amount
+import net.taler.wallet.tip.ConfirmTipResult
+import net.taler.wallet.tip.PrepareTipResponse
+import org.junit.Test
+
+class TipResponsesTest {
+
+    private val json = Json {
+        ignoreUnknownKeys = true
+    }
+
+    @Test
+    fun testConfirmTipResult() {
+        val jsonStr = """
+            {
+            "type": "response", 
+            "operation": "acceptTip",
+             "id": 47,
+            "result": {}
+             }
+        """.trimIndent()
+        val response = json.decodeFromString(ConfirmTipResult.serializer(), 
jsonStr)
+        response as ConfirmTipResult
+        assert(response != null)
+    }
+
+/*
+
+*/
+
+
+    @Test
+    fun testTipPossibleSerializer() {
+        val jsonStr = """
+        {
+            "accepted": false,
+            "tipAmountRaw": "ARS:2",
+            "exchangeBaseUrl": "http://exchange.taler:8081/";,
+            "merchantBaseUrl": "http://merchant-backend.taler:9966/";,
+            "expirationTimestamp": {
+                "t_s": 1688217455
+            },
+            "tipAmountEffective": "ARS:1.4",
+            "walletTipId": 
"SZH86ATJC4NZ427JHFVQ9M3S1TCQKVWSSZGSBW8MQ8VTVWD4M4GG"
+        }    
+        """.trimIndent()
+        val response = json.decodeFromString(PrepareTipResponse.serializer(), 
jsonStr)
+        response as PrepareTipResponse.TipPossibleResponse
+        assert(response.walletTipId == 
"SZH86ATJC4NZ427JHFVQ9M3S1TCQKVWSSZGSBW8MQ8VTVWD4M4GG")
+        assert(response.tipAmountEffective == Amount(currency = "ARS", 
fraction = 40000000, value = 1))
+    }
+
+
+    @Test
+    fun testTipAcceptedSerializer() {
+        val jsonStr = """
+        {
+            "accepted": true,
+            "tipAmountRaw": "ARS:2",
+            "exchangeBaseUrl": "http://exchange.taler:8081/";,
+            "merchantBaseUrl": "http://merchant-backend.taler:9966/";,
+            "expirationTimestamp": {
+                "t_s": 1688217455
+            },
+            "tipAmountEffective": "ARS:1.4",
+            "walletTipId": 
"SZH86ATJC4NZ427JHFVQ9M3S1TCQKVWSSZGSBW8MQ8VTVWD4M4GG"
+        }  
+        """.trimIndent()
+        val response = json.decodeFromString(PrepareTipResponse.serializer(), 
jsonStr)
+        assert(response is PrepareTipResponse.AlreadyAcceptedResponse)
+        assert((response as 
PrepareTipResponse.AlreadyAcceptedResponse).walletTipId == 
"SZH86ATJC4NZ427JHFVQ9M3S1TCQKVWSSZGSBW8MQ8VTVWD4M4GG")
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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