summaryrefslogtreecommitdiff
path: root/cashier/src/main/java/net/taler/cashier
diff options
context:
space:
mode:
Diffstat (limited to 'cashier/src/main/java/net/taler/cashier')
-rw-r--r--cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt18
-rw-r--r--cashier/src/main/java/net/taler/cashier/BalanceFragment.kt38
-rw-r--r--cashier/src/main/java/net/taler/cashier/HttpHelper.kt12
-rw-r--r--cashier/src/main/java/net/taler/cashier/MainActivity.kt1
-rw-r--r--cashier/src/main/java/net/taler/cashier/MainViewModel.kt23
-rw-r--r--cashier/src/main/java/net/taler/cashier/Response.kt7
-rw-r--r--cashier/src/main/java/net/taler/cashier/SignedAmount.kt10
-rw-r--r--cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt30
-rw-r--r--cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt12
-rw-r--r--cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt11
-rw-r--r--cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt14
-rw-r--r--cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt49
12 files changed, 124 insertions, 101 deletions
diff --git a/cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt b/cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt
index cdea792..90becbd 100644
--- a/cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt
@@ -17,20 +17,14 @@
package net.taler.cashier
import android.os.Bundle
-import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.view.WindowManager
-import android.widget.Button
-import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
-import androidx.fragment.app.Fragment
import net.taler.cashier.BuildConfig.VERSION_NAME
import net.taler.cashier.config.VERSION_BANK
import net.taler.cashier.databinding.FragmentAboutDialogBinding
-import net.taler.cashier.databinding.FragmentBalanceBinding
-import net.taler.lib.common.Version
+import net.taler.common.Version
class AboutDialogFragment : DialogFragment() {
@@ -39,8 +33,8 @@ class AboutDialogFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
+ savedInstanceState: Bundle?,
+ ): View {
ui = FragmentAboutDialogBinding.inflate(layoutInflater, container, false)
return ui.root
}
@@ -50,8 +44,10 @@ class AboutDialogFragment : DialogFragment() {
ui.versionView.text = getString(R.string.about_version, VERSION_NAME)
ui.bankVersionView.text = getString(R.string.about_supported_bank_api, VERSION_BANK.str())
- ui.licenseView.text = getString(R.string.about_license, getString(R.string.about_license_content))
- ui.copyrightView.text = getString(R.string.about_copyright, getString(R.string.about_copyright_holder))
+ ui.licenseView.text =
+ getString(R.string.about_license, getString(R.string.about_license_content))
+ ui.copyrightView.text =
+ getString(R.string.about_copyright, getString(R.string.about_copyright_holder))
ui.button.setOnClickListener { dismiss() }
}
diff --git a/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt b/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
index 002301c..4fd3143 100644
--- a/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
@@ -32,10 +32,10 @@ import net.taler.cashier.BalanceFragmentDirections.Companion.actionBalanceFragme
import net.taler.cashier.databinding.FragmentBalanceBinding
import net.taler.cashier.withdraw.LastTransaction
import net.taler.cashier.withdraw.WithdrawStatus
+import net.taler.common.Amount
import net.taler.common.exhaustive
import net.taler.common.fadeIn
import net.taler.common.fadeOut
-import net.taler.lib.common.Amount
sealed class BalanceResult {
class Error(val msg: String) : BalanceResult()
@@ -54,19 +54,19 @@ class BalanceFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
- ): View? {
+ ): View {
setHasOptionsMenu(true)
ui = FragmentBalanceBinding.inflate(layoutInflater, container, false)
return ui.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- withdrawManager.lastTransaction.observe(viewLifecycleOwner, { lastTransaction ->
+ withdrawManager.lastTransaction.observe(viewLifecycleOwner) { lastTransaction ->
onLastTransaction(lastTransaction)
- })
- viewModel.balance.observe(viewLifecycleOwner, { result ->
+ }
+ viewModel.balance.observe(viewLifecycleOwner) { result ->
onBalanceUpdated(result)
- })
+ }
ui.button5.setOnClickListener { onAmountButtonPressed(5) }
ui.button10.setOnClickListener { onAmountButtonPressed(10) }
ui.button20.setOnClickListener { onAmountButtonPressed(20) }
@@ -81,9 +81,9 @@ class BalanceFragment : Fragment() {
true
} else false
}
- configManager.currency.observe(viewLifecycleOwner, { currency ->
+ configManager.currency.observe(viewLifecycleOwner) { currency ->
ui.currencyView.text = currency
- })
+ }
ui.confirmWithdrawalButton.setOnClickListener { onAmountConfirmed(getAmountFromView()) }
}
@@ -104,11 +104,13 @@ class BalanceFragment : Fragment() {
}
}
+ @Deprecated("Deprecated in Java")
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.balance, menu)
super.onCreateOptionsMenu(menu, inflater)
}
+ @Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.action_reconfigure -> {
findNavController().navigate(configManager.configDestination)
@@ -164,13 +166,19 @@ class BalanceFragment : Fragment() {
private fun onAmountConfirmed(amount: Amount) {
if (amount.isZero()) {
ui.amountView.error = getString(R.string.withdraw_error_zero)
- } else if (!withdrawManager.hasSufficientBalance(amount)) {
- ui.amountView.error = getString(R.string.withdraw_error_insufficient_balance)
- } else {
- ui.amountView.error = null
- withdrawManager.withdraw(amount)
- actionBalanceFragmentToTransactionFragment().let {
- findNavController().navigate(it)
+ } else when (withdrawManager.hasSufficientBalance(amount)) {
+ true -> {
+ ui.amountView.error = null
+ withdrawManager.withdraw(amount)
+ actionBalanceFragmentToTransactionFragment().let {
+ findNavController().navigate(it)
+ }
+ }
+ false -> {
+ ui.amountView.error = getString(R.string.withdraw_error_insufficient_balance)
+ }
+ null -> {
+ ui.amountView.error = getString(R.string.withdraw_error_currency_mismatch)
}
}
}
diff --git a/cashier/src/main/java/net/taler/cashier/HttpHelper.kt b/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
index fd48b2d..69cc46f 100644
--- a/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
+++ b/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
@@ -50,11 +50,13 @@ object HttpHelper {
Log.e(TAG, "Error retrieving $url", e)
return HttpJsonResult.Error(0)
}
- return if (response.code == 200 && response.body != null) {
+ return if (response.code == 204) {
+ HttpJsonResult.Success(JSONObject())
+ } else if (response.code in 200..299 && response.body != null) {
val jsonObject = JSONObject(response.body!!.string())
HttpJsonResult.Success(jsonObject)
} else {
- Log.e(TAG, "Received status ${response.code} from $url expected 200")
+ Log.e(TAG, "Received status ${response.code} from $url expected 2xx")
HttpJsonResult.Error(response.code, getErrorBody(response))
}
}
@@ -76,11 +78,13 @@ object HttpHelper {
Log.e(TAG, "Error retrieving $url", e)
return HttpJsonResult.Error(0)
}
- return if (response.code == 200 && response.body != null) {
+ return if (response.code == 204) {
+ HttpJsonResult.Success(JSONObject())
+ } else if (response.code in 200..299 && response.body != null) {
val jsonObject = JSONObject(response.body!!.string())
HttpJsonResult.Success(jsonObject)
} else {
- Log.e(TAG, "Received status ${response.code} from $url expected 200")
+ Log.e(TAG, "Received status ${response.code} from $url expected 2xx")
HttpJsonResult.Error(response.code, getErrorBody(response))
}
}
diff --git a/cashier/src/main/java/net/taler/cashier/MainActivity.kt b/cashier/src/main/java/net/taler/cashier/MainActivity.kt
index 2f4c4ec..aacc225 100644
--- a/cashier/src/main/java/net/taler/cashier/MainActivity.kt
+++ b/cashier/src/main/java/net/taler/cashier/MainActivity.kt
@@ -52,6 +52,7 @@ class MainActivity : AppCompatActivity() {
}
}
+ @Deprecated("Deprecated in Java")
override fun onBackPressed() {
if (!configManager.hasConfig() && nav.currentDestination?.id == R.id.configFragment) {
// we are in the configuration screen and need a config to continue
diff --git a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
index 253c7d5..2196e78 100644
--- a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
+++ b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
@@ -24,17 +24,17 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import io.ktor.client.HttpClient
import io.ktor.client.engine.okhttp.OkHttp
-import io.ktor.client.features.json.JsonFeature
-import io.ktor.client.features.json.serializer.KotlinxSerializer
+import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
+import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import net.taler.cashier.HttpHelper.makeJsonGetRequest
import net.taler.cashier.config.ConfigManager
import net.taler.cashier.withdraw.WithdrawManager
+import net.taler.common.Amount
+import net.taler.common.AmountParserException
import net.taler.common.isOnline
-import net.taler.lib.common.Amount
-import net.taler.lib.common.AmountParserException
private val TAG = MainViewModel::class.java.simpleName
@@ -46,12 +46,12 @@ class MainViewModel(private val app: Application) : AndroidViewModel(app) {
retryOnConnectionFailure(true)
}
}
- install(JsonFeature) {
- serializer = KotlinxSerializer(
- Json {
- ignoreUnknownKeys = true
- }
- )
+ expectSuccess = true
+ install(ContentNegotiation) {
+ json(Json {
+ encodeDefaults = false
+ ignoreUnknownKeys = true
+ })
}
}
val configManager = ConfigManager(app, viewModelScope, httpClient)
@@ -77,7 +77,8 @@ class MainViewModel(private val app: Application) : AndroidViewModel(app) {
"debit" -> false
else -> throw AmountParserException("Unexpected credit_debit_indicator: $creditDebitIndicator")
}
- BalanceResult.Success(SignedAmount(positive, Amount.fromJSONString(balanceAmount)))
+ BalanceResult.Success(SignedAmount(positive,
+ Amount.fromJSONString(balanceAmount)))
} catch (e: Exception) {
Log.e(TAG, "Error parsing balance", e)
BalanceResult.Error("Invalid amount:\n${response.json.toString(2)}")
diff --git a/cashier/src/main/java/net/taler/cashier/Response.kt b/cashier/src/main/java/net/taler/cashier/Response.kt
index 6a72604..e9db447 100644
--- a/cashier/src/main/java/net/taler/cashier/Response.kt
+++ b/cashier/src/main/java/net/taler/cashier/Response.kt
@@ -18,8 +18,8 @@ package net.taler.cashier
import android.content.Context
import android.util.Log
-import io.ktor.client.call.receive
-import io.ktor.client.features.ResponseException
+import io.ktor.client.call.body
+import io.ktor.client.plugins.ResponseException
import io.ktor.http.HttpStatusCode
import kotlinx.serialization.Serializable
import net.taler.common.isOnline
@@ -46,8 +46,7 @@ class Response<out T> private constructor(
private suspend fun getExceptionString(e: ResponseException): String {
val response = e.response
return try {
- Log.e("TEST", "TRY RECEIVE $response")
- val error: Error = response.receive()
+ val error: Error = response.body()
"Error ${error.code}: ${error.hint}"
} catch (ex: Exception) {
"Status code: ${response.status.value}"
diff --git a/cashier/src/main/java/net/taler/cashier/SignedAmount.kt b/cashier/src/main/java/net/taler/cashier/SignedAmount.kt
index e79acfd..45bc3af 100644
--- a/cashier/src/main/java/net/taler/cashier/SignedAmount.kt
+++ b/cashier/src/main/java/net/taler/cashier/SignedAmount.kt
@@ -16,15 +16,17 @@
package net.taler.cashier
-import net.taler.lib.common.Amount
+import net.taler.common.Amount
data class SignedAmount(
val positive: Boolean,
val amount: Amount
) {
- override fun toString(): String {
- return if (positive) "$amount" else "-$amount"
- }
+ override fun toString() = toString(showSymbol = true)
+ fun toString(showSymbol: Boolean) = amount.toString(
+ showSymbol = showSymbol,
+ negative = !positive,
+ )
}
diff --git a/cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt b/cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt
index e6ac249..3085bef 100644
--- a/cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt
@@ -37,22 +37,23 @@ import net.taler.cashier.MainViewModel
import net.taler.cashier.R
import net.taler.cashier.databinding.FragmentConfigBinding
import net.taler.common.exhaustive
+import net.taler.common.showError
-private const val URL_BANK_TEST = "https://bank.test.taler.net"
-private const val URL_BANK_TEST_REGISTER = "$URL_BANK_TEST/accounts/register"
+private const val URL_BANK_TEST = "https://bank.demo.taler.net"
+private const val URL_BANK_TEST_REGISTER = "https://bank.demo.taler.net/webui/#/register"
class ConfigFragment : Fragment() {
private val viewModel: MainViewModel by activityViewModels()
- private val configManager by lazy { viewModel.configManager}
+ private val configManager by lazy { viewModel.configManager }
private lateinit var ui: FragmentConfigBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
+ savedInstanceState: Bundle?,
+ ): View {
ui = FragmentConfigBinding.inflate(inflater, container, false)
return ui.root
}
@@ -73,9 +74,9 @@ class ConfigFragment : Fragment() {
}
ui.saveButton.setOnClickListener {
val config = Config(
- bankUrl = ui.urlView.editText!!.text.toString(),
- username = ui.usernameView.editText!!.text.toString(),
- password = ui.passwordView.editText!!.text.toString()
+ bankUrl = ui.urlView.editText!!.text.toString().trim(),
+ username = ui.usernameView.editText!!.text.toString().trim(),
+ password = ui.passwordView.editText!!.text.toString().trim()
)
if (checkConfig(config)) {
// show progress
@@ -110,13 +111,15 @@ class ConfigFragment : Fragment() {
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// for some reason automatic restore isn't working at the moment!?
- outState.putCharSequence("urlView", ui.urlView.editText?.text)
- outState.putCharSequence("usernameView", ui.usernameView.editText?.text)
- outState.putCharSequence("passwordView", ui.passwordView.editText?.text)
+ outState.putCharSequence("urlView", ui.urlView.editText?.text?.trim())
+ outState.putCharSequence("usernameView", ui.usernameView.editText?.text?.trim())
+ outState.putCharSequence("passwordView", ui.passwordView.editText?.text?.trim())
}
private fun checkConfig(config: Config): Boolean {
- if (!config.bankUrl.startsWith("https://")) {
+ if (!config.bankUrl.startsWith("https://") &&
+ !config.bankUrl.startsWith("http://")
+ ) {
ui.urlView.error = getString(R.string.config_bank_url_error)
ui.urlView.requestFocus()
return false
@@ -144,8 +147,7 @@ class ConfigFragment : Fragment() {
if (result.authError) {
Snackbar.make(requireView(), R.string.config_error_auth, LENGTH_LONG).show()
} else {
- val str = getString(R.string.config_error, result.msg)
- Snackbar.make(requireView(), str, LENGTH_LONG).show()
+ requireActivity().showError(getString(R.string.config_error), result.msg)
}
}
}.exhaustive
diff --git a/cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt b/cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt
index 0718963..50b1faf 100644
--- a/cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt
+++ b/cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt
@@ -29,6 +29,7 @@ import androidx.security.crypto.EncryptedSharedPreferences.PrefValueEncryptionSc
import androidx.security.crypto.MasterKeys
import androidx.security.crypto.MasterKeys.AES256_GCM_SPEC
import io.ktor.client.HttpClient
+import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.request.header
import io.ktor.http.HttpHeaders.Authorization
@@ -37,12 +38,13 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import net.taler.cashier.BuildConfig
import net.taler.cashier.Response
import net.taler.cashier.Response.Companion.response
+import net.taler.common.Version
import net.taler.common.getIncompatibleStringOrNull
-import net.taler.lib.common.Version
-val VERSION_BANK = Version(0, 0, 0)
+val VERSION_BANK = Version.parse(BuildConfig.BACKEND_API_VERSION)!!
private const val PREF_NAME = "net.taler.cashier.prefs"
private const val PREF_KEY_BANK_URL = "bankUrl"
private const val PREF_KEY_USERNAME = "username"
@@ -54,7 +56,7 @@ private val TAG = ConfigManager::class.java.simpleName
class ConfigManager(
private val app: Application,
private val scope: CoroutineScope,
- private val httpClient: HttpClient
+ private val httpClient: HttpClient,
) {
val configDestination = ConfigFragmentDirections.actionGlobalConfigFragment()
@@ -116,7 +118,7 @@ class ConfigManager(
val url = "${config.bankUrl}/config"
Log.d(TAG, "Checking config: $url")
val configResponse = response {
- httpClient.get(url) as ConfigResponse
+ httpClient.get(url).body<ConfigResponse>()
}
if (configResponse.isFailure) {
configResponse
@@ -126,7 +128,7 @@ class ConfigManager(
val balanceResponse = response {
val authUrl = "${config.bankUrl}/accounts/${config.username}"
Log.d(TAG, "Checking auth: $authUrl")
- httpClient.get<Unit>(authUrl) {
+ httpClient.get(authUrl) {
header(Authorization, config.basicAuth)
}
}
diff --git a/cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt b/cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
index 4f98847..c951bb8 100644
--- a/cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
@@ -22,7 +22,6 @@ 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 net.taler.cashier.MainViewModel
import net.taler.cashier.R
@@ -37,22 +36,22 @@ class ErrorFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
+ savedInstanceState: Bundle?,
+ ): View {
ui = FragmentErrorBinding.inflate(inflater, container, false)
return ui.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer { status ->
- if (status == null) return@Observer
+ withdrawManager.withdrawStatus.observe(viewLifecycleOwner) { status ->
+ if (status == null) return@observe
if (status is WithdrawStatus.Aborted) {
ui.textView.setText(R.string.transaction_aborted)
} else if (status is WithdrawStatus.Error) {
ui.textView.text = status.msg
}
withdrawManager.completeTransaction()
- })
+ }
ui.backButton.setOnClickListener {
findNavController().popBackStack()
}
diff --git a/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt b/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
index ffb1539..0f606b8 100644
--- a/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
@@ -50,21 +50,21 @@ class TransactionFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
- ): View? {
+ ): View {
ui = FragmentTransactionBinding.inflate(inflater, container, false)
return ui.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- withdrawManager.withdrawAmount.observe(viewLifecycleOwner, { amount ->
+ withdrawManager.withdrawAmount.observe(viewLifecycleOwner) { amount ->
ui.amountView.text = amount?.toString()
- })
- withdrawManager.withdrawResult.observe(viewLifecycleOwner, { result ->
+ }
+ withdrawManager.withdrawResult.observe(viewLifecycleOwner) { result ->
onWithdrawResultReceived(result)
- })
- withdrawManager.withdrawStatus.observe(viewLifecycleOwner, { status ->
+ }
+ withdrawManager.withdrawStatus.observe(viewLifecycleOwner) { status ->
onWithdrawStatusChanged(status)
- })
+ }
// change intro text depending on whether NFC is available or not
val hasNfc = NfcManager.hasNfc(requireContext())
diff --git a/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt b/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
index 5d34bba..487475d 100644
--- a/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
+++ b/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
@@ -34,21 +34,19 @@ import net.taler.cashier.HttpJsonResult.Error
import net.taler.cashier.HttpJsonResult.Success
import net.taler.cashier.MainViewModel
import net.taler.cashier.R
+import net.taler.common.Amount
import net.taler.common.QrCodeManager.makeQrCode
import net.taler.common.isOnline
-import net.taler.lib.common.Amount
import org.json.JSONObject
-import java.util.concurrent.TimeUnit.MINUTES
import java.util.concurrent.TimeUnit.SECONDS
private val TAG = WithdrawManager::class.java.simpleName
private val INTERVAL = SECONDS.toMillis(1)
-private val TIMEOUT = MINUTES.toMillis(2)
class WithdrawManager(
private val app: Application,
- private val viewModel: MainViewModel
+ private val viewModel: MainViewModel,
) {
private val scope
get() = viewModel.viewModelScope
@@ -73,11 +71,20 @@ class WithdrawManager(
private val mLastTransaction = MutableLiveData<LastTransaction>()
val lastTransaction: LiveData<LastTransaction> = mLastTransaction
+ /**
+ * Returns null if the given [amount] can't be compared to the balance
+ * e.g. due to mismatching currency.
+ */
@UiThread
- fun hasSufficientBalance(amount: Amount): Boolean {
+ fun hasSufficientBalance(amount: Amount): Boolean? {
val balanceResult = viewModel.balance.value
if (balanceResult !is BalanceResult.Success) return false
- return balanceResult.amount.positive && amount <= balanceResult.amount.amount
+ return try {
+ balanceResult.amount.positive && amount <= balanceResult.amount.amount
+ } catch (e: IllegalStateException) {
+ Log.e(TAG, "Error comparing amounts", e)
+ null
+ }
}
@UiThread
@@ -119,7 +126,7 @@ class WithdrawManager(
}
}
- private val timer: CountDownTimer = object : CountDownTimer(TIMEOUT, INTERVAL) {
+ private val timer: CountDownTimer = object : CountDownTimer(Long.MAX_VALUE, INTERVAL) {
override fun onTick(millisUntilFinished: Long) {
val result = withdrawResult.value
if (result is WithdrawResult.Success) {
@@ -146,31 +153,32 @@ class WithdrawManager(
}
private fun checkWithdrawStatus(withdrawalId: String) = scope.launch(Dispatchers.IO) {
- val url = "${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}"
+ val url =
+ "${config.bankUrl}/withdrawals/${withdrawalId}"
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
try {
- when {
- response.json.getBoolean("aborted") -> {
+ when(response.json.getString("status")) {
+ "selected" -> {
+ // 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))
+ }
+ }
+ "aborted" -> {
cancelWithdrawStatusCheck()
mWithdrawStatus.postValue(WithdrawStatus.Aborted)
}
- response.json.getBoolean("confirmation_done") -> {
+ "confirmed" -> {
if (oldStatus !is WithdrawStatus.Success) {
cancelWithdrawStatusCheck()
mWithdrawStatus.postValue(WithdrawStatus.Success)
viewModel.getBalance()
}
}
- response.json.getBoolean("selection_done") -> {
- // 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))
- }
- }
}
} catch (e: Exception) {
mWithdrawStatus.postValue(WithdrawStatus.Error(e.toString()))
@@ -197,7 +205,8 @@ class WithdrawManager(
}
private fun abort(withdrawalId: String) = scope.launch(Dispatchers.IO) {
- val url = "${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}/abort"
+ val url =
+ "${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}/abort"
Log.d(TAG, "Aborting withdrawal at $url")
makeJsonPostRequest(url, JSONObject(), config)
}
@@ -254,5 +263,5 @@ sealed class WithdrawStatus {
data class LastTransaction(
val withdrawAmount: Amount,
- val withdrawStatus: WithdrawStatus
+ val withdrawStatus: WithdrawStatus,
)