[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-wallet-android] branch master updated (5f57c48 -> 30980bc)
From: |
gnunet |
Subject: |
[taler-wallet-android] branch master updated (5f57c48 -> 30980bc) |
Date: |
Tue, 03 Mar 2020 21:30:01 +0100 |
This is an automated email from the git hooks/post-receive script.
torsten-grote pushed a change to branch master
in repository wallet-android.
from 5f57c48 Fix lint and make all strings translatable
new a9fd9aa Clean up MainActivity and unregister receivers to not leak
them
new 30980bc Clean up and improve withdraw UI (first pass)
The 2 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:
.idea/codeStyles/Project.xml | 3 -
.idea/copyright/profiles_settings.xml | 2 +-
.idea/gradle.xml | 4 +-
.idea/scopes/Copyright_Files.xml | 3 +
app/build.gradle | 3 +-
app/src/main/java/net/taler/wallet/MainActivity.kt | 158 +++++++--------
.../main/java/net/taler/wallet/PromptWithdraw.kt | 127 ------------
.../java/net/taler/wallet/ReviewExchangeTOS.kt | 91 ---------
app/src/main/java/net/taler/wallet/ShowBalance.kt | 155 +++++++-------
app/src/main/java/net/taler/wallet/Utils.kt | 11 +-
.../main/java/net/taler/wallet/WalletViewModel.kt | 187 +----------------
.../wallet/withdraw/PromptWithdrawFragment.kt | 107 ++++++++++
.../wallet/withdraw/ReviewExchangeTosFragment.kt | 80 ++++++++
.../WithdrawManager.kt} | 222 ++-------------------
.../WithdrawSuccessfulFragment.kt} | 28 +--
.../main/res/layout-w550dp/payment_bottom_bar.xml | 3 +-
app/src/main/res/layout/app_bar_main.xml | 32 ++-
.../main/res/layout/fragment_prompt_withdraw.xml | 201 ++++++++++++-------
.../res/layout/fragment_review_exchange_tos.xml | 101 +++++++---
.../res/layout/fragment_withdraw_successful.xml | 66 +++---
app/src/main/res/layout/payment_bottom_bar.xml | 3 +-
app/src/main/res/navigation/nav_graph.xml | 12 +-
app/src/main/res/values/strings.xml | 3 +
app/src/main/res/values/styles.xml | 5 +
build.gradle | 7 +-
gradle/wrapper/gradle-wrapper.properties | 20 +-
26 files changed, 641 insertions(+), 993 deletions(-)
create mode 100644 .idea/scopes/Copyright_Files.xml
delete mode 100644 app/src/main/java/net/taler/wallet/PromptWithdraw.kt
delete mode 100644 app/src/main/java/net/taler/wallet/ReviewExchangeTOS.kt
create mode 100644
app/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
create mode 100644
app/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
copy app/src/main/java/net/taler/wallet/{WalletViewModel.kt =>
withdraw/WithdrawManager.kt} (50%)
rename app/src/main/java/net/taler/wallet/{WithdrawSuccessful.kt =>
withdraw/WithdrawSuccessfulFragment.kt} (65%)
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index a705caf..fad1c60 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -1,8 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
- <AndroidXmlCodeStyleSettings>
- <option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
- </AndroidXmlCodeStyleSettings>
<JetCodeStyleSettings>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS"
value="2147483647" />
diff --git a/.idea/copyright/profiles_settings.xml
b/.idea/copyright/profiles_settings.xml
index 0040fda..31766eb 100644
--- a/.idea/copyright/profiles_settings.xml
+++ b/.idea/copyright/profiles_settings.xml
@@ -1,7 +1,7 @@
<component name="CopyrightManager">
<settings default="Taler">
<module2copyright>
- <element module="Project Files" copyright="Taler" />
+ <element module="Copyright Files" copyright="Taler" />
</module2copyright>
</settings>
</component>
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 031c262..69c1925 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
+ <component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
+ <option name="delegatedBuild" value="false" />
+ <option name="testRunner" value="PLATFORM" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
@@ -13,7 +16,6 @@
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
- <option name="testRunner" value="PLATFORM" />
</GradleProjectSettings>
</option>
</component>
diff --git a/.idea/scopes/Copyright_Files.xml b/.idea/scopes/Copyright_Files.xml
new file mode 100644
index 0000000..e74c29b
--- /dev/null
+++ b/.idea/scopes/Copyright_Files.xml
@@ -0,0 +1,3 @@
+<component name="DependencyValidationManager">
+ <scope name="Copyright Files"
pattern="file[app]:src/*/java//*||file[app]:src/main/res/layout/*||file[app]:src/main/res/layout-w550dp/*||file[app]:src/main/res/navigation//*||file[app]:src/main/res/values//*||file[app]:src/main/res/xml//*"
/>
+</component>
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 921bbb1..2c7807e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -16,12 +16,11 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
- buildToolsVersion "29.0.2"
+ buildToolsVersion "29.0.3"
defaultConfig {
applicationId "net.taler.wallet"
minSdkVersion 21
diff --git a/app/src/main/java/net/taler/wallet/MainActivity.kt
b/app/src/main/java/net/taler/wallet/MainActivity.kt
index 29a56da..ebc7136 100644
--- a/app/src/main/java/net/taler/wallet/MainActivity.kt
+++ b/app/src/main/java/net/taler/wallet/MainActivity.kt
@@ -19,16 +19,16 @@ package net.taler.wallet
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
+import android.content.Intent.ACTION_VIEW
import android.content.IntentFilter
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
-import android.view.View.INVISIBLE
+import android.view.View.GONE
import android.view.View.VISIBLE
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.GravityCompat
-import androidx.drawerlayout.widget.DrawerLayout
+import androidx.core.view.GravityCompat.START
import androidx.lifecycle.Observer
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
@@ -38,9 +38,13 @@ import
com.google.android.material.navigation.NavigationView.OnNavigationItemSel
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.snackbar.Snackbar.LENGTH_SHORT
import com.google.zxing.integration.android.IntentIntegrator
-import com.google.zxing.integration.android.IntentResult
+import
com.google.zxing.integration.android.IntentIntegrator.parseActivityResult
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.app_bar_main.*
+import net.taler.wallet.HostCardEmulatorService.Companion.HTTP_TUNNEL_RESPONSE
+import
net.taler.wallet.HostCardEmulatorService.Companion.MERCHANT_NFC_CONNECTED
+import
net.taler.wallet.HostCardEmulatorService.Companion.MERCHANT_NFC_DISCONNECTED
+import
net.taler.wallet.HostCardEmulatorService.Companion.TRIGGER_PAYMENT_ACTION
import java.util.Locale.ROOT
class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener,
@@ -54,13 +58,6 @@ class MainActivity : AppCompatActivity(),
OnNavigationItemSelectedListener,
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
- fab.setOnClickListener {
- val integrator = IntentIntegrator(this)
- integrator.setPrompt("Place merchant's QR Code inside the
viewfinder rectangle to initiate payment.")
- integrator.initiateScan(listOf("QR_CODE"))
- }
- fab.hide()
-
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as
NavHostFragment
nav = navHostFragment.navController
@@ -76,106 +73,52 @@ class MainActivity : AppCompatActivity(),
OnNavigationItemSelectedListener,
)
toolbar.setupWithNavController(nav, appBarConfiguration)
- model.init()
- model.getBalances()
-
model.showProgressBar.observe(this, Observer { show ->
- progress_bar.visibility = if (show) VISIBLE else INVISIBLE
+ progress_bar.visibility = if (show) VISIBLE else GONE
})
- val triggerPaymentFilter =
IntentFilter(HostCardEmulatorService.TRIGGER_PAYMENT_ACTION)
- registerReceiver(object : BroadcastReceiver() {
- override fun onReceive(p0: Context?, p1: Intent?) {
-
- if (nav.currentDestination?.id == R.id.promptPayment) {
- return
- }
-
- val url = p1!!.extras!!.get("contractUrl") as String
-
- nav.navigate(R.id.action_global_promptPayment)
- model.paymentManager.preparePay(url)
-
- }
- }, triggerPaymentFilter)
-
- val nfcConnectedFilter =
IntentFilter(HostCardEmulatorService.MERCHANT_NFC_CONNECTED)
- registerReceiver(object : BroadcastReceiver() {
- override fun onReceive(p0: Context?, p1: Intent?) {
- Log.v(TAG, "got MERCHANT_NFC_CONNECTED")
- //model.startTunnel()
- }
- }, nfcConnectedFilter)
-
- val nfcDisconnectedFilter =
IntentFilter(HostCardEmulatorService.MERCHANT_NFC_DISCONNECTED)
- registerReceiver(object : BroadcastReceiver() {
- override fun onReceive(p0: Context?, p1: Intent?) {
- Log.v(TAG, "got MERCHANT_NFC_DISCONNECTED")
- //model.stopTunnel()
- }
- }, nfcDisconnectedFilter)
-
- IntentFilter(HostCardEmulatorService.HTTP_TUNNEL_RESPONSE).also {
filter ->
- registerReceiver(object : BroadcastReceiver() {
- override fun onReceive(p0: Context?, p1: Intent?) {
- Log.v("taler-tunnel", "got HTTP_TUNNEL_RESPONSE")
- model.tunnelResponse(p1!!.getStringExtra("response"))
- }
- }, filter)
- }
-
- if (intent.action == Intent.ACTION_VIEW) {
- val uri = intent.dataString
- if (uri != null)
- handleTalerUri(uri, "intent")
+ if (intent.action == ACTION_VIEW) intent.dataString?.let { uri ->
+ handleTalerUri(uri, "intent")
}
//model.startTunnel()
+
+ registerReceiver(triggerPaymentReceiver,
IntentFilter(TRIGGER_PAYMENT_ACTION))
+ registerReceiver(nfcConnectedReceiver,
IntentFilter(MERCHANT_NFC_CONNECTED))
+ registerReceiver(nfcDisconnectedReceiver,
IntentFilter(MERCHANT_NFC_DISCONNECTED))
+ registerReceiver(tunnelResponseReceiver,
IntentFilter(HTTP_TUNNEL_RESPONSE))
}
override fun onBackPressed() {
- val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
- if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
- drawerLayout.closeDrawer(GravityCompat.START)
- } else {
- super.onBackPressed()
- }
+ if (drawer_layout.isDrawerOpen(START)) drawer_layout.closeDrawer(START)
+ else super.onBackPressed()
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
- // Handle navigation view item clicks here.
when (item.itemId) {
- R.id.nav_home -> {
- nav.navigate(R.id.showBalance)
- }
- R.id.nav_settings -> {
- nav.navigate(R.id.settings)
- }
- R.id.nav_history -> {
- nav.navigate(R.id.walletHistory)
- }
+ R.id.nav_home -> nav.navigate(R.id.showBalance)
+ R.id.nav_settings -> nav.navigate(R.id.settings)
+ R.id.nav_history -> nav.navigate(R.id.walletHistory)
}
- val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
- drawerLayout.closeDrawer(GravityCompat.START)
+ drawer_layout.closeDrawer(START)
return true
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data:
Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- if (requestCode != IntentIntegrator.REQUEST_CODE) {
- return
- }
-
- val scanResult: IntentResult? =
- IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
-
- if (scanResult == null || scanResult.contents == null) {
- Snackbar.make(nav_view, "QR Code scan canceled.",
LENGTH_SHORT).show()
- return
+ if (requestCode == IntentIntegrator.REQUEST_CODE) {
+ parseActivityResult(requestCode, resultCode, data)?.contents?.let
{ contents ->
+ handleTalerUri(contents, "QR code")
+ }
}
+ }
- val url = scanResult.contents!!
- handleTalerUri(url, "QR code")
+ override fun onDestroy() {
+ unregisterReceiver(triggerPaymentReceiver)
+ unregisterReceiver(nfcConnectedReceiver)
+ unregisterReceiver(nfcDisconnectedReceiver)
+ unregisterReceiver(tunnelResponseReceiver)
+ super.onDestroy()
}
private fun handleTalerUri(url: String, from: String) {
@@ -188,7 +131,7 @@ class MainActivity : AppCompatActivity(),
OnNavigationItemSelectedListener,
url.toLowerCase(ROOT).startsWith("taler://withdraw/") -> {
Log.v(TAG, "navigating!")
nav.navigate(R.id.action_showBalance_to_promptWithdraw)
- model.getWithdrawalInfo(url)
+ model.withdrawManager.getWithdrawalInfo(url)
}
url.toLowerCase(ROOT).startsWith("taler://refund/") -> {
// TODO implement refunds
@@ -204,6 +147,39 @@ class MainActivity : AppCompatActivity(),
OnNavigationItemSelectedListener,
}
}
+ private val triggerPaymentReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (nav.currentDestination?.id == R.id.promptPayment) return
+ intent.extras?.getString("contractUrl")?.let { url ->
+ nav.navigate(R.id.action_global_promptPayment)
+ model.paymentManager.preparePay(url)
+ }
+ }
+ }
+
+ private val nfcConnectedReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ Log.v(TAG, "got MERCHANT_NFC_CONNECTED")
+ //model.startTunnel()
+ }
+ }
+
+ private val nfcDisconnectedReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ Log.v(TAG, "got MERCHANT_NFC_DISCONNECTED")
+ //model.stopTunnel()
+ }
+ }
+
+ private val tunnelResponseReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ Log.v("taler-tunnel", "got HTTP_TUNNEL_RESPONSE")
+ intent.getStringExtra("response")?.let {
+ model.tunnelResponse(it)
+ }
+ }
+ }
+
override fun onResetConfirmed() {
model.dangerouslyReset()
Snackbar.make(nav_view, "Wallet has been reset", LENGTH_SHORT).show()
diff --git a/app/src/main/java/net/taler/wallet/PromptWithdraw.kt
b/app/src/main/java/net/taler/wallet/PromptWithdraw.kt
deleted file mode 100644
index ec65b0e..0000000
--- a/app/src/main/java/net/taler/wallet/PromptWithdraw.kt
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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
-
-import android.annotation.SuppressLint
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Button
-import android.widget.TextView
-import androidx.lifecycle.Observer
-import androidx.lifecycle.ViewModelProviders
-import androidx.navigation.findNavController
-import com.google.android.material.snackbar.Snackbar
-import me.zhanghai.android.materialprogressbar.MaterialProgressBar
-
-
-class PromptWithdraw : Fragment() {
-
- private lateinit var model: WalletViewModel
-
- private fun triggerLoading() {
- val loading =
- model.withdrawStatus.value is WithdrawStatus.Loading ||
model.withdrawStatus.value is WithdrawStatus.Withdrawing
- val myActivity = activity!!
- val progressBar =
myActivity.findViewById<MaterialProgressBar>(R.id.progress_bar)
- if (loading) {
- progressBar.visibility = View.VISIBLE
- } else {
- progressBar.visibility = View.INVISIBLE
- }
- }
-
- private fun showWithdrawStatus(view: View, status: WithdrawStatus) {
- val confirmButton =
view.findViewById<Button>(R.id.button_confirm_withdraw)
- val promptWithdraw = view.findViewById<View>(R.id.prompt_withdraw)
- when (status) {
- is WithdrawStatus.ReceivedDetails -> {
- promptWithdraw.visibility = View.VISIBLE
- confirmButton.isEnabled = true
- val promptWithdraw =
view.findViewById<View>(R.id.prompt_withdraw)
- promptWithdraw.visibility = View.VISIBLE
- val amountView =
view.findViewById<TextView>(R.id.withdraw_amount)
- val exchangeView =
view.findViewById<TextView>(R.id.withdraw_exchange)
- exchangeView.text = status.suggestedExchange
- @SuppressLint("SetTextI18n")
- amountView.text = "${status.amount.amount}
${status.amount.currency}"
- }
- is WithdrawStatus.Success -> {
- this.model.withdrawStatus.value = WithdrawStatus.None()
- activity!!.findNavController(R.id.nav_host_fragment)
- .navigate(R.id.action_promptWithdraw_to_withdrawSuccessful)
- }
- is WithdrawStatus.Loading -> {
- promptWithdraw.visibility = View.INVISIBLE
- // Wait
- }
- is WithdrawStatus.Withdrawing -> {
- confirmButton.isEnabled = false
-
- }
- is WithdrawStatus.None -> {
-
- }
- is WithdrawStatus.TermsOfServiceReviewRequired -> {
- val navController =
requireActivity().findNavController(R.id.nav_host_fragment)
-
navController.navigate(R.id.action_promptWithdraw_to_reviewExchangeTOS)
- }
- else -> {
- val bar = Snackbar.make(view, "Bug: Unexpected result",
Snackbar.LENGTH_SHORT)
- bar.show()
- }
- }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- model = activity?.run {
- ViewModelProviders.of(this)[WalletViewModel::class.java]
- } ?: throw Exception("Invalid Activity")
- }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- val view = inflater.inflate(R.layout.fragment_prompt_withdraw,
container, false)
-
- this.model.withdrawStatus.observe(this, Observer {
- triggerLoading()
- showWithdrawStatus(view, it)
- })
-
-
view.findViewById<Button>(R.id.button_cancel_withdraw).setOnClickListener {
- val navController =
requireActivity().findNavController(R.id.nav_host_fragment)
- model.cancelCurrentWithdraw()
- navController.navigateUp()
- }
-
-
view.findViewById<Button>(R.id.button_confirm_withdraw).setOnClickListener {
- val status = this.model.withdrawStatus.value
- if (status !is WithdrawStatus.ReceivedDetails) {
- return@setOnClickListener
- }
- model.acceptWithdrawal(status.talerWithdrawUri,
status.suggestedExchange)
- }
-
- return view
- }
-}
diff --git a/app/src/main/java/net/taler/wallet/ReviewExchangeTOS.kt
b/app/src/main/java/net/taler/wallet/ReviewExchangeTOS.kt
deleted file mode 100644
index 4f5db9e..0000000
--- a/app/src/main/java/net/taler/wallet/ReviewExchangeTOS.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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
-
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Button
-import android.widget.CheckBox
-import android.widget.TextView
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.Observer
-import androidx.lifecycle.ViewModelProviders
-import androidx.navigation.findNavController
-
-/**
- * A simple [Fragment] subclass.
- */
-class ReviewExchangeTOS : Fragment() {
-
- private lateinit var acceptButton: Button
- private lateinit var model: WalletViewModel
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- model = activity?.run {
- ViewModelProviders.of(this)[WalletViewModel::class.java]
- } ?: throw Exception("Invalid Activity")
- }
-
- private fun onAcceptCheck(checked: Boolean) {
- acceptButton.isEnabled = checked
- }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- // Inflate the layout for this fragment
- val view = inflater.inflate(R.layout.fragment_review_exchange_tos,
container, false)
- val navController =
requireActivity().findNavController(R.id.nav_host_fragment)
- view.findViewById<Button>(R.id.button_tos_abort).setOnClickListener {
- model.cancelCurrentWithdraw()
- navController.navigateUp()
- }
- acceptButton = view.findViewById(R.id.button_tos_accept)
- acceptButton.setOnClickListener {
- model.acceptCurrentTermsOfService()
- }
- val checkbox = view.findViewById<CheckBox>(R.id.checkBox_accept_tos)
- checkbox.isChecked = false
- checkbox.setOnCheckedChangeListener { buttonView, isChecked ->
- onAcceptCheck(isChecked)
- }
- onAcceptCheck(false)
- val tosTextField = view.findViewById<TextView>(R.id.text_tos)
- model.withdrawStatus.observe(this, Observer {
- when (it) {
- is WithdrawStatus.TermsOfServiceReviewRequired -> {
- tosTextField.text = it.tosText
- }
- is WithdrawStatus.Loading -> {
-
navController.navigate(R.id.action_reviewExchangeTOS_to_promptWithdraw)
- }
- is WithdrawStatus.ReceivedDetails -> {
-
navController.navigate(R.id.action_reviewExchangeTOS_to_promptWithdraw)
- }
- else -> {
- }
- }
- })
- return view
- }
-}
diff --git a/app/src/main/java/net/taler/wallet/ShowBalance.kt
b/app/src/main/java/net/taler/wallet/ShowBalance.kt
index 1238903..4b52426 100644
--- a/app/src/main/java/net/taler/wallet/ShowBalance.kt
+++ b/app/src/main/java/net/taler/wallet/ShowBalance.kt
@@ -16,7 +16,6 @@
package net.taler.wallet
-
import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
@@ -25,20 +24,21 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
-import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import com.google.zxing.integration.android.IntentIntegrator
import com.google.zxing.integration.android.IntentIntegrator.QR_CODE_TYPES
-import me.zhanghai.android.materialprogressbar.MaterialProgressBar
import org.json.JSONObject
class WalletBalanceAdapter(private var myDataset: WalletBalances) :
@@ -70,9 +70,9 @@ class WalletBalanceAdapter(private var myDataset:
WalletBalances) :
val amountIncomingView =
holder.rowView.findViewById<TextView>(R.id.balance_pending)
if (amountIncoming.isZero()) {
- amountIncomingRow.visibility = View.GONE
+ amountIncomingRow.visibility = GONE
} else {
- amountIncomingRow.visibility = View.VISIBLE
+ amountIncomingRow.visibility = VISIBLE
@SuppressLint("SetTextI18n")
amountIncomingView.text = "${amountIncoming.amount}
${amountIncoming.currency}"
}
@@ -120,7 +120,7 @@ class PendingOperationsAdapter(private var myDataset:
PendingOperations) :
"proposal-choice" -> {
val btn1 =
holder.rowView.findViewById<TextView>(R.id.button_pending_action_1)
btn1.text =
btn1.context.getString(R.string.pending_operations_refuse)
- btn1.visibility = View.VISIBLE
+ btn1.visibility = VISIBLE
btn1.setOnClickListener {
this.listener?.onPendingOperationActionClick(p.type,
p.detail)
}
@@ -128,7 +128,7 @@ class PendingOperationsAdapter(private var myDataset:
PendingOperations) :
else -> {
val btn1 =
holder.rowView.findViewById<TextView>(R.id.button_pending_action_1)
btn1.text =
btn1.context.getString(R.string.pending_operations_no_action)
- btn1.visibility = View.GONE
+ btn1.visibility = GONE
btn1.setOnClickListener {}
}
}
@@ -151,94 +151,21 @@ interface PendingOperationClickListener {
fun onPendingOperationActionClick(type: String, detail: JSONObject)
}
-/**
- * A simple [Fragment] subclass.
- *
- */
class ShowBalance : Fragment(), PendingOperationClickListener {
+ private val model: WalletViewModel by activityViewModels()
+ private val withdrawManager by lazy { model.withdrawManager }
+
private lateinit var pendingOperationsLabel: View
private lateinit var balancesView: RecyclerView
private lateinit var balancesPlaceholderView: TextView
- private lateinit var model: WalletViewModel
private lateinit var balancesAdapter: WalletBalanceAdapter
private lateinit var pendingAdapter: PendingOperationsAdapter
- private fun triggerLoading() {
- val loading: Boolean =
- (model.testWithdrawalInProgress.value == true) ||
(model.balances.value == null) || !model.balances.value!!.initialized
-
- val myActivity = activity!!
- val progressBar =
myActivity.findViewById<MaterialProgressBar>(R.id.progress_bar)
- if (loading) {
- progressBar.visibility = View.VISIBLE
- } else {
- progressBar.visibility = View.INVISIBLE
- }
- }
-
- override fun onResume() {
- super.onResume()
- triggerLoading()
- Log.v("taler-wallet", "called onResume on ShowBalance")
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return when (item.itemId) {
- R.id.retry_pending -> {
- model.retryPendingNow()
- true
- }
- R.id.reload_balance -> {
- triggerLoading()
- model.balances.value = WalletBalances(false, listOf())
- model.getBalances()
- true
- }
- else -> super.onOptionsItemSelected(item)
- }
- }
-
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- inflater.inflate(R.menu.balance, menu)
- Log.e("TEST", "MENU INFLATED!!! ${menu.size()}")
- super.onCreateOptionsMenu(menu, inflater)
- }
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
-
- model = activity?.run {
- ViewModelProvider(this)[WalletViewModel::class.java]
- } ?: throw Exception("Invalid Activity")
-
- }
-
-
- private fun updateBalances(balances: WalletBalances) {
- if (!balances.initialized) {
- balancesPlaceholderView.visibility = View.GONE
- balancesView.visibility = View.GONE
- } else if (balances.byCurrency.isEmpty()) {
- balancesPlaceholderView.visibility = View.VISIBLE
- balancesView.visibility = View.GONE
- } else {
- balancesPlaceholderView.visibility = View.GONE
- balancesView.visibility = View.VISIBLE
- }
- Log.v(TAG, "updating balances $balances")
- balancesAdapter.update(balances)
- }
-
- private fun updatePending(pendingOperations: PendingOperations) {
- if (pendingOperations.pending.isEmpty()) {
- pendingOperationsLabel.visibility = View.GONE
- } else {
- pendingOperationsLabel.visibility = View.VISIBLE
- }
- pendingAdapter.update(pendingOperations)
}
override fun onCreateView(
@@ -280,10 +207,10 @@ class ShowBalance : Fragment(),
PendingOperationClickListener {
val withdrawTestkudosButton =
view.findViewById<Button>(R.id.button_withdraw_testkudos)
withdrawTestkudosButton.setOnClickListener {
- model.withdrawTestkudos()
+ withdrawManager.withdrawTestkudos()
}
- model.testWithdrawalInProgress.observe(viewLifecycleOwner, Observer {
loading ->
+ withdrawManager.testWithdrawalInProgress.observe(viewLifecycleOwner,
Observer { loading ->
Log.v("taler-wallet", "observing balance loading $loading in show
balance")
withdrawTestkudosButton.isEnabled = !loading
triggerLoading()
@@ -309,6 +236,64 @@ class ShowBalance : Fragment(),
PendingOperationClickListener {
return view
}
+ override fun onResume() {
+ super.onResume()
+ triggerLoading()
+ Log.v("taler-wallet", "called onResume on ShowBalance")
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return when (item.itemId) {
+ R.id.retry_pending -> {
+ model.retryPendingNow()
+ true
+ }
+ R.id.reload_balance -> {
+ triggerLoading()
+ model.balances.value = WalletBalances(false, listOf())
+ model.getBalances()
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ inflater.inflate(R.menu.balance, menu)
+ super.onCreateOptionsMenu(menu, inflater)
+ }
+
+ private fun triggerLoading() {
+ val withdrawInProgress =
withdrawManager.testWithdrawalInProgress.value == true
+ val balances = model.balances.value
+ val loading: Boolean = (withdrawInProgress) || (balances == null) ||
!balances.initialized
+ model.showProgressBar.value = loading
+ }
+
+ private fun updateBalances(balances: WalletBalances) {
+ if (!balances.initialized) {
+ balancesPlaceholderView.visibility = GONE
+ balancesView.visibility = GONE
+ } else if (balances.byCurrency.isEmpty()) {
+ balancesPlaceholderView.visibility = VISIBLE
+ balancesView.visibility = GONE
+ } else {
+ balancesPlaceholderView.visibility = GONE
+ balancesView.visibility = VISIBLE
+ }
+ Log.v(TAG, "updating balances $balances")
+ balancesAdapter.update(balances)
+ }
+
+ private fun updatePending(pendingOperations: PendingOperations) {
+ if (pendingOperations.pending.isEmpty()) {
+ pendingOperationsLabel.visibility = GONE
+ } else {
+ pendingOperationsLabel.visibility = VISIBLE
+ }
+ pendingAdapter.update(pendingOperations)
+ }
+
override fun onPendingOperationClick(type: String, detail: JSONObject) {
val v = view ?: return
when {
diff --git a/app/src/main/java/net/taler/wallet/Utils.kt
b/app/src/main/java/net/taler/wallet/Utils.kt
index 673fa2b..fb0b3ae 100644
--- a/app/src/main/java/net/taler/wallet/Utils.kt
+++ b/app/src/main/java/net/taler/wallet/Utils.kt
@@ -20,16 +20,21 @@ import android.view.View
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
-fun View.fadeIn() {
+fun View.fadeIn(endAction: () -> Unit = {}) {
+ if (visibility == VISIBLE) return
alpha = 0f
visibility = VISIBLE
- animate().alpha(1f).start()
+ animate().alpha(1f).withEndAction {
+ if (context != null) endAction.invoke()
+ }.start()
}
-fun View.fadeOut() {
+fun View.fadeOut(endAction: () -> Unit = {}) {
if (visibility == INVISIBLE) return
animate().alpha(0f).withEndAction {
+ if (context == null) return@withEndAction
visibility = INVISIBLE
alpha = 1f
+ endAction.invoke()
}.start()
}
diff --git a/app/src/main/java/net/taler/wallet/WalletViewModel.kt
b/app/src/main/java/net/taler/wallet/WalletViewModel.kt
index 2942805..d9e730d 100644
--- a/app/src/main/java/net/taler/wallet/WalletViewModel.kt
+++ b/app/src/main/java/net/taler/wallet/WalletViewModel.kt
@@ -18,6 +18,7 @@ package net.taler.wallet
import android.app.Application
import android.util.Log
+import androidx.annotation.UiThread
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
@@ -36,6 +37,7 @@ import net.taler.wallet.backend.WalletBackendApi
import net.taler.wallet.history.History
import net.taler.wallet.history.HistoryEvent
import net.taler.wallet.payment.PaymentManager
+import net.taler.wallet.withdraw.WithdrawManager
import org.json.JSONObject
const val TAG = "taler-wallet"
@@ -46,26 +48,6 @@ data class BalanceEntry(val available: Amount, val
pendingIncoming: Amount)
data class WalletBalances(val initialized: Boolean, val byCurrency:
List<BalanceEntry>)
-open class WithdrawStatus {
- class None : WithdrawStatus()
- data class Loading(val talerWithdrawUri: String) : WithdrawStatus()
- data class TermsOfServiceReviewRequired(
- val talerWithdrawUri: String,
- val exchangeBaseUrl: String,
- val tosText: String,
- val tosEtag: String
- ) : WithdrawStatus()
-
- class Success : WithdrawStatus()
- data class ReceivedDetails(
- val talerWithdrawUri: String,
- val amount: Amount,
- val suggestedExchange: String
- ) : WithdrawStatus()
-
- data class Withdrawing(val talerWithdrawUri: String) : WithdrawStatus()
-}
-
open class PendingOperationInfo(
val type: String,
val detail: JSONObject
@@ -78,20 +60,11 @@ open class PendingOperations(
@Suppress("EXPERIMENTAL_API_USAGE")
class WalletViewModel(val app: Application) : AndroidViewModel(app) {
- private var initialized = false
-
- val testWithdrawalInProgress = MutableLiveData<Boolean>().apply {
- value = false
- }
val balances = MutableLiveData<WalletBalances>().apply {
value = WalletBalances(false, listOf())
}
- val withdrawStatus = MutableLiveData<WithdrawStatus>().apply {
- value = WithdrawStatus.None()
- }
-
val pendingOperations = MutableLiveData<PendingOperations>().apply {
value = PendingOperations(listOf())
}
@@ -113,24 +86,16 @@ class WalletViewModel(val app: Application) :
AndroidViewModel(app) {
private var activeGetBalance = 0
private var activeGetPending = 0
- private var currentWithdrawRequestId = 0
-
private val walletBackendApi = WalletBackendApi(app)
private val mapper = ObjectMapper()
.registerModule(KotlinModule())
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
+ val withdrawManager = WithdrawManager(walletBackendApi)
val paymentManager = PaymentManager(walletBackendApi, mapper)
- fun init() {
- if (initialized) {
- Log.e(TAG, "WalletViewModel already initialized")
- return
- }
-
- this.initialized = true
-
+ init {
getBalances()
getPending()
@@ -147,7 +112,6 @@ class WalletViewModel(val app: Application) :
AndroidViewModel(app) {
}
}
-
fun getBalances() {
if (activeGetBalance > 0) {
return
@@ -221,17 +185,10 @@ class WalletViewModel(val app: Application) :
AndroidViewModel(app) {
awaitClose()
}
- fun withdrawTestkudos() {
- testWithdrawalInProgress.value = true
-
- walletBackendApi.sendRequest("withdrawTestkudos", null) { _, _ ->
- testWithdrawalInProgress.postValue(false)
- }
- }
-
+ @UiThread
fun dangerouslyReset() {
walletBackendApi.sendRequest("reset", null)
- testWithdrawalInProgress.value = false
+ withdrawManager.testWithdrawalInProgress.value = false
balances.value = WalletBalances(false, listOf())
}
@@ -248,113 +205,6 @@ class WalletViewModel(val app: Application) :
AndroidViewModel(app) {
walletBackendApi.sendRequest("tunnelResponse", respJson)
}
- fun getWithdrawalInfo(talerWithdrawUri: String) {
- val args = JSONObject()
- args.put("talerWithdrawUri", talerWithdrawUri)
-
- withdrawStatus.value = WithdrawStatus.Loading(talerWithdrawUri)
-
- this.currentWithdrawRequestId++
- val myWithdrawRequestId = this.currentWithdrawRequestId
-
- walletBackendApi.sendRequest("getWithdrawDetailsForUri", args) {
isError, result ->
- if (isError) {
- Log.e(TAG, "Error getWithdrawDetailsForUri
${result.toString(4)}")
- return@sendRequest
- }
- if (myWithdrawRequestId != this.currentWithdrawRequestId) {
- val mismatch = "$myWithdrawRequestId !=
${this.currentWithdrawRequestId}"
- Log.w(TAG, "Got withdraw result for different request id
$mismatch")
- return@sendRequest
- }
- Log.v(TAG, "got getWithdrawDetailsForUri result")
- val status = withdrawStatus.value
- if (status !is WithdrawStatus.Loading) {
- Log.v(TAG, "ignoring withdrawal info result, not loading.")
- return@sendRequest
- }
- val wi = result.getJSONObject("bankWithdrawDetails")
- val suggestedExchange = wi.getString("suggestedExchange")
- // We just use the suggested exchange, in the future there will be
- // a selection dialog.
- getWithdrawalInfoWithExchange(talerWithdrawUri, suggestedExchange)
- }
- }
-
- private fun getWithdrawalInfoWithExchange(talerWithdrawUri: String,
selectedExchange: String) {
- val args = JSONObject()
- args.put("talerWithdrawUri", talerWithdrawUri)
- args.put("selectedExchange", selectedExchange)
-
- this.currentWithdrawRequestId++
- val myWithdrawRequestId = this.currentWithdrawRequestId
-
- walletBackendApi.sendRequest("getWithdrawDetailsForUri", args) {
isError, result ->
- if (isError) {
- Log.e(TAG, "Error getWithdrawDetailsForUri
${result.toString(4)}")
- return@sendRequest
- }
- if (myWithdrawRequestId != this.currentWithdrawRequestId) {
- val mismatch = "$myWithdrawRequestId !=
${this.currentWithdrawRequestId}"
- Log.w(TAG, "Got withdraw result for different request id
$mismatch")
- return@sendRequest
- }
- Log.v(TAG, "got getWithdrawDetailsForUri result (with exchange
details)")
- val status = withdrawStatus.value
- if (status !is WithdrawStatus.Loading) {
- Log.v(TAG, "ignoring withdrawal info result, not loading.")
- return@sendRequest
- }
- val ei = result.getJSONObject("exchangeWithdrawDetails")
- val termsOfServiceAccepted =
ei.getBoolean("termsOfServiceAccepted")
- if (!termsOfServiceAccepted) {
- val exchange = ei.getJSONObject("exchangeInfo")
- val tosText = exchange.getString("termsOfServiceText")
- val tosEtag = exchange.optString("termsOfServiceLastEtag",
"undefined")
- withdrawStatus.postValue(
- WithdrawStatus.TermsOfServiceReviewRequired(
- status.talerWithdrawUri,
- selectedExchange,
- tosText,
- tosEtag
- )
- )
- } else {
- val wi = result.getJSONObject("bankWithdrawDetails")
- val suggestedExchange = wi.getString("suggestedExchange")
- val amount = Amount.fromJson(wi.getJSONObject("amount"))
- withdrawStatus.postValue(
- WithdrawStatus.ReceivedDetails(
- status.talerWithdrawUri,
- amount,
- suggestedExchange
- )
- )
- }
- }
- }
-
- fun acceptWithdrawal(talerWithdrawUri: String, selectedExchange: String) {
- val args = JSONObject()
- args.put("talerWithdrawUri", talerWithdrawUri)
- args.put("selectedExchange", selectedExchange)
-
- withdrawStatus.value = WithdrawStatus.Withdrawing(talerWithdrawUri)
-
- walletBackendApi.sendRequest("acceptWithdrawal", args) { isError, _ ->
- if (isError) {
- Log.v(TAG, "got acceptWithdrawal error result")
- return@sendRequest
- }
- Log.v(TAG, "got acceptWithdrawal result")
- val status = withdrawStatus.value
- if (status !is WithdrawStatus.Withdrawing) {
- Log.v(TAG, "ignoring acceptWithdrawal result, invalid state")
- }
- withdrawStatus.postValue(WithdrawStatus.Success())
- }
- }
-
fun retryPendingNow() {
walletBackendApi.sendRequest("retryPendingNow", null)
}
@@ -363,29 +213,4 @@ class WalletViewModel(val app: Application) :
AndroidViewModel(app) {
walletBackendApi.destroy()
super.onCleared()
}
-
- /**
- * Accept the currently displayed terms of service.
- */
- fun acceptCurrentTermsOfService() {
- when (val s = withdrawStatus.value) {
- is WithdrawStatus.TermsOfServiceReviewRequired -> {
- val args = JSONObject()
- args.put("exchangeBaseUrl", s.exchangeBaseUrl)
- args.put("etag", s.tosEtag)
- walletBackendApi.sendRequest("acceptExchangeTermsOfService",
args) { isError, _ ->
- if (isError) {
- return@sendRequest
- }
- // Try withdrawing again with accepted ToS
- getWithdrawalInfo(s.talerWithdrawUri)
- }
- }
- }
- }
-
- fun cancelCurrentWithdraw() {
- currentWithdrawRequestId++
- withdrawStatus.value = WithdrawStatus.None()
- }
}
diff --git
a/app/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
b/app/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
new file mode 100644
index 0000000..0b14e32
--- /dev/null
+++ b/app/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.withdraw
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Observer
+import androidx.navigation.fragment.findNavController
+import kotlinx.android.synthetic.main.fragment_prompt_withdraw.*
+import net.taler.wallet.R
+import net.taler.wallet.WalletViewModel
+import net.taler.wallet.fadeIn
+import net.taler.wallet.fadeOut
+import net.taler.wallet.withdraw.WithdrawStatus.Loading
+import net.taler.wallet.withdraw.WithdrawStatus.TermsOfServiceReviewRequired
+import net.taler.wallet.withdraw.WithdrawStatus.Withdrawing
+
+class PromptWithdrawFragment : Fragment() {
+
+ private val model: WalletViewModel by activityViewModels()
+ private val withdrawManager by lazy { model.withdrawManager }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_prompt_withdraw, container,
false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ button_cancel_withdraw.setOnClickListener {
+ withdrawManager.cancelCurrentWithdraw()
+ findNavController().navigateUp()
+ }
+
+ button_confirm_withdraw.setOnClickListener {
+ val status = withdrawManager.withdrawStatus.value
+ if (status !is WithdrawStatus.ReceivedDetails) throw
AssertionError()
+ it.fadeOut()
+ confirmProgressBar.fadeIn()
+ withdrawManager.acceptWithdrawal(status.talerWithdrawUri,
status.suggestedExchange)
+ }
+
+ withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer {
+ showWithdrawStatus(it)
+ })
+ }
+
+ private fun showWithdrawStatus(status: WithdrawStatus) = when (status) {
+ is WithdrawStatus.ReceivedDetails -> {
+ model.showProgressBar.value = false
+ progressBar.fadeOut()
+
+ introView.fadeIn()
+ @SuppressLint("SetTextI18n")
+ withdrawAmountView.text = "${status.amount.amount}
${status.amount.currency}"
+ withdrawAmountView.fadeIn()
+ feeView.fadeIn()
+
+ exchangeIntroView.fadeIn()
+ withdrawExchangeUrl.text = status.suggestedExchange
+ withdrawExchangeUrl.fadeIn()
+
+ button_confirm_withdraw.isEnabled = true
+ }
+ is WithdrawStatus.Success -> {
+ model.showProgressBar.value = false
+ withdrawManager.withdrawStatus.value = WithdrawStatus.None
+
findNavController().navigate(R.id.action_promptWithdraw_to_withdrawSuccessful)
+ }
+ is Loading -> {
+ model.showProgressBar.value = true
+ }
+ is Withdrawing -> {
+ model.showProgressBar.value = true
+ }
+ is TermsOfServiceReviewRequired -> {
+ model.showProgressBar.value = false
+
findNavController().navigate(R.id.action_promptWithdraw_to_reviewExchangeTOS)
+ }
+ is WithdrawStatus.None -> {
+ model.showProgressBar.value = false
+ }
+ }
+
+}
diff --git
a/app/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
b/app/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
new file mode 100644
index 0000000..cd01a33
--- /dev/null
+++ b/app/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.withdraw
+
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Observer
+import androidx.navigation.fragment.findNavController
+import kotlinx.android.synthetic.main.fragment_review_exchange_tos.*
+import net.taler.wallet.R
+import net.taler.wallet.WalletViewModel
+import net.taler.wallet.fadeIn
+import net.taler.wallet.fadeOut
+
+class ReviewExchangeTosFragment : Fragment() {
+
+ private val model: WalletViewModel by activityViewModels()
+ private val withdrawManager by lazy { model.withdrawManager }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_review_exchange_tos,
container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ acceptTosCheckBox.isChecked = false
+ acceptTosCheckBox.setOnCheckedChangeListener { _, isChecked ->
+ acceptTosButton.isEnabled = isChecked
+ }
+ abortTosButton.setOnClickListener {
+ withdrawManager.cancelCurrentWithdraw()
+ findNavController().navigateUp()
+ }
+ acceptTosButton.setOnClickListener {
+ withdrawManager.acceptCurrentTermsOfService()
+ }
+ withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer {
+ when (it) {
+ is WithdrawStatus.TermsOfServiceReviewRequired -> {
+ tosTextView.text = it.tosText
+ tosTextView.fadeIn()
+ acceptTosCheckBox.fadeIn()
+ progressBar.fadeOut()
+ }
+ is WithdrawStatus.Loading -> {
+
findNavController().navigate(R.id.action_reviewExchangeTOS_to_promptWithdraw)
+ }
+ is WithdrawStatus.ReceivedDetails -> {
+
findNavController().navigate(R.id.action_reviewExchangeTOS_to_promptWithdraw)
+ }
+ else -> {
+ }
+ }
+ })
+ }
+
+}
diff --git a/app/src/main/java/net/taler/wallet/WalletViewModel.kt
b/app/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
similarity index 50%
copy from app/src/main/java/net/taler/wallet/WalletViewModel.kt
copy to app/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
index 2942805..fa20318 100644
--- a/app/src/main/java/net/taler/wallet/WalletViewModel.kt
+++ b/app/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
@@ -14,40 +14,17 @@
* GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-package net.taler.wallet
+package net.taler.wallet.withdraw
-import android.app.Application
import android.util.Log
-import androidx.lifecycle.AndroidViewModel
-import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.asLiveData
-import androidx.lifecycle.switchMap
-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 kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.onCompletion
-import kotlinx.coroutines.flow.onStart
+import net.taler.wallet.Amount
+import net.taler.wallet.TAG
import net.taler.wallet.backend.WalletBackendApi
-import net.taler.wallet.history.History
-import net.taler.wallet.history.HistoryEvent
-import net.taler.wallet.payment.PaymentManager
import org.json.JSONObject
-const val TAG = "taler-wallet"
-
-
-data class BalanceEntry(val available: Amount, val pendingIncoming: Amount)
-
-
-data class WalletBalances(val initialized: Boolean, val byCurrency:
List<BalanceEntry>)
-
-open class WithdrawStatus {
- class None : WithdrawStatus()
+sealed class WithdrawStatus {
+ object None : WithdrawStatus()
data class Loading(val talerWithdrawUri: String) : WithdrawStatus()
data class TermsOfServiceReviewRequired(
val talerWithdrawUri: String,
@@ -56,7 +33,7 @@ open class WithdrawStatus {
val tosEtag: String
) : WithdrawStatus()
- class Success : WithdrawStatus()
+ object Success : WithdrawStatus()
data class ReceivedDetails(
val talerWithdrawUri: String,
val amount: Amount,
@@ -66,161 +43,13 @@ open class WithdrawStatus {
data class Withdrawing(val talerWithdrawUri: String) : WithdrawStatus()
}
-open class PendingOperationInfo(
- val type: String,
- val detail: JSONObject
-)
-
-open class PendingOperations(
- val pending: List<PendingOperationInfo>
-)
-
-
-@Suppress("EXPERIMENTAL_API_USAGE")
-class WalletViewModel(val app: Application) : AndroidViewModel(app) {
- private var initialized = false
-
- val testWithdrawalInProgress = MutableLiveData<Boolean>().apply {
- value = false
- }
+class WithdrawManager(private val walletBackendApi: WalletBackendApi) {
- val balances = MutableLiveData<WalletBalances>().apply {
- value = WalletBalances(false, listOf())
- }
-
- val withdrawStatus = MutableLiveData<WithdrawStatus>().apply {
- value = WithdrawStatus.None()
- }
-
- val pendingOperations = MutableLiveData<PendingOperations>().apply {
- value = PendingOperations(listOf())
- }
-
- private val mHistoryProgress = MutableLiveData<Boolean>()
- val historyProgress: LiveData<Boolean> = mHistoryProgress
-
- val historyShowAll = MutableLiveData<Boolean>()
-
- val history: LiveData<History> = historyShowAll.switchMap { showAll ->
- loadHistory(showAll)
- .onStart { mHistoryProgress.postValue(true) }
- .onCompletion { mHistoryProgress.postValue(false) }
- .asLiveData(Dispatchers.IO)
- }
-
- val showProgressBar = MutableLiveData<Boolean>()
-
- private var activeGetBalance = 0
- private var activeGetPending = 0
+ val withdrawStatus = MutableLiveData<WithdrawStatus>(WithdrawStatus.None)
+ val testWithdrawalInProgress = MutableLiveData<Boolean>(false)
private var currentWithdrawRequestId = 0
- private val walletBackendApi = WalletBackendApi(app)
-
- private val mapper = ObjectMapper()
- .registerModule(KotlinModule())
- .configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
-
- val paymentManager = PaymentManager(walletBackendApi, mapper)
-
- fun init() {
- if (initialized) {
- Log.e(TAG, "WalletViewModel already initialized")
- return
- }
-
- this.initialized = true
-
- getBalances()
- getPending()
-
- walletBackendApi.notificationHandler = {
- Log.i(TAG, "got notification from wallet")
- getBalances()
- getPending()
- }
- walletBackendApi.connectedHandler = {
- activeGetBalance = 0
- activeGetPending = 0
- getBalances()
- getPending()
- }
- }
-
-
- fun getBalances() {
- if (activeGetBalance > 0) {
- return
- }
- activeGetBalance++
- walletBackendApi.sendRequest("getBalances", null) { isError, result ->
- activeGetBalance--
- if (isError) {
- return@sendRequest
- }
- val balanceList = mutableListOf<BalanceEntry>()
- val byCurrency = result.getJSONObject("byCurrency")
- val currencyList = byCurrency.keys().asSequence().toList().sorted()
- for (currency in currencyList) {
- val jsonAmount = byCurrency.getJSONObject(currency)
- .getJSONObject("available")
- val amount = Amount.fromJson(jsonAmount)
- val jsonAmountIncoming = byCurrency.getJSONObject(currency)
- .getJSONObject("pendingIncoming")
- val amountIncoming = Amount.fromJson(jsonAmountIncoming)
- balanceList.add(BalanceEntry(amount, amountIncoming))
- }
- balances.postValue(WalletBalances(true, balanceList))
- }
- }
-
- private fun getPending() {
- if (activeGetPending > 0) {
- return
- }
- activeGetPending++
- walletBackendApi.sendRequest("getPendingOperations", null) { isError,
result ->
- activeGetPending--
- if (isError) {
- Log.i(TAG, "got getPending error result")
- return@sendRequest
- }
- Log.i(TAG, "got getPending result")
- val pendingList = mutableListOf<PendingOperationInfo>()
- val pendingJson = result.getJSONArray("pendingOperations")
- for (i in 0 until pendingJson.length()) {
- val p = pendingJson.getJSONObject(i)
- val type = p.getString("type")
- pendingList.add(PendingOperationInfo(type, p))
- }
- Log.i(TAG, "Got ${pendingList.size} pending operations")
- pendingOperations.postValue(PendingOperations((pendingList)))
- }
- }
-
- private fun loadHistory(showAll: Boolean) = callbackFlow {
- mHistoryProgress.postValue(true)
- walletBackendApi.sendRequest("getHistory", null) { isError, result ->
- if (isError) {
- // TODO show error message in [WalletHistory] fragment
- close()
- return@sendRequest
- }
- val history = History()
- val json = result.getJSONArray("history")
- for (i in 0 until json.length()) {
- val event: HistoryEvent = mapper.readValue(json.getString(i))
- event.json = json.getJSONObject(i)
- history.add(event)
- }
- history.reverse() // show latest first
- mHistoryProgress.postValue(false)
- offer(if (showAll) history else history.filter { it.showToUser }
as History)
- close()
- }
- awaitClose()
- }
-
fun withdrawTestkudos() {
testWithdrawalInProgress.value = true
@@ -229,25 +58,6 @@ class WalletViewModel(val app: Application) :
AndroidViewModel(app) {
}
}
- fun dangerouslyReset() {
- walletBackendApi.sendRequest("reset", null)
- testWithdrawalInProgress.value = false
- balances.value = WalletBalances(false, listOf())
- }
-
- fun startTunnel() {
- walletBackendApi.sendRequest("startTunnel", null)
- }
-
- fun stopTunnel() {
- walletBackendApi.sendRequest("stopTunnel", null)
- }
-
- fun tunnelResponse(resp: String) {
- val respJson = JSONObject(resp)
- walletBackendApi.sendRequest("tunnelResponse", respJson)
- }
-
fun getWithdrawalInfo(talerWithdrawUri: String) {
val args = JSONObject()
args.put("talerWithdrawUri", talerWithdrawUri)
@@ -351,19 +161,10 @@ class WalletViewModel(val app: Application) :
AndroidViewModel(app) {
if (status !is WithdrawStatus.Withdrawing) {
Log.v(TAG, "ignoring acceptWithdrawal result, invalid state")
}
- withdrawStatus.postValue(WithdrawStatus.Success())
+ withdrawStatus.postValue(WithdrawStatus.Success)
}
}
- fun retryPendingNow() {
- walletBackendApi.sendRequest("retryPendingNow", null)
- }
-
- override fun onCleared() {
- walletBackendApi.destroy()
- super.onCleared()
- }
-
/**
* Accept the currently displayed terms of service.
*/
@@ -386,6 +187,7 @@ class WalletViewModel(val app: Application) :
AndroidViewModel(app) {
fun cancelCurrentWithdraw() {
currentWithdrawRequestId++
- withdrawStatus.value = WithdrawStatus.None()
+ withdrawStatus.value = WithdrawStatus.None
}
+
}
diff --git a/app/src/main/java/net/taler/wallet/WithdrawSuccessful.kt
b/app/src/main/java/net/taler/wallet/withdraw/WithdrawSuccessfulFragment.kt
similarity index 65%
rename from app/src/main/java/net/taler/wallet/WithdrawSuccessful.kt
rename to
app/src/main/java/net/taler/wallet/withdraw/WithdrawSuccessfulFragment.kt
index 4ff7478..5daeff1 100644
--- a/app/src/main/java/net/taler/wallet/WithdrawSuccessful.kt
+++ b/app/src/main/java/net/taler/wallet/withdraw/WithdrawSuccessfulFragment.kt
@@ -14,29 +14,31 @@
* GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-package net.taler.wallet
-
+package net.taler.wallet.withdraw
import android.os.Bundle
-import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.Button
-import androidx.navigation.findNavController
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.findNavController
+import kotlinx.android.synthetic.main.fragment_withdraw_successful.*
+import net.taler.wallet.R
+
+class WithdrawSuccessfulFragment : Fragment() {
-/**
- * A simple [Fragment] subclass.
- */
-class WithdrawSuccessful : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- val view = inflater.inflate(R.layout.fragment_withdraw_successful,
container, false)
- view.findViewById<Button>(R.id.backButton).setOnClickListener {
- activity!!.findNavController(R.id.nav_host_fragment).navigateUp()
+ return inflater.inflate(R.layout.fragment_withdraw_successful,
container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ backButton.setOnClickListener {
+ findNavController().navigateUp()
}
- return view
}
+
}
diff --git a/app/src/main/res/layout-w550dp/payment_bottom_bar.xml
b/app/src/main/res/layout-w550dp/payment_bottom_bar.xml
index f9fa32a..d9e2f59 100644
--- a/app/src/main/res/layout-w550dp/payment_bottom_bar.xml
+++ b/app/src/main/res/layout-w550dp/payment_bottom_bar.xml
@@ -18,10 +18,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bottomView"
+ style="@style/BottomCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
- app:cardCornerRadius="0dp"
- app:cardElevation="8dp"
tools:showIn="@layout/fragment_prompt_payment">
<androidx.constraintlayout.widget.ConstraintLayout
diff --git a/app/src/main/res/layout/app_bar_main.xml
b/app/src/main/res/layout/app_bar_main.xml
index f2d8571..e2fa71f 100644
--- a/app/src/main/res/layout/app_bar_main.xml
+++ b/app/src/main/res/layout/app_bar_main.xml
@@ -21,34 +21,40 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
-
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
- <RelativeLayout
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/AppTheme.Toolbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progress_bar"
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="4dp"
- android:layout_alignParentBottom="true"
android:indeterminate="true"
- android:visibility="invisible"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:mpb_progressStyle="horizontal"
app:mpb_useIntrinsicPadding="false"
tools:visibility="visible" />
- </RelativeLayout>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.AppBarLayout>
@@ -65,14 +71,4 @@
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
- <com.google.android.material.floatingactionbutton.FloatingActionButton
- android:id="@+id/fab"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|end"
- android:layout_margin="@dimen/fab_margin"
- android:scaleType="center"
- app:fabSize="normal"
- app:srcCompat="@drawable/ic_scan_qr" />
-
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout/fragment_prompt_withdraw.xml
b/app/src/main/res/layout/fragment_prompt_withdraw.xml
index dba7450..1114c17 100644
--- a/app/src/main/res/layout/fragment_prompt_withdraw.xml
+++ b/app/src/main/res/layout/fragment_prompt_withdraw.xml
@@ -14,93 +14,158 @@
~ GNU Taler; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<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:id="@+id/prompt_withdraw"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_margin="15dp"
- android:orientation="vertical"
- tools:context=".PromptWithdraw">
-
- <Space
- android:layout_width="match_parent"
- android:layout_height="15dp"
- android:layout_weight="1" />
+ tools:context=".withdraw.PromptWithdrawFragment">
<TextView
- android:id="@+id/order_summary_label"
- android:layout_width="wrap_content"
+ android:id="@+id/introView"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/withdraw_do_you_want" />
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginBottom="8dp"
+ android:gravity="center"
+ android:text="@string/withdraw_do_you_want"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toTopOf="@+id/withdrawAmountView"
+ 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/withdraw_amount"
- android:layout_width="wrap_content"
+ android:id="@+id/withdrawAmountView"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:textSize="25sp"
- tools:text="10.00 KUDOS" />
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:gravity="center"
+ android:textAppearance="@style/TextAppearance.AppCompat.Headline"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toTopOf="@+id/feeView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/introView"
+ tools:text="10.00 TESTKUDOS"
+ tools:visibility="visible" />
<TextView
- android:layout_width="wrap_content"
+ android:id="@+id/feeView"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/withdraw_fees" />
-
- <Space
- android:layout_width="match_parent"
- android:layout_height="25dp" />
-
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="16dp"
+ android:gravity="center"
+ android:text="@string/withdraw_fees"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toTopOf="@+id/exchangeIntroView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/withdrawAmountView"
+ tools:visibility="visible" />
<TextView
- android:id="@+id/order_amount_label"
- android:layout_width="wrap_content"
+ android:id="@+id/exchangeIntroView"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/withdraw_exchange" />
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="32dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginBottom="8dp"
+ android:gravity="center"
+ android:text="@string/withdraw_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/withdraw_exchange"
- android:layout_width="wrap_content"
+ android:id="@+id/withdrawExchangeUrl"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:gravity="center"
android:textSize="25sp"
- tools:text="(exchange base url)" />
-
- <Space
- android:layout_width="match_parent"
- android:layout_height="15dp"
- android:layout_weight="1" />
-
-
- <Space
- android:layout_width="match_parent"
- android:layout_height="15dp"
- android:layout_weight="1" />
-
- <LinearLayout
- android:layout_width="match_parent"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toTopOf="@+id/withdrawCard"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/exchangeIntroView"
+ tools:text="(exchange base url)"
+ tools:visibility="visible" />
+
+ <ProgressBar
+ android:id="@+id/progressBar"
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/button_cancel_withdraw"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/button_cancel" />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1" />
+ app:layout_constraintBottom_toTopOf="@+id/withdrawCard"
+ 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"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent">
- <Button
- android:id="@+id/button_confirm_withdraw"
- android:layout_width="wrap_content"
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/withdraw_button_confirm" />
- </LinearLayout>
-
-</LinearLayout>
+ android:padding="8dp">
+
+ <Button
+ android:id="@+id/button_cancel_withdraw"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:backgroundTint="@color/red"
+ android:text="@string/button_cancel"
+ app:layout_constraintBottom_toBottomOf="parent"
+
app:layout_constraintEnd_toStartOf="@+id/button_confirm_withdraw"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <Button
+ android:id="@+id/button_confirm_withdraw"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:backgroundTint="@color/green"
+ android:enabled="false"
+ android:text="@string/withdraw_button_confirm"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+
app:layout_constraintStart_toEndOf="@+id/button_cancel_withdraw" />
+
+ <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/button_confirm_withdraw"
+
app:layout_constraintEnd_toEndOf="@+id/button_confirm_withdraw"
+
app:layout_constraintStart_toStartOf="@+id/button_confirm_withdraw"
+
app:layout_constraintTop_toTopOf="@+id/button_confirm_withdraw"
+ tools:visibility="visible" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ </com.google.android.material.card.MaterialCardView>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/fragment_review_exchange_tos.xml
b/app/src/main/res/layout/fragment_review_exchange_tos.xml
index 355fe25..61a61f1 100644
--- a/app/src/main/res/layout/fragment_review_exchange_tos.xml
+++ b/app/src/main/res/layout/fragment_review_exchange_tos.xml
@@ -14,55 +14,92 @@
~ GNU Taler; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<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"
- android:layout_margin="15dp"
- android:orientation="vertical"
- tools:context=".ReviewExchangeTOS">
+ tools:context=".withdraw.ReviewExchangeTosFragment">
<ScrollView
- android:layout_width="match_parent"
+ android:id="@+id/tosScrollView"
+ android:layout_width="0dp"
android:layout_height="0dp"
- android:layout_weight="1"
- android:fillViewport="true"
- android:scrollbars="vertical">
+ app:layout_constraintBottom_toTopOf="@+id/buttonCard"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
<TextView
- android:id="@+id/text_tos"
+ android:id="@+id/tosTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- tools:text="TextView" />
+ android:padding="16dp"
+ android:visibility="invisible"
+ tools:text="@tools:sample/lorem/random"
+ tools:visibility="visible" />
+
</ScrollView>
- <CheckBox
- android:id="@+id/checkBox_accept_tos"
- android:layout_width="match_parent"
+ <ProgressBar
+ android:id="@+id/progressBar"
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/exchange_tos_accept" />
+ app:layout_constraintBottom_toBottomOf="@+id/tosScrollView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
- <LinearLayout
- android:layout_width="match_parent"
+ <com.google.android.material.card.MaterialCardView
+ android:id="@+id/buttonCard"
+ style="@style/BottomCard"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent">
- <Button
- android:id="@+id/button_tos_abort"
- android:layout_width="wrap_content"
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/button_cancel" />
+ android:padding="8dp">
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
+ <CheckBox
+ android:id="@+id/acceptTosCheckBox"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/exchange_tos_accept"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toTopOf="@+id/acceptTosButton"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ tools:visibility="visible" />
- <Button
- android:id="@+id/button_tos_accept"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/exchange_tos_button_continue" />
- </LinearLayout>
+ <Button
+ android:id="@+id/abortTosButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:backgroundTint="@color/red"
+ android:text="@string/button_cancel"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/acceptTosButton"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <Button
+ android:id="@+id/acceptTosButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:backgroundTint="@color/green"
+ android:enabled="false"
+ android:text="@string/exchange_tos_button_continue"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/abortTosButton" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ </com.google.android.material.card.MaterialCardView>
-</LinearLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/fragment_withdraw_successful.xml
b/app/src/main/res/layout/fragment_withdraw_successful.xml
index 5a48f75..d1b9c90 100644
--- a/app/src/main/res/layout/fragment_withdraw_successful.xml
+++ b/app/src/main/res/layout/fragment_withdraw_successful.xml
@@ -14,51 +14,49 @@
~ GNU Taler; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<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"
- android:layout_margin="10dp"
- android:orientation="vertical"
- tools:context=".WithdrawSuccessful">
-
- <Space
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
+ tools:context=".withdraw.WithdrawSuccessfulFragment">
<TextView
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:layout_gravity="center"
+ android:id="@+id/withdrawHeadlineView"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_margin="16dp"
+ android:gravity="center_horizontal|bottom"
android:text="@string/withdraw_accepted"
- android:textAlignment="center"
- android:textColor="@android:color/holo_green_dark"
- app:autoSizeTextType="uniform" />
+ android:textColor="@color/green"
+ app:autoSizeMaxTextSize="40sp"
+ app:autoSizeTextType="uniform"
+ app:layout_constraintBottom_toTopOf="@+id/withdrawInfoView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
<TextView
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:layout_gravity="center"
- android:text="@string/withdraw_success_info"
- android:textAlignment="center" />
-
- <Space
- android:layout_width="match_parent"
+ android:id="@+id/withdrawInfoView"
+ android:layout_width="0dp"
android:layout_height="0dp"
- android:layout_weight="1" />
-
-
- <Space
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
+ android:layout_margin="16dp"
+ android:text="@string/withdraw_success_info"
+ android:textAlignment="center"
+ app:layout_constraintBottom_toTopOf="@+id/backButton"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/withdrawHeadlineView" />
<Button
android:id="@+id/backButton"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:text="@string/button_back" />
-
-</LinearLayout>
+ android:layout_margin="16dp"
+ android:text="@string/button_back"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/withdrawInfoView" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/payment_bottom_bar.xml
b/app/src/main/res/layout/payment_bottom_bar.xml
index 5b5c9f3..8fdf0f8 100644
--- a/app/src/main/res/layout/payment_bottom_bar.xml
+++ b/app/src/main/res/layout/payment_bottom_bar.xml
@@ -17,10 +17,9 @@
<com.google.android.material.card.MaterialCardView
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"
+ style="@style/BottomCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
- app:cardCornerRadius="0dp"
- app:cardElevation="8dp"
tools:showIn="@layout/fragment_prompt_payment">
<androidx.constraintlayout.widget.ConstraintLayout
diff --git a/app/src/main/res/navigation/nav_graph.xml
b/app/src/main/res/navigation/nav_graph.xml
index 39068ec..2cc1eaa 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -67,10 +67,11 @@
android:name="net.taler.wallet.payment.AlreadyPaidFragment"
android:label="Already Paid"
tools:layout="@layout/fragment_already_paid" />
+
<fragment
android:id="@+id/promptWithdraw"
- android:name="net.taler.wallet.PromptWithdraw"
- android:label="Withdraw Digital Cash"
+ android:name="net.taler.wallet.withdraw.PromptWithdrawFragment"
+ android:label="@string/nav_prompt_withdraw"
tools:layout="@layout/fragment_prompt_withdraw">
<action
android:id="@+id/action_promptWithdraw_to_withdrawSuccessful"
@@ -81,15 +82,16 @@
app:destination="@id/reviewExchangeTOS"
app:popUpTo="@id/showBalance" />
</fragment>
+
<fragment
android:id="@+id/withdrawSuccessful"
- android:name="net.taler.wallet.WithdrawSuccessful"
+ android:name="net.taler.wallet.withdraw.WithdrawSuccessfulFragment"
android:label="Withdrawal Confirmed"
tools:layout="@layout/fragment_withdraw_successful" />
<fragment
android:id="@+id/reviewExchangeTOS"
- android:name="net.taler.wallet.ReviewExchangeTOS"
- android:label="Exchange's Terms of Service"
+ android:name="net.taler.wallet.withdraw.ReviewExchangeTosFragment"
+ android:label="@string/nav_exchange_tos"
tools:layout="@layout/fragment_review_exchange_tos">
<action
android:id="@+id/action_reviewExchangeTOS_to_promptWithdraw"
diff --git a/app/src/main/res/values/strings.xml
b/app/src/main/res/values/strings.xml
index 8307e37..19159b9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -21,6 +21,9 @@
<string name="nav_header_subtitle">Wallet</string>
<string name="nav_header_desc">Navigation header</string>
+ <string name="nav_prompt_withdraw">Withdraw Digital Cash</string>
+ <string name="nav_exchange_tos">Exchange\'s Terms of Service</string>
+
<string name="button_back">Go Back</string>
<string name="button_cancel">Cancel</string>
<string name="button_scan_qr_code">Scan Taler QR Code</string>
diff --git a/app/src/main/res/values/styles.xml
b/app/src/main/res/values/styles.xml
index 09d7a02..83f3e3a 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -38,4 +38,9 @@
<item name="android:textColor">?android:textColorPrimary</item>
</style>
+ <style name="BottomCard">
+ <item name="cardCornerRadius">0dp</item>
+ <item name="cardElevation">8dp</item>
+ </style>
+
</resources>
diff --git a/build.gradle b/build.gradle
index df21dcd..a9d913c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,20 +14,15 @@
* GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-// Top-level build file where you can add configuration options common to all
sub-projects/modules.
-
buildscript {
ext.kotlin_version = '1.3.61'
repositories {
google()
jcenter()
-
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.3'
+ classpath 'com.android.tools.build:gradle:3.6.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
}
}
diff --git a/gradle/wrapper/gradle-wrapper.properties
b/gradle/wrapper/gradle-wrapper.properties
index d432222..75a58ba 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,22 +1,6 @@
-#
-# 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/>
-#
-
-#Wed Aug 14 17:39:00 CEST 2019
+#Tue Mar 03 08:42:04 BRT 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
--
To stop receiving notification emails like this one, please contact
address@hidden.
- [taler-wallet-android] branch master updated (5f57c48 -> 30980bc),
gnunet <=