diff options
Diffstat (limited to 'cashier/src/main/java/net/taler/cashier')
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, ) |