[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-cashier-terminal-android] 05/06: Add app logo and optimize UX wor
From: |
gnunet |
Subject: |
[taler-cashier-terminal-android] 05/06: Add app logo and optimize UX workflow |
Date: |
Wed, 19 Feb 2020 21:31:59 +0100 |
This is an automated email from the git hooks/post-receive script.
torsten-grote pushed a commit to branch master
in repository cashier-terminal-android.
commit 2f7eb8ad573b26e244ec17173abe98218bee39eb
Author: Torsten Grote <address@hidden>
AuthorDate: Wed Feb 19 15:33:07 2020 -0300
Add app logo and optimize UX workflow
---
app/build.gradle | 2 +-
app/src/main/ic_launcher-web.png | Bin 0 -> 30434 bytes
.../main/java/net/taler/cashier/BalanceFragment.kt | 87 ++++++++-
.../main/java/net/taler/cashier/MainViewModel.kt | 16 +-
app/src/main/java/net/taler/cashier/Utils.kt | 1 +
.../net/taler/cashier/withdraw/ErrorFragment.kt | 10 +-
.../java/net/taler/cashier/withdraw/NfcManager.kt | 17 +-
.../net/taler/cashier/withdraw/SuccessFragment.kt | 33 ----
.../taler/cashier/withdraw/TransactionFragment.kt | 50 ++++--
.../net/taler/cashier/withdraw/WithdrawFragment.kt | 79 ---------
.../net/taler/cashier/withdraw/WithdrawManager.kt | 88 +++++++---
app/src/main/res/drawable-w550dp/ic_arrow.xml | 11 ++
app/src/main/res/drawable/ic_arrow.xml | 11 ++
app/src/main/res/drawable/ic_check_circle.xml | 1 -
.../main/res/drawable/ic_launcher_foreground.xml | 13 ++
.../main/res/layout-w550dp/fragment_balance.xml | 195 +++++++++++++++++++++
.../res/layout-w550dp/fragment_transaction.xml | 21 ++-
app/src/main/res/layout/activity_main.xml | 4 +-
app/src/main/res/layout/fragment_balance.xml | 127 +++++++++++++-
app/src/main/res/layout/fragment_error.xml | 2 +-
app/src/main/res/layout/fragment_success.xml | 49 ------
app/src/main/res/layout/fragment_transaction.xml | 18 +-
app/src/main/res/layout/fragment_withdraw.xml | 105 -----------
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml | 5 +
.../res/mipmap-anydpi-v26/ic_launcher_round.xml | 5 +
app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3687 bytes
app/src/main/res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 3687 bytes
app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2408 bytes
app/src/main/res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2408 bytes
app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4875 bytes
.../main/res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 4875 bytes
app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7673 bytes
.../main/res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 7673 bytes
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10362 bytes
.../main/res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 10362 bytes
app/src/main/res/navigation/nav_graph.xml | 35 +---
app/src/main/res/values/colors.xml | 2 +-
app/src/main/res/values/ic_launcher_background.xml | 4 +
app/src/main/res/values/strings.xml | 14 +-
app/src/main/res/values/styles.xml | 8 +-
artwork/ic_bottom_left.svg | 56 ++++++
artwork/ic_bottom_right.svg | 56 ++++++
artwork/ic_launcher.svg | 55 ++++++
43 files changed, 797 insertions(+), 383 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 217ad35..bc3e2ed 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -35,7 +35,7 @@ dependencies {
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.security:security-crypto:1.0.0-alpha02'
- implementation 'com.google.android.material:material:1.2.0-alpha04'
+ implementation 'com.google.android.material:material:1.1.0'
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png
new file mode 100644
index 0000000..04a58c6
Binary files /dev/null and b/app/src/main/ic_launcher-web.png differ
diff --git a/app/src/main/java/net/taler/cashier/BalanceFragment.kt
b/app/src/main/java/net/taler/cashier/BalanceFragment.kt
index 50e8488..13274f5 100644
--- a/app/src/main/java/net/taler/cashier/BalanceFragment.kt
+++ b/app/src/main/java/net/taler/cashier/BalanceFragment.kt
@@ -6,17 +6,22 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
-import android.view.View.INVISIBLE
+import android.view.View.VISIBLE
import android.view.ViewGroup
+import android.view.inputmethod.EditorInfo
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_balance.*
+import
net.taler.cashier.BalanceFragmentDirections.Companion.actionBalanceFragmentToTransactionFragment
+import net.taler.cashier.withdraw.LastTransaction
+import net.taler.cashier.withdraw.WithdrawStatus
class BalanceFragment : Fragment() {
private val viewModel: MainViewModel by activityViewModels()
+ private val withdrawManager by lazy { viewModel.withdrawManager }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@@ -27,16 +32,35 @@ class BalanceFragment : Fragment() {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ withdrawManager.lastTransaction.observe(viewLifecycleOwner, Observer {
lastTransaction ->
+ onLastTransaction(lastTransaction)
+ })
viewModel.balance.observe(viewLifecycleOwner, Observer { balance ->
balanceView.text = balance
- progressBar.visibility = INVISIBLE
+ val fadeIn =
+ listOf(introView, button5, button10, button20, button50,
amountView, currencyView)
+ for (v in fadeIn) v.fadeIn()
fab.show()
+ progressBar.fadeOut()
})
- fab.setOnClickListener {
-
BalanceFragmentDirections.actionBalanceFragmentToWithdrawFragment().let {
- findNavController().navigate(it)
- }
+ button5.setOnClickListener { onAmountButtonPressed(5) }
+ button10.setOnClickListener { onAmountButtonPressed(10) }
+ button20.setOnClickListener { onAmountButtonPressed(20) }
+ button50.setOnClickListener { onAmountButtonPressed(50) }
+
+ if (savedInstanceState != null) {
+
amountView.editText!!.setText(savedInstanceState.getCharSequence("amountView"))
+ }
+ amountView.editText!!.setOnEditorActionListener { _, actionId, _ ->
+ if (actionId == EditorInfo.IME_ACTION_GO) {
+ onAmountConfirmed(getAmountFromView())
+ true
+ } else false
}
+ viewModel.currency.observe(viewLifecycleOwner, Observer { currency ->
+ currencyView.text = currency
+ })
+ fab.setOnClickListener { onAmountConfirmed(getAmountFromView()) }
}
override fun onStart() {
@@ -47,6 +71,14 @@ class BalanceFragment : Fragment() {
}
}
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ // for some reason automatic restore isn't working at the moment!?
+ amountView?.editText?.text.let {
+ outState.putCharSequence("amountView", it)
+ }
+ }
+
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.balance, menu)
super.onCreateOptionsMenu(menu, inflater)
@@ -65,4 +97,47 @@ class BalanceFragment : Fragment() {
else -> super.onOptionsItemSelected(item)
}
+ private fun onAmountButtonPressed(amount: Int) {
+ amountView.editText!!.setText(amount.toString())
+ amountView.error = null
+ }
+
+ private fun getAmountFromView(): Int {
+ val str = amountView.editText!!.text.toString()
+ if (str.isBlank()) return 0
+ return Integer.parseInt(str)
+ }
+
+ private fun onAmountConfirmed(amount: Int) {
+ if (amount <= 0) {
+ amountView.error = getString(R.string.withdraw_error_zero)
+ } else if (!withdrawManager.hasSufficientBalance(amount)) {
+ amountView.error =
getString(R.string.withdraw_error_insufficient_balance)
+ } else {
+ amountView.error = null
+ withdrawManager.withdraw(amount)
+ actionBalanceFragmentToTransactionFragment().let {
+ findNavController().navigate(it)
+ }
+ }
+ }
+
+ private fun onLastTransaction(lastTransaction: LastTransaction?) {
+ val status = lastTransaction?.withdrawStatus
+ val text = when (status) {
+ is WithdrawStatus.Success -> getString(
+ R.string.transaction_last_success,
lastTransaction.withdrawAmount
+ )
+ is WithdrawStatus.Aborted ->
getString(R.string.transaction_last_aborted)
+ else -> getString(R.string.transaction_last_error)
+ }
+ lastTransactionView.text = text
+ val drawable = if (status == WithdrawStatus.Success)
+ R.drawable.ic_check_circle
+ else
+ R.drawable.ic_error
+
lastTransactionView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable,
0, 0, 0)
+ lastTransactionView.visibility = VISIBLE
+ }
+
}
diff --git a/app/src/main/java/net/taler/cashier/MainViewModel.kt
b/app/src/main/java/net/taler/cashier/MainViewModel.kt
index b3b1184..2ef7a09 100644
--- a/app/src/main/java/net/taler/cashier/MainViewModel.kt
+++ b/app/src/main/java/net/taler/cashier/MainViewModel.kt
@@ -43,8 +43,10 @@ class MainViewModel(private val app: Application) :
AndroidViewModel(app) {
password = prefs.getString(PREF_KEY_PASSWORD, "")!!
)
- internal var currency: String = prefs.getString(PREF_KEY_CURRENCY,
"TESTKUDOS")!!
- private set
+ private val mCurrency = MutableLiveData<String>(
+ prefs.getString(PREF_KEY_CURRENCY, null)
+ )
+ internal val currency: LiveData<String> = mCurrency
private val mConfigResult = MutableLiveData<ConfigResult>()
val configResult: LiveData<ConfigResult> = mConfigResult
@@ -52,8 +54,7 @@ class MainViewModel(private val app: Application) :
AndroidViewModel(app) {
private val mBalance = MutableLiveData<String>()
val balance: LiveData<String> = mBalance
- internal val withdrawManager =
- WithdrawManager(app, this)
+ internal val withdrawManager = WithdrawManager(app, this)
fun hasConfig() = config.bankUrl.isNotEmpty()
&& config.username.isNotEmpty()
@@ -73,8 +74,8 @@ class MainViewModel(private val app: Application) :
AndroidViewModel(app) {
is HttpJsonResult.Success -> {
val balance = response.json.getString("balance")
val amount = fromStringSigned(balance)!!
- currency = amount.currency
- prefs.edit().putString(PREF_KEY_CURRENCY, currency).apply()
+ mCurrency.postValue(amount.currency)
+ prefs.edit().putString(PREF_KEY_CURRENCY,
amount.currency).apply()
// save config
saveConfig(config)
ConfigResult(true)
@@ -110,7 +111,8 @@ class MainViewModel(private val app: Application) :
AndroidViewModel(app) {
"${amount.amount} ${amount.currency}"
}
is HttpJsonResult.Error -> {
- app.getString(R.string.balance_error)
+ // show last known value or error string in case of an error
+ mBalance.value ?: app.getString(R.string.balance_error)
}
}
mBalance.postValue(result)
diff --git a/app/src/main/java/net/taler/cashier/Utils.kt
b/app/src/main/java/net/taler/cashier/Utils.kt
index 5c9cf5c..e8abe9a 100644
--- a/app/src/main/java/net/taler/cashier/Utils.kt
+++ b/app/src/main/java/net/taler/cashier/Utils.kt
@@ -40,6 +40,7 @@ object Utils {
}
fun View.fadeIn(endAction: () -> Unit = {}) {
+ if (visibility == VISIBLE) return
alpha = 0f
visibility = VISIBLE
animate().alpha(1f).withEndAction {
diff --git a/app/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
b/app/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
index acb0ea3..3ab2f73 100644
--- a/app/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
+++ b/app/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
@@ -6,8 +6,9 @@ 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_success.*
+import kotlinx.android.synthetic.main.fragment_error.*
import net.taler.cashier.MainViewModel
import net.taler.cashier.R
@@ -24,7 +25,12 @@ class ErrorFragment : Fragment() {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- withdrawManager.resetState()
+ withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer {
status ->
+ if (status is WithdrawStatus.Aborted) {
+ textView.setText(R.string.transaction_aborted)
+ }
+ })
+ withdrawManager.completeTransaction()
backButton.setOnClickListener {
findNavController().popBackStack()
}
diff --git a/app/src/main/java/net/taler/cashier/withdraw/NfcManager.kt
b/app/src/main/java/net/taler/cashier/withdraw/NfcManager.kt
index 3aa1caa..f05cb52 100644
--- a/app/src/main/java/net/taler/cashier/withdraw/NfcManager.kt
+++ b/app/src/main/java/net/taler/cashier/withdraw/NfcManager.kt
@@ -5,6 +5,7 @@ import android.content.Context
import android.nfc.NfcAdapter
import android.nfc.NfcAdapter.FLAG_READER_NFC_A
import android.nfc.NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK
+import android.nfc.NfcAdapter.getDefaultAdapter
import android.nfc.Tag
import android.nfc.tech.IsoDep
import android.util.Log
@@ -19,25 +20,29 @@ class NfcManager : NfcAdapter.ReaderCallback {
companion object {
const val TAG = "taler-merchant"
+ /**
+ * Returns true if NFC is supported and false otherwise.
+ */
+ fun hasNfc(context: Context): Boolean {
+ return getDefaultAdapter(context) != null
+ }
+
/**
* Enables NFC reader mode. Don't forget to call [stop] afterwards.
*/
fun start(activity: Activity, nfcManager: NfcManager) {
- getNfcAdapter(
- activity
- )?.enableReaderMode(activity, nfcManager, nfcManager.flags, null)
+ getNfcAdapter(activity)?.enableReaderMode(activity, nfcManager,
nfcManager.flags, null)
}
/**
* Disables NFC reader mode. Call after [start].
*/
fun stop(activity: Activity) {
- getNfcAdapter(
- activity
- )?.disableReaderMode(activity)
+ getNfcAdapter(activity)?.disableReaderMode(activity)
}
private fun getNfcAdapter(context: Context): NfcAdapter? {
+ val test: android.nfc.NfcManager
return NfcAdapter.getDefaultAdapter(context)
}
}
diff --git a/app/src/main/java/net/taler/cashier/withdraw/SuccessFragment.kt
b/app/src/main/java/net/taler/cashier/withdraw/SuccessFragment.kt
deleted file mode 100644
index 53459f9..0000000
--- a/app/src/main/java/net/taler/cashier/withdraw/SuccessFragment.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package net.taler.cashier.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.navigation.fragment.findNavController
-import kotlinx.android.synthetic.main.fragment_success.*
-import net.taler.cashier.MainViewModel
-import net.taler.cashier.R
-
-class SuccessFragment : Fragment() {
-
- private val viewModel: MainViewModel by activityViewModels()
- private val withdrawManager by lazy { viewModel.withdrawManager }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- return inflater.inflate(R.layout.fragment_success, container, false)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- withdrawManager.resetState()
- backButton.setOnClickListener {
- findNavController().popBackStack()
- }
- }
-
-}
diff --git
a/app/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
b/app/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
index f359cbc..dfef1cf 100644
--- a/app/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
+++ b/app/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
@@ -16,8 +16,8 @@ import net.taler.cashier.MainViewModel
import net.taler.cashier.R
import net.taler.cashier.fadeIn
import net.taler.cashier.fadeOut
+import
net.taler.cashier.withdraw.TransactionFragmentDirections.Companion.actionTransactionFragmentToBalanceFragment
import
net.taler.cashier.withdraw.TransactionFragmentDirections.Companion.actionTransactionFragmentToErrorFragment
-import
net.taler.cashier.withdraw.TransactionFragmentDirections.Companion.actionTransactionFragmentToSuccessFragment
import net.taler.cashier.withdraw.WithdrawResult.Error
import net.taler.cashier.withdraw.WithdrawResult.InsufficientBalance
import net.taler.cashier.withdraw.WithdrawResult.Success
@@ -45,6 +45,12 @@ class TransactionFragment : Fragment() {
withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer {
status ->
onWithdrawStatusChanged(status)
})
+
+ // change intro text depending on whether NFC is available or not
+ val hasNfc = NfcManager.hasNfc(requireContext())
+ val intro = if (hasNfc) R.string.transaction_intro_nfc else
R.string.transaction_intro
+ introView.setText(intro)
+
cancelButton.setOnClickListener {
findNavController().popBackStack()
}
@@ -53,10 +59,7 @@ class TransactionFragment : Fragment() {
override fun onStart() {
super.onStart()
if (withdrawManager.withdrawResult.value is Success) {
- NfcManager.start(
- requireActivity(),
- nfcManager
- )
+ NfcManager.start(requireActivity(), nfcManager)
}
}
@@ -82,18 +85,12 @@ class TransactionFragment : Fragment() {
}
when (result) {
is InsufficientBalance -> {
- val c = getColor(
- requireContext(),
- R.color.design_default_color_error
- )
+ val c = getColor(requireContext(),
R.color.design_default_color_error)
introView.setTextColor(c)
introView.text =
getString(R.string.withdraw_error_insufficient_balance)
}
is Error -> {
- val c = getColor(
- requireContext(),
- R.color.design_default_color_error
- )
+ val c = getColor(requireContext(),
R.color.design_default_color_error)
introView.setTextColor(c)
introView.text = result.msg
}
@@ -120,15 +117,30 @@ class TransactionFragment : Fragment() {
private fun onWithdrawStatusChanged(status: WithdrawStatus?): Any = when
(status) {
is WithdrawStatus.SelectionDone -> {
- qrCodeView.fadeOut()
- progressBar.fadeIn()
+ qrCodeView.fadeOut {
+ qrCodeView?.setImageResource(R.drawable.ic_arrow)
+ qrCodeView?.fadeIn()
+ }
introView.fadeOut {
- introView.text = getString(R.string.transaction_intro_scanned)
- introView.fadeIn()
+ introView?.text = getString(R.string.transaction_intro_scanned)
+ introView?.fadeIn {
+ confirmButton?.isEnabled = true
+ confirmButton?.setOnClickListener {
+ withdrawManager.confirm(status.withdrawalId)
+ }
+ }
}
}
- is WithdrawStatus.Confirmed ->
actionTransactionFragmentToSuccessFragment().let {
- findNavController().navigate(it)
+ is WithdrawStatus.Confirming -> {
+ confirmButton.isEnabled = false
+ qrCodeView.fadeOut()
+ progressBar.fadeIn()
+ }
+ is WithdrawStatus.Success -> {
+ withdrawManager.completeTransaction()
+ actionTransactionFragmentToBalanceFragment().let {
+ findNavController().navigate(it)
+ }
}
is WithdrawStatus.Aborted -> onError()
is WithdrawStatus.Error -> onError()
diff --git a/app/src/main/java/net/taler/cashier/withdraw/WithdrawFragment.kt
b/app/src/main/java/net/taler/cashier/withdraw/WithdrawFragment.kt
deleted file mode 100644
index d4b4c8d..0000000
--- a/app/src/main/java/net/taler/cashier/withdraw/WithdrawFragment.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-package net.taler.cashier.withdraw
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.view.inputmethod.EditorInfo.IME_ACTION_GO
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.activityViewModels
-import androidx.navigation.fragment.findNavController
-import kotlinx.android.synthetic.main.fragment_withdraw.*
-import net.taler.cashier.MainViewModel
-import net.taler.cashier.R
-
-class WithdrawFragment : Fragment() {
-
- private val viewModel: MainViewModel by activityViewModels()
- private val withdrawManager by lazy { viewModel.withdrawManager }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- return inflater.inflate(R.layout.fragment_withdraw, container, false)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- button5.setOnClickListener { onAmountButtonPressed(5) }
- button10.setOnClickListener { onAmountButtonPressed(10) }
- button20.setOnClickListener { onAmountButtonPressed(20) }
- button50.setOnClickListener { onAmountButtonPressed(50) }
-
- if (savedInstanceState != null) {
-
amountView.editText!!.setText(savedInstanceState.getCharSequence("amount"))
- }
- amountView.editText!!.setOnEditorActionListener { _, actionId, _ ->
- if (actionId == IME_ACTION_GO) {
- onAmountConfirmed(getAmountFromView())
- true
- } else false
- }
- fab.setOnClickListener { onAmountConfirmed(getAmountFromView()) }
- }
-
- override fun onSaveInstanceState(outState: Bundle) {
- super.onSaveInstanceState(outState)
- // for some reason automatic restore isn't working at the moment!?
- amountView?.editText?.text.let {
- outState.putCharSequence("amount", it)
- }
- }
-
- private fun onAmountButtonPressed(amount: Int) {
- amountView.editText!!.setText(amount.toString())
- amountView.error = null
- }
-
- private fun getAmountFromView(): Int {
- val str = amountView.editText!!.text.toString()
- if (str.isBlank()) return 0
- return Integer.parseInt(str)
- }
-
- private fun onAmountConfirmed(amount: Int) {
- if (amount <= 0) {
- amountView.error = getString(R.string.withdraw_error_zero)
- } else if (!withdrawManager.hasSufficientBalance(amount)) {
- amountView.error =
getString(R.string.withdraw_error_insufficient_balance)
- } else {
- amountView.error = null
- withdrawManager.withdraw(amount)
-
WithdrawFragmentDirections.actionWithdrawFragmentToTransactionFragment()
- .let {
- findNavController().navigate(it)
- }
- }
- }
-
-}
diff --git a/app/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
b/app/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
index 6ccf344..c8b1972 100644
--- a/app/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
+++ b/app/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
@@ -5,12 +5,11 @@ import android.graphics.Bitmap
import android.os.CountDownTimer
import android.util.Log
import androidx.annotation.UiThread
-import androidx.annotation.WorkerThread
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import net.taler.cashier.HttpHelper.makeJsonGetRequest
import net.taler.cashier.HttpHelper.makeJsonPostRequest
@@ -37,8 +36,10 @@ class WithdrawManager(
private val config
get() = viewModel.config
- private val currency
- get() = viewModel.currency
+ private val currency: String?
+ get() = viewModel.currency.value
+
+ private var withdrawStatusCheck: Job? = null
private val mWithdrawAmount = MutableLiveData<String>()
val withdrawAmount: LiveData<String> = mWithdrawAmount
@@ -47,7 +48,10 @@ class WithdrawManager(
val withdrawResult: LiveData<WithdrawResult> = mWithdrawResult
private val mWithdrawStatus = MutableLiveData<WithdrawStatus>()
- val withdrawStatus: LiveData<WithdrawStatus> =
mWithdrawStatus.distinctUntilChanged()
+ val withdrawStatus: LiveData<WithdrawStatus> = mWithdrawStatus
+
+ private val mLastTransaction = MutableLiveData<LastTransaction>()
+ val lastTransaction: LiveData<LastTransaction> = mLastTransaction
@UiThread
fun hasSufficientBalance(amount: Int): Boolean {
@@ -60,6 +64,7 @@ class WithdrawManager(
@UiThread
fun withdraw(amount: Int) {
check(amount > 0) { "Withdraw amount was <= 0" }
+ check(currency != null) { "Currency is null" }
mWithdrawResult.value = null
mWithdrawAmount.value = "$amount $currency"
scope.launch(Dispatchers.IO) {
@@ -89,7 +94,11 @@ class WithdrawManager(
override fun onTick(millisUntilFinished: Long) {
val result = withdrawResult.value
if (result is WithdrawResult.Success) {
- checkWithdrawStatus(result.id)
+ // check for active jobs and only do one at a time
+ val hasActiveCheck = withdrawStatusCheck?.isActive ?: false
+ if (!hasActiveCheck) {
+ withdrawStatusCheck = checkWithdrawStatus(result.id)
+ }
} else {
cancel()
}
@@ -107,34 +116,44 @@ class WithdrawManager(
Log.d(TAG, "Checking withdraw status at $url")
val response = makeJsonGetRequest(url, config)
if (response !is Success) return@launch // ignore errors and continue
trying
+ val oldStatus = mWithdrawStatus.value
when {
response.json.getBoolean("aborted") -> {
+ cancelWithdrawStatusCheck()
mWithdrawStatus.postValue(WithdrawStatus.Aborted)
- timer.cancel()
}
response.json.getBoolean("confirmation_done") -> {
- mWithdrawStatus.postValue(WithdrawStatus.Confirmed)
- viewModel.getBalance()
- timer.cancel()
+ if (oldStatus !is WithdrawStatus.Success) {
+ cancelWithdrawStatusCheck()
+ mWithdrawStatus.postValue(WithdrawStatus.Success)
+ viewModel.getBalance()
+ }
}
response.json.getBoolean("selection_done") -> {
- if (mWithdrawStatus.value != WithdrawStatus.SelectionDone) {
- mWithdrawStatus.postValue(WithdrawStatus.SelectionDone)
- confirm(withdrawalId)
+ // only update status, if there's none, yet
+ // so we don't re-notify or overwrite newer status info
+ if (oldStatus == null) {
+
mWithdrawStatus.postValue(WithdrawStatus.SelectionDone(withdrawalId))
}
}
}
}
+ private fun cancelWithdrawStatusCheck() {
+ timer.cancel()
+ withdrawStatusCheck?.cancel()
+ }
+
/**
* Aborts the last [withdrawResult], if it exists und there is no
[withdrawStatus].
* Otherwise this is a no-op.
*/
+ @UiThread
fun abort() {
val result = withdrawResult.value
val status = withdrawStatus.value
if (result is WithdrawResult.Success && status == null) {
- timer.cancel()
+ cancelWithdrawStatusCheck()
abort(result.id)
}
}
@@ -145,24 +164,29 @@ class WithdrawManager(
makeJsonPostRequest(url, "", config)
}
- @WorkerThread
- private fun confirm(withdrawalId: String) {
- val url =
-
"${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}/confirm"
- Log.d(TAG, "Confirming withdrawal at $url")
- when (val result = makeJsonPostRequest(url, "", config)) {
- is Success -> {
- mWithdrawStatus.postValue(WithdrawStatus.Confirmed)
- }
- is Error -> {
- Log.e(TAG, "Error confirming withdrawal. Status code:
${result.statusCode}")
- mWithdrawStatus.postValue(WithdrawStatus.Error)
+ @UiThread
+ fun confirm(withdrawalId: String) {
+ mWithdrawStatus.value = WithdrawStatus.Confirming
+ scope.launch(Dispatchers.IO) {
+ val url =
+
"${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}/confirm"
+ Log.d(TAG, "Confirming withdrawal at $url")
+ when (val result = makeJsonPostRequest(url, "", config)) {
+ is Success -> {
+ // no-op still waiting for [timer] to confirm our
confirmation
+ }
+ is Error -> {
+ Log.e(TAG, "Error confirming withdrawal. Status code:
${result.statusCode}")
+ mWithdrawStatus.postValue(WithdrawStatus.Error)
+ }
}
}
}
@UiThread
- fun resetState() {
+ fun completeTransaction() {
+ mLastTransaction.value = LastTransaction(withdrawAmount.value!!,
withdrawStatus.value!!)
+ withdrawStatusCheck = null
mWithdrawAmount.value = null
mWithdrawResult.value = null
mWithdrawStatus.value = null
@@ -179,6 +203,12 @@ sealed class WithdrawResult {
sealed class WithdrawStatus {
object Error : WithdrawStatus()
object Aborted : WithdrawStatus()
- object SelectionDone : WithdrawStatus()
- object Confirmed : WithdrawStatus()
+ class SelectionDone(val withdrawalId: String) : WithdrawStatus()
+ object Confirming : WithdrawStatus()
+ object Success : WithdrawStatus()
}
+
+data class LastTransaction(
+ val withdrawAmount: String,
+ val withdrawStatus: WithdrawStatus
+)
diff --git a/app/src/main/res/drawable-w550dp/ic_arrow.xml
b/app/src/main/res/drawable-w550dp/ic_arrow.xml
new file mode 100644
index 0000000..331ea06
--- /dev/null
+++ b/app/src/main/res/drawable-w550dp/ic_arrow.xml
@@ -0,0 +1,11 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:alpha="0.56"
+ android:tint="@color/green"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#000000"
+ android:pathData="M20,5.41 L18.59,4 7,15.59V9H5V19H15V17H8.41" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_arrow.xml
b/app/src/main/res/drawable/ic_arrow.xml
new file mode 100644
index 0000000..d7578bd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow.xml
@@ -0,0 +1,11 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:alpha="0.56"
+ android:tint="@color/green"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#000000"
+ android:pathData="M5,5.41 L6.41,4 18,15.59V9h2V19H10v-2h6.59" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_check_circle.xml
b/app/src/main/res/drawable/ic_check_circle.xml
index 7fbbed1..d43d6ba 100644
--- a/app/src/main/res/drawable/ic_check_circle.xml
+++ b/app/src/main/res/drawable/ic_check_circle.xml
@@ -2,7 +2,6 @@
android:width="24dp"
android:height="24dp"
android:alpha="0.56"
- android:tint="@color/green"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml
b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..581c480
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,13 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+ <group android:translateX="12"
+ android:translateY="12">
+ <path
+ android:pathData="M6,3L6,6L9,6L9,7L6.25,7C5.05,7 4.0508,8
4.0508,9L3.5,16L20.5,16L20,9C19.8,8 18.8008,7
17.8008,7L11,7L11,6L14,6L14,3L6,3zM7,4L13,4L13,5L7,5L7,4zM6,9L8,9L8,10L6,10L6,9zM9,9L11,9L11,10L9,10L9,9zM13,9L18,9L18,11L13,11L13,9zM6,11L8,11L8,12L6,12L6,11zM9,11L11,11L11,12L9,12L9,11zM6,13L8,13L8,14L6,14L6,13zM9,13L11,13L11,14L9,14L9,13zM2,17L2,21L22,21L22,17L2,17zM4.7422,17.291L7.2695,17.291L7.2695,17.7793L6.3574,17.7793L6.3574,20.6777L5.6543,20.6777L5.6543,17.7793L4.7422,
[...]
+ android:fillColor="#f9f9f9"
+ android:fillAlpha="1"/>
+ </group>
+</vector>
diff --git a/app/src/main/res/layout-w550dp/fragment_balance.xml
b/app/src/main/res/layout-w550dp/fragment_balance.xml
new file mode 100644
index 0000000..72d5b89
--- /dev/null
+++ b/app/src/main/res/layout-w550dp/fragment_balance.xml
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout
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=".BalanceFragment">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/lastTransactionView"
+ style="@style/Widget.MaterialComponents.Snackbar.FullWidth"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="?attr/colorPrimaryDark"
+ android:drawableStart="@drawable/ic_check_circle"
+ android:drawablePadding="8dp"
+ android:drawableTint="?attr/colorOnPrimarySurface"
+ android:gravity="center_vertical"
+ android:padding="8dp"
+ android:textColor="?attr/colorOnPrimarySurface"
+ android:visibility="gone"
+ app:layout_constraintEnd_toStartOf="@+id/guideline"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="@string/transaction_last_success"
+ tools:visibility="visible" />
+
+ <TextView
+ android:id="@+id/balanceLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="32dp"
+ android:layout_marginTop="32dp"
+ android:layout_marginEnd="32dp"
+ android:text="@string/balance_current_label"
+ android:textAppearance="@style/TextAppearance.AppCompat.Medium"
+ app:layout_constraintBottom_toTopOf="@+id/balanceView"
+ app:layout_constraintEnd_toStartOf="@+id/guideline"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/lastTransactionView"
+ app:layout_constraintVertical_bias="0.0"
+ app:layout_constraintVertical_chainStyle="packed" />
+
+ <TextView
+ android:id="@+id/balanceView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="32dp"
+ android:textAppearance="@style/TextAppearance.AppCompat.Headline"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/guideline"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/balanceLabel"
+ tools:text="100 KUDOS" />
+
+ <ProgressBar
+ android:id="@+id/progressBar"
+ style="?android:attr/progressBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="@+id/balanceView"
+ app:layout_constraintEnd_toEndOf="@+id/balanceView"
+ app:layout_constraintStart_toStartOf="@+id/balanceView"
+ app:layout_constraintTop_toTopOf="@+id/balanceView" />
+
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ app:layout_constraintGuide_percent="0.5" />
+
+ <TextView
+ android:id="@+id/introView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="32dp"
+ android:text="@string/withdraw_into"
+ android:textAlignment="center"
+ android:textAppearance="@style/TextAppearance.AppCompat.Medium"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="@+id/guideline"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:visibility="visible" />
+
+ <Button
+ android:id="@+id/button5"
+ style="@style/AmountButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="5"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toStartOf="@+id/button10"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ app:layout_constraintStart_toStartOf="@+id/guideline"
+ app:layout_constraintTop_toBottomOf="@+id/introView"
+ tools:ignore="HardcodedText"
+ tools:visibility="visible" />
+
+ <Button
+ android:id="@+id/button10"
+ style="@style/AmountButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="10"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toStartOf="@+id/button20"
+ app:layout_constraintStart_toEndOf="@+id/button5"
+ app:layout_constraintTop_toBottomOf="@+id/introView"
+ tools:ignore="HardcodedText"
+ tools:visibility="visible" />
+
+ <Button
+ android:id="@+id/button20"
+ style="@style/AmountButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="20"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toStartOf="@+id/button50"
+ app:layout_constraintStart_toEndOf="@+id/button10"
+ app:layout_constraintTop_toBottomOf="@+id/introView"
+ tools:ignore="HardcodedText"
+ tools:visibility="visible" />
+
+ <Button
+ android:id="@+id/button50"
+ style="@style/AmountButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="50"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/button20"
+ app:layout_constraintTop_toBottomOf="@+id/introView"
+ tools:ignore="HardcodedText"
+ tools:visibility="visible" />
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/amountView"
+
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="32dp"
+ android:hint="@string/withdraw_input_amount"
+ android:visibility="invisible"
+ app:endIconDrawable="@drawable/ic_clear"
+ app:endIconMode="clear_text"
+ app:endIconTint="?attr/colorControlNormal"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="@+id/guideline"
+ app:layout_constraintTop_toBottomOf="@+id/button5"
+ tools:visibility="visible">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ems="6"
+ android:imeOptions="actionGo"
+ android:inputType="number"
+ android:maxLength="4" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <TextView
+ android:id="@+id/currencyView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/amountView"
+ app:layout_constraintTop_toTopOf="@+id/amountView"
+ tools:text="TESTKUDOS"
+ tools:visibility="visible" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <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/default_margin"
+ android:visibility="invisible"
+ app:srcCompat="@drawable/ic_withdraw"
+ app:useCompatPadding="true"
+ tools:visibility="visible" />
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout-w550dp/fragment_transaction.xml
b/app/src/main/res/layout-w550dp/fragment_transaction.xml
index 0076f25..634633a 100644
--- a/app/src/main/res/layout-w550dp/fragment_transaction.xml
+++ b/app/src/main/res/layout-w550dp/fragment_transaction.xml
@@ -49,7 +49,7 @@
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
- tools:src="@tools:sample/avatars"
+ tools:src="@drawable/ic_arrow"
tools:visibility="visible" />
<ProgressBar
@@ -70,9 +70,26 @@
android:backgroundTint="@color/red"
android:text="@string/transaction_abort"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/guideline"
+ app:layout_constraintEnd_toStartOf="@+id/confirmButton"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/qrCodeView"
app:layout_constraintVertical_bias="1.0" />
+ <Button
+ android:id="@+id/confirmButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:backgroundTint="@color/green"
+ android:enabled="false"
+ android:text="@string/transaction_confirm"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/guideline"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toEndOf="@+id/cancelButton"
+ tools:enabled="true" />
+
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/activity_main.xml
b/app/src/main/res/layout/activity_main.xml
index bf7f543..766537e 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -13,9 +13,9 @@
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
+ style="@style/AppTheme.Toolbar"
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary" />
+ android:layout_height="wrap_content" />
</com.google.android.material.appbar.AppBarLayout>
diff --git a/app/src/main/res/layout/fragment_balance.xml
b/app/src/main/res/layout/fragment_balance.xml
index dd376d0..2ef77fd 100644
--- a/app/src/main/res/layout/fragment_balance.xml
+++ b/app/src/main/res/layout/fragment_balance.xml
@@ -10,6 +10,25 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <TextView
+ android:id="@+id/lastTransactionView"
+ style="@style/Widget.MaterialComponents.Snackbar.FullWidth"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="?attr/colorPrimaryDark"
+ android:drawableStart="@drawable/ic_check_circle"
+ android:drawablePadding="8dp"
+ android:drawableTint="?attr/colorOnPrimarySurface"
+ android:gravity="center_vertical"
+ android:padding="8dp"
+ android:textColor="?attr/colorOnPrimarySurface"
+ android:visibility="gone"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="@string/transaction_last_success"
+ tools:visibility="visible" />
+
<TextView
android:id="@+id/balanceLabel"
android:layout_width="wrap_content"
@@ -19,7 +38,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toBottomOf="@+id/lastTransactionView" />
<TextView
android:id="@+id/balanceView"
@@ -42,6 +61,112 @@
app:layout_constraintStart_toStartOf="@+id/balanceView"
app:layout_constraintTop_toTopOf="@+id/balanceView" />
+ <TextView
+ android:id="@+id/introView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="32dp"
+ android:text="@string/withdraw_into"
+ android:textAlignment="center"
+ android:textAppearance="@style/TextAppearance.AppCompat.Medium"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/progressBar"
+ tools:visibility="visible" />
+
+ <Button
+ android:id="@+id/button5"
+ style="@style/AmountButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="5"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toStartOf="@+id/button10"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/introView"
+ tools:ignore="HardcodedText"
+ tools:visibility="visible" />
+
+ <Button
+ android:id="@+id/button10"
+ style="@style/AmountButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="10"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toStartOf="@+id/button20"
+ app:layout_constraintStart_toEndOf="@+id/button5"
+ app:layout_constraintTop_toBottomOf="@+id/introView"
+ tools:ignore="HardcodedText"
+ tools:visibility="visible" />
+
+ <Button
+ android:id="@+id/button20"
+ style="@style/AmountButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="20"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toStartOf="@+id/button50"
+ app:layout_constraintStart_toEndOf="@+id/button10"
+ app:layout_constraintTop_toBottomOf="@+id/introView"
+ tools:ignore="HardcodedText"
+ tools:visibility="visible" />
+
+ <Button
+ android:id="@+id/button50"
+ style="@style/AmountButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="50"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/button20"
+ app:layout_constraintTop_toBottomOf="@+id/introView"
+ tools:ignore="HardcodedText"
+ tools:visibility="visible" />
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/amountView"
+
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="32dp"
+ android:hint="@string/withdraw_input_amount"
+ android:visibility="invisible"
+ app:endIconDrawable="@drawable/ic_clear"
+ app:endIconMode="clear_text"
+ app:endIconTint="?attr/colorControlNormal"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/button5"
+ tools:visibility="visible">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ems="6"
+ android:imeOptions="actionGo"
+ android:inputType="number"
+ android:maxLength="4" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <TextView
+ android:id="@+id/currencyView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:textAppearance="@style/TextAppearance.AppCompat.Medium"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/amountView"
+ app:layout_constraintTop_toTopOf="@+id/amountView"
+ tools:text="TESTKUDOS"
+ tools:visibility="visible" />
+
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
diff --git a/app/src/main/res/layout/fragment_error.xml
b/app/src/main/res/layout/fragment_error.xml
index 143a92d..f96e08f 100644
--- a/app/src/main/res/layout/fragment_error.xml
+++ b/app/src/main/res/layout/fragment_error.xml
@@ -5,7 +5,7 @@
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".withdraw.SuccessFragment">
+ tools:context=".withdraw.ErrorFragment">
<ImageView
android:id="@+id/imageView"
diff --git a/app/src/main/res/layout/fragment_success.xml
b/app/src/main/res/layout/fragment_success.xml
deleted file mode 100644
index e59072e..0000000
--- a/app/src/main/res/layout/fragment_success.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<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/frameLayout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".withdraw.SuccessFragment">
-
- <ImageView
- android:id="@+id/imageView"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_margin="32dp"
- android:src="@drawable/ic_check_circle"
- app:layout_constraintBottom_toTopOf="@+id/textView"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.5"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:ignore="ContentDescription" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/textView"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_margin="32dp"
- android:text="@string/transaction_success"
- android:textAlignment="center"
- android:textColor="@color/green"
- app:autoSizeMaxTextSize="42sp"
- app:autoSizeTextType="uniform"
- app:layout_constraintBottom_toTopOf="@+id/backButton"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.5"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/imageView" />
-
- <Button
- android:id="@+id/backButton"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_margin="16dp"
- android:text="@string/transaction_button_back"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_transaction.xml
b/app/src/main/res/layout/fragment_transaction.xml
index 8083fcf..43c7db3 100644
--- a/app/src/main/res/layout/fragment_transaction.xml
+++ b/app/src/main/res/layout/fragment_transaction.xml
@@ -41,7 +41,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/amountView"
tools:ignore="ContentDescription"
- tools:src="@tools:sample/avatars"
+ tools:src="@drawable/ic_arrow"
tools:visibility="visible" />
<ProgressBar
@@ -62,9 +62,23 @@
android:backgroundTint="@color/red"
android:text="@string/transaction_abort"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/confirmButton"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/qrCodeView"
app:layout_constraintVertical_bias="1.0" />
+ <Button
+ android:id="@+id/confirmButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:backgroundTint="@color/green"
+ android:enabled="false"
+ android:text="@string/transaction_confirm"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/cancelButton"
+ tools:enabled="true" />
+
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/fragment_withdraw.xml
b/app/src/main/res/layout/fragment_withdraw.xml
deleted file mode 100644
index e038978..0000000
--- a/app/src/main/res/layout/fragment_withdraw.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.coordinatorlayout.widget.CoordinatorLayout
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=".withdraw.WithdrawFragment">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/introView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="32dp"
- android:text="@string/withdraw_into"
- android:textSize="16sp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <com.google.android.material.textfield.TextInputLayout
- android:id="@+id/amountView"
-
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="32dp"
- android:hint="@string/withdraw_input_amount"
- app:endIconDrawable="@drawable/ic_clear"
- app:endIconMode="clear_text"
- app:endIconTint="?attr/colorControlNormal"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/button5">
-
- <com.google.android.material.textfield.TextInputEditText
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:ems="6"
- android:imeOptions="actionGo"
- android:inputType="number"
- android:maxLength="4" />
-
- </com.google.android.material.textfield.TextInputLayout>
-
- <Button
- android:id="@+id/button5"
- style="@style/AmountButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="5"
- app:layout_constraintEnd_toStartOf="@+id/button10"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/introView"
- tools:ignore="HardcodedText" />
-
- <Button
- android:id="@+id/button10"
- style="@style/AmountButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="10"
- app:layout_constraintEnd_toStartOf="@+id/button20"
- app:layout_constraintStart_toEndOf="@+id/button5"
- app:layout_constraintTop_toBottomOf="@+id/introView"
- tools:ignore="HardcodedText" />
-
- <Button
- android:id="@+id/button20"
- style="@style/AmountButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="20"
- app:layout_constraintEnd_toStartOf="@+id/button50"
- app:layout_constraintStart_toEndOf="@+id/button10"
- app:layout_constraintTop_toBottomOf="@+id/introView"
- tools:ignore="HardcodedText" />
-
- <Button
- android:id="@+id/button50"
- style="@style/AmountButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="50"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@+id/button20"
- app:layout_constraintTop_toBottomOf="@+id/introView"
- tools:ignore="HardcodedText" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <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/default_margin"
- android:tint="@color/design_default_color_surface"
- app:srcCompat="@drawable/ic_check"
- app:useCompatPadding="true" />
-
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..7353dbd
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/ic_launcher_background"/>
+ <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..7353dbd
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/ic_launcher_background"/>
+ <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png
b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..c52928c
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..c52928c
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png
b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..b97178b
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b97178b
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png
b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..8f92c07
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..8f92c07
Binary files /dev/null and
b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..214cbea
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..214cbea
Binary files /dev/null and
b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b959cd3
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b959cd3
Binary files /dev/null and
b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/navigation/nav_graph.xml
b/app/src/main/res/navigation/nav_graph.xml
index 5d7dd78..0bd6d15 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -23,24 +23,8 @@
android:label="fragment_balance"
tools:layout="@layout/fragment_balance">
<action
- android:id="@+id/action_balanceFragment_to_withdrawFragment"
- app:destination="@id/withdrawFragment"
- app:enterAnim="@anim/fragment_open_enter"
- app:exitAnim="@anim/fragment_open_exit"
- app:launchSingleTop="true" />
- </fragment>
-
- <fragment
- android:id="@+id/withdrawFragment"
- android:name="net.taler.cashier.withdraw.WithdrawFragment"
- android:label="fragment_withdraw"
- tools:layout="@layout/fragment_withdraw">
- <action
- android:id="@+id/action_withdrawFragment_to_transactionFragment"
- app:destination="@id/transactionFragment"
- app:enterAnim="@anim/fragment_open_enter"
- app:exitAnim="@anim/fragment_open_exit"
- app:launchSingleTop="true" />
+ android:id="@+id/action_balanceFragment_to_transactionFragment"
+ app:destination="@id/transactionFragment" />
</fragment>
<fragment
@@ -49,22 +33,17 @@
android:label="fragment_transaction"
tools:layout="@layout/fragment_transaction">
<action
- android:id="@+id/action_transactionFragment_to_successFragment"
- app:destination="@id/successFragment"
+ android:id="@+id/action_transactionFragment_to_errorFragment"
+ app:destination="@id/errorFragment"
app:launchSingleTop="true"
app:popUpTo="@+id/balanceFragment" />
<action
- android:id="@+id/action_transactionFragment_to_errorFragment"
- app:destination="@id/errorFragment"
+ android:id="@+id/action_transactionFragment_to_balanceFragment"
+ app:destination="@id/balanceFragment"
app:launchSingleTop="true"
- app:popUpTo="@+id/withdrawFragment" />
+ app:popUpTo="@+id/balanceFragment" />
</fragment>
- <fragment
- android:id="@+id/successFragment"
- android:name="net.taler.cashier.withdraw.SuccessFragment"
- tools:layout="@layout/fragment_success" />
-
<fragment
android:id="@+id/errorFragment"
android:name="net.taler.cashier.withdraw.ErrorFragment"
diff --git a/app/src/main/res/values/colors.xml
b/app/src/main/res/values/colors.xml
index d9acb88..f69adcd 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -4,6 +4,6 @@
<color name="colorPrimaryDark">#6A1B9A</color>
<color name="colorAccent">#D81B60</color>
- <color name="green">#4CAF50</color>
+ <color name="green">#388E3C</color>
<color name="red">#D32F2F</color>
</resources>
diff --git a/app/src/main/res/values/ic_launcher_background.xml
b/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..3862264
--- /dev/null
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="ic_launcher_background">#1565C0</color>
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml
b/app/src/main/res/values/strings.xml
index ab15c09..2d33169 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -10,23 +10,29 @@
<string name="config_error">Error retrieving configuration</string>
<string name="config_error_auth">Invalid username or password</string>
- <string name="balance_current_label">Current Balance:</string>
+ <string name="balance_current_label">Current balance</string>
<string name="balance_error">ERROR</string>
<string name="action_reconfigure">Reconfigure</string>
<string name="action_lock">Lock</string>
<string name="withdraw_input_amount">Amount</string>
<string name="withdraw_clear">clear amount</string>
- <string name="withdraw_into">How much to cash in?</string>
+ <string name="withdraw_into">How much e-cash should be withdrawn?</string>
<string name="withdraw_error_zero">Enter positive amount</string>
<string name="withdraw_error_insufficient_balance">Insufficient
balance</string>
<string name="withdraw_error_fetch">Error communicating with bank</string>
- <string name="transaction_intro">Scan code or use NFC\nwith the Taler
wallet app\nto get</string>
- <string name="transaction_intro_scanned">Waiting for confirmation…</string>
+ <string name="transaction_intro">Scan code\nwith the Taler wallet app\nto
get</string>
+ <string name="transaction_intro_nfc">Scan code or use NFC\nwith the Taler
wallet app\nto get</string>
+ <string name="transaction_intro_scanned">Please confirm the
transaction!</string>
+ <string name="transaction_confirm">Confirm</string>
<string name="transaction_abort">Abort</string>
<string name="transaction_success">Transaction successful</string>
<string name="transaction_error">Transaction error</string>
+ <string name="transaction_aborted">Transaction aborted</string>
<string name="transaction_button_back">Go back</string>
+ <string name="transaction_last_success">Last Transaction: %s
withdrawn</string>
+ <string name="transaction_last_aborted">Last Transaction: Aborted</string>
+ <string name="transaction_last_error">Last Transaction: Error</string>
</resources>
diff --git a/app/src/main/res/values/styles.xml
b/app/src/main/res/values/styles.xml
index 667fe05..84dfe74 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -7,10 +7,6 @@
<item name="colorSecondary">@color/colorAccent</item>
<item
name="colorOnSecondary">@color/design_default_color_background</item>
<item name="colorAccent">@color/colorAccent</item>
-
- <!-- https://stackoverflow.com/q/59081672/4856311 -->
- <item
name="actionOverflowMenuStyle">@style/Widget.MaterialComponents.PopupMenu.Overflow
- </item>
</style>
<style name="AppTheme.NoActionBar">
@@ -18,7 +14,9 @@
<item name="windowNoTitle">true</item>
</style>
- <style name="AppTheme.AppBarOverlay"
parent="ThemeOverlay.MaterialComponents.Dark.ActionBar" />
+ <style name="AppTheme.AppBarOverlay"
parent="ThemeOverlay.MaterialComponents.ActionBar" />
+
+ <style name="AppTheme.Toolbar"
parent="Widget.MaterialComponents.Toolbar.Primary" />
<style name="AmountButton" parent="Widget.MaterialComponents.Button">
<item name="android:minWidth">48dp</item>
diff --git a/artwork/ic_bottom_left.svg b/artwork/ic_bottom_left.svg
new file mode 100644
index 0000000..c3aa7e4
--- /dev/null
+++ b/artwork/ic_bottom_left.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="24"
+ version="1.1"
+ viewBox="0 0 24 24"
+ width="24"
+ id="svg4"
+ sodipodi:docname="ic_bottom_left.svg"
+ inkscape:version="0.92.4 (unknown)">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="982"
+ id="namedview6"
+ showgrid="false"
+ inkscape:zoom="9.8333333"
+ inkscape:cx="-10.728814"
+ inkscape:cy="12"
+ inkscape:window-x="1920"
+ inkscape:window-y="72"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg4" />
+ <path
+ d="M 20,5.41 18.59,4 7,15.59 V 9 H 5 V 19 H 15 V 17 H 8.41"
+ id="path2"
+ inkscape:connector-curvature="0"
+ style="fill:#000000" />
+</svg>
diff --git a/artwork/ic_bottom_right.svg b/artwork/ic_bottom_right.svg
new file mode 100644
index 0000000..26869ba
--- /dev/null
+++ b/artwork/ic_bottom_right.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="24"
+ version="1.1"
+ viewBox="0 0 24 24"
+ width="24"
+ id="svg4"
+ sodipodi:docname="ic_bottom_right.svg"
+ inkscape:version="0.92.4 (unknown)">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="982"
+ id="namedview6"
+ showgrid="false"
+ inkscape:zoom="9.8333333"
+ inkscape:cx="-10.728814"
+ inkscape:cy="12"
+ inkscape:window-x="1920"
+ inkscape:window-y="72"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg4" />
+ <path
+ d="M 5,5.41 6.41,4 18,15.59 V 9 h 2 V 19 H 10 v -2 h 6.59"
+ id="path2"
+ inkscape:connector-curvature="0"
+ style="fill:#000000" />
+</svg>
diff --git a/artwork/ic_launcher.svg b/artwork/ic_launcher.svg
new file mode 100644
index 0000000..4868fe4
--- /dev/null
+++ b/artwork/ic_launcher.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ id="svg4"
+ sodipodi:docname="ic_launcher.svg"
+ inkscape:version="0.92.4 (unknown)">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#000000"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="982"
+ id="namedview6"
+ showgrid="false"
+ inkscape:zoom="9.8333335"
+ inkscape:cx="-21.143993"
+ inkscape:cy="20.1778"
+ inkscape:window-x="1920"
+ inkscape:window-y="72"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg4" />
+ <path
+ d="M 6 3 L 6 6 L 9 6 L 9 7 L 6.25 7 C 5.05 7 4.0507812 8 4.0507812 9 L
3.5 16 L 20.5 16 L 20 9 C 19.8 8 18.800781 7 17.800781 7 L 11 7 L 11 6 L 14 6 L
14 3 L 6 3 z M 7 4 L 13 4 L 13 5 L 7 5 L 7 4 z M 6 9 L 8 9 L 8 10 L 6 10 L 6 9
z M 9 9 L 11 9 L 11 10 L 9 10 L 9 9 z M 13 9 L 18 9 L 18 11 L 13 11 L 13 9 z M
6 11 L 8 11 L 8 12 L 6 12 L 6 11 z M 9 11 L 11 11 L 11 12 L 9 12 L 9 11 z M 6
13 L 8 13 L 8 14 L 6 14 L 6 13 z M 9 13 L 11 13 L 11 14 L 9 14 L 9 13 z M 2 17
L 2 21 L 22 21 L 22 1 [...]
+ id="path2"
+ style="fill:#f9f9f9;fill-opacity:1" />
+</svg>
--
To stop receiving notification emails like this one, please contact
address@hidden.
- [taler-cashier-terminal-android] branch master updated (41dc9a4 -> a8307d0), gnunet, 2020/02/19
- [taler-cashier-terminal-android] 03/06: Get and save currency when doing configuration, gnunet, 2020/02/19
- [taler-cashier-terminal-android] 02/06: Use QR code and NFC to make taler:// Uri available, gnunet, 2020/02/19
- [taler-cashier-terminal-android] 01/06: Add screen for entering amount to withdraw, gnunet, 2020/02/19
- [taler-cashier-terminal-android] 04/06: First complete prototype, gnunet, 2020/02/19
- [taler-cashier-terminal-android] 05/06: Add app logo and optimize UX workflow,
gnunet <=
- [taler-cashier-terminal-android] 06/06: Add README, license and copyright headers, gnunet, 2020/02/19