From e19ba096d57353db6b1f141da4bf170ef2d2d534 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 29 Jul 2020 14:12:50 -0300 Subject: [wallet] update to new wallet-core with v8 exchange API (except payments which are still buggy) --- .../java/net/taler/wallet/withdraw/ExchangeFees.kt | 95 --------- .../wallet/withdraw/ManualWithdrawFragment.kt | 2 +- .../wallet/withdraw/PromptWithdrawFragment.kt | 26 ++- .../wallet/withdraw/ReviewExchangeTosFragment.kt | 2 +- .../wallet/withdraw/SelectExchangeFragment.kt | 142 ------------- .../net/taler/wallet/withdraw/WithdrawManager.kt | 227 ++++++++++----------- 6 files changed, 126 insertions(+), 368 deletions(-) delete mode 100644 wallet/src/main/java/net/taler/wallet/withdraw/ExchangeFees.kt delete mode 100644 wallet/src/main/java/net/taler/wallet/withdraw/SelectExchangeFragment.kt (limited to 'wallet/src/main/java/net/taler/wallet/withdraw') diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/ExchangeFees.kt b/wallet/src/main/java/net/taler/wallet/withdraw/ExchangeFees.kt deleted file mode 100644 index 9c815c9..0000000 --- a/wallet/src/main/java/net/taler/wallet/withdraw/ExchangeFees.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This file is part of GNU Taler - * (C) 2020 Taler Systems S.A. - * - * GNU Taler is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation; either version 3, or (at your option) any later version. - * - * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * GNU Taler; see the file COPYING. If not, see - */ - -package net.taler.wallet.withdraw - -import net.taler.common.Amount -import net.taler.common.Timestamp -import org.json.JSONObject - -data class CoinFee( - val coin: Amount, - val quantity: Int, - val feeDeposit: Amount, - val feeRefresh: Amount, - val feeRefund: Amount, - val feeWithdraw: Amount -) - -data class WireFee( - val start: Timestamp, - val end: Timestamp, - val wireFee: Amount, - val closingFee: Amount -) - -data class ExchangeFees( - val withdrawFee: Amount, - val overhead: Amount, - val earliestDepositExpiration: Timestamp, - val coinFees: List, - val wireFees: List -) { - companion object { - fun fromExchangeWithdrawDetailsJson(json: JSONObject): ExchangeFees { - val earliestDepositExpiration = - json.getJSONObject("earliestDepositExpiration").getLong("t_ms") - val selectedDenoms = json.getJSONObject("selectedDenoms") - val denoms = selectedDenoms.getJSONArray("selectedDenoms") - val coinFees = ArrayList(denoms.length()) - for (i in 0 until denoms.length()) { - val denom = denoms.getJSONObject(i) - val d = denom.getJSONObject("denom") - val coinFee = CoinFee( - coin = Amount.fromJsonObject(d.getJSONObject("value")), - quantity = denom.getInt("count"), - feeDeposit = Amount.fromJsonObject(d.getJSONObject("feeDeposit")), - feeRefresh = Amount.fromJsonObject(d.getJSONObject("feeRefresh")), - feeRefund = Amount.fromJsonObject(d.getJSONObject("feeRefund")), - feeWithdraw = Amount.fromJsonObject(d.getJSONObject("feeWithdraw")) - ) - coinFees.add(coinFee) - } - - val wireFeesJson = json.getJSONObject("wireFees") - val feesForType = wireFeesJson.getJSONObject("feesForType") - val bankFees = feesForType.getJSONArray("x-taler-bank") - val wireFees = ArrayList(bankFees.length()) - for (i in 0 until bankFees.length()) { - val fee = bankFees.getJSONObject(i) - val startStamp = - fee.getJSONObject("startStamp").getLong("t_ms") - val endStamp = - fee.getJSONObject("endStamp").getLong("t_ms") - val wireFee = WireFee( - start = Timestamp(startStamp), - end = Timestamp(endStamp), - wireFee = Amount.fromJsonObject(fee.getJSONObject("wireFee")), - closingFee = Amount.fromJsonObject(fee.getJSONObject("closingFee")) - ) - wireFees.add(wireFee) - } - - return ExchangeFees( - withdrawFee = Amount.fromJsonObject(json.getJSONObject("withdrawFee")), - overhead = Amount.fromJsonObject(json.getJSONObject("overhead")), - earliestDepositExpiration = Timestamp(earliestDepositExpiration), - coinFees = coinFees, - wireFees = wireFees - ) - } - } -} diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt index 55f931d..9788d1c 100644 --- a/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/withdraw/ManualWithdrawFragment.kt @@ -60,7 +60,7 @@ class ManualWithdrawFragment : Fragment() { val amount = Amount(exchangeItem.currency, value, 0) amountView.hideKeyboard() Toast.makeText(view.context, "Not implemented: $amount", LENGTH_SHORT).show() - withdrawManager.getWithdrawalDetails(exchangeItem, amount) + withdrawManager.getWithdrawalDetails(exchangeItem.exchangeBaseUrl, amount) } } diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt index 331554b..5a98a89 100644 --- a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt @@ -20,6 +20,8 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast +import android.widget.Toast.LENGTH_SHORT import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.Observer @@ -34,7 +36,7 @@ import net.taler.wallet.MainViewModel import net.taler.wallet.R import net.taler.wallet.cleanExchange import net.taler.wallet.withdraw.WithdrawStatus.Loading -import net.taler.wallet.withdraw.WithdrawStatus.TermsOfServiceReviewRequired +import net.taler.wallet.withdraw.WithdrawStatus.TosReviewRequired import net.taler.wallet.withdraw.WithdrawStatus.Withdrawing class PromptWithdrawFragment : Fragment() { @@ -59,17 +61,13 @@ class PromptWithdrawFragment : Fragment() { private fun showWithdrawStatus(status: WithdrawStatus?): Any = when (status) { is WithdrawStatus.ReceivedDetails -> { - showContent(status.amount, status.fee, status.exchange) + showContent(status.amountRaw, status.amountEffective, status.exchangeBaseUrl) confirmWithdrawButton.apply { text = getString(R.string.withdraw_button_confirm) setOnClickListener { it.fadeOut() confirmProgressBar.fadeIn() - withdrawManager.acceptWithdrawal( - status.talerWithdrawUri, - status.exchange, - status.amount.currency - ) + withdrawManager.acceptWithdrawal() } isEnabled = true } @@ -87,8 +85,8 @@ class PromptWithdrawFragment : Fragment() { is Withdrawing -> { model.showProgressBar.value = true } - is TermsOfServiceReviewRequired -> { - showContent(status.amount, status.fee, status.exchange) + is TosReviewRequired -> { + showContent(status.amountRaw, status.amountEffective, status.exchangeBaseUrl) confirmWithdrawButton.apply { text = getString(R.string.withdraw_button_tos) setOnClickListener { @@ -104,20 +102,20 @@ class PromptWithdrawFragment : Fragment() { null -> model.showProgressBar.value = false } - private fun showContent(amount: Amount, fee: Amount, exchange: String) { + private fun showContent(amountRaw: Amount, amountEffective: Amount, exchange: String) { model.showProgressBar.value = false progressBar.fadeOut() introView.fadeIn() - effectiveAmountView.text = (amount - fee).toString() + effectiveAmountView.text = amountEffective.toString() effectiveAmountView.fadeIn() chosenAmountLabel.fadeIn() - chosenAmountView.text = amount.toString() + chosenAmountView.text = amountRaw.toString() chosenAmountView.fadeIn() feeLabel.fadeIn() - feeView.text = getString(R.string.amount_negative, fee.toString()) + feeView.text = getString(R.string.amount_negative, (amountRaw - amountEffective).toString()) feeView.fadeIn() exchangeIntroView.fadeIn() @@ -125,7 +123,7 @@ class PromptWithdrawFragment : Fragment() { withdrawExchangeUrl.fadeIn() selectExchangeButton.fadeIn() selectExchangeButton.setOnClickListener { - findNavController().navigate(R.id.action_promptWithdraw_to_selectExchangeFragment) + Toast.makeText(context, "Not yet implemented", LENGTH_SHORT).show() } withdrawCard.fadeIn() diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt index ffaef5a..db1f326 100644 --- a/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt @@ -55,7 +55,7 @@ class ReviewExchangeTosFragment : Fragment() { } withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer { when (it) { - is WithdrawStatus.TermsOfServiceReviewRequired -> { + is WithdrawStatus.TosReviewRequired -> { val sections = try { // TODO remove next line once exchange delivers proper markdown val text = it.tosText.replace("****************", "================") diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/SelectExchangeFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/SelectExchangeFragment.kt deleted file mode 100644 index 2ade9f2..0000000 --- a/wallet/src/main/java/net/taler/wallet/withdraw/SelectExchangeFragment.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of GNU Taler - * (C) 2020 Taler Systems S.A. - * - * GNU Taler is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation; either version 3, or (at your option) any later version. - * - * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * GNU Taler; see the file COPYING. If not, see - */ - -package net.taler.wallet.withdraw - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.View.GONE -import android.view.ViewGroup -import android.widget.TextView -import androidx.core.content.ContextCompat.getColor -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.recyclerview.widget.RecyclerView.Adapter -import androidx.recyclerview.widget.RecyclerView.ViewHolder -import kotlinx.android.synthetic.main.fragment_select_exchange.* -import net.taler.common.Amount -import net.taler.common.toRelativeTime -import net.taler.common.toShortDate -import net.taler.wallet.MainViewModel -import net.taler.wallet.R -import net.taler.wallet.withdraw.CoinFeeAdapter.CoinFeeViewHolder -import net.taler.wallet.withdraw.WireFeeAdapter.WireFeeViewHolder - -class SelectExchangeFragment : Fragment() { - - private val model: MainViewModel by activityViewModels() - private val withdrawManager by lazy { model.withdrawManager } - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.fragment_select_exchange, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val fees = withdrawManager.exchangeFees ?: throw IllegalStateException() - if (fees.withdrawFee.isZero()) { - withdrawFeeLabel.visibility = GONE - withdrawFeeView.visibility = GONE - } else withdrawFeeView.setAmount(fees.withdrawFee) - if (fees.overhead.isZero()) { - overheadLabel.visibility = GONE - overheadView.visibility = GONE - } else overheadView.setAmount(fees.overhead) - expirationView.text = fees.earliestDepositExpiration.ms.toRelativeTime(requireContext()) - coinFeesList.adapter = CoinFeeAdapter(fees.coinFees) - wireFeesList.adapter = WireFeeAdapter(fees.wireFees) - } - - private fun TextView.setAmount(amount: Amount) { - if (amount.isZero()) text = amount.toString() - else { - text = getString(R.string.amount_negative, amount) - setTextColor(getColor(context, R.color.red)) - } - } - -} - -private class CoinFeeAdapter(private val items: List) : Adapter() { - override fun getItemCount() = items.size - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CoinFeeViewHolder { - val v = - LayoutInflater.from(parent.context).inflate(R.layout.list_item_coin_fee, parent, false) - return CoinFeeViewHolder(v) - } - - override fun onBindViewHolder(holder: CoinFeeViewHolder, position: Int) { - holder.bind(items[position]) - } - - private class CoinFeeViewHolder(private val v: View) : ViewHolder(v) { - private val res = v.context.resources - private val coinView: TextView = v.findViewById(R.id.coinView) - private val withdrawFeeView: TextView = v.findViewById(R.id.withdrawFeeView) - private val depositFeeView: TextView = v.findViewById(R.id.depositFeeView) - private val refreshFeeView: TextView = v.findViewById(R.id.refreshFeeView) - private val refundFeeView: TextView = v.findViewById(R.id.refundFeeView) - fun bind(item: CoinFee) { - coinView.text = res.getQuantityString( - R.plurals.exchange_fee_coin, - item.quantity, - item.coin, - item.quantity - ) - withdrawFeeView.text = - v.context.getString(R.string.exchange_fee_withdraw_fee, item.feeWithdraw) - depositFeeView.text = - v.context.getString(R.string.exchange_fee_deposit_fee, item.feeDeposit) - refreshFeeView.text = - v.context.getString(R.string.exchange_fee_refresh_fee, item.feeRefresh) - refundFeeView.text = - v.context.getString(R.string.exchange_fee_refund_fee, item.feeRefresh) - } - } -} - -private class WireFeeAdapter(private val items: List) : Adapter() { - override fun getItemCount() = items.size - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WireFeeViewHolder { - val v = - LayoutInflater.from(parent.context).inflate(R.layout.list_item_wire_fee, parent, false) - return WireFeeViewHolder(v) - } - - override fun onBindViewHolder(holder: WireFeeViewHolder, position: Int) { - holder.bind(items[position]) - } - - private class WireFeeViewHolder(private val v: View) : ViewHolder(v) { - private val validityView: TextView = v.findViewById(R.id.validityView) - private val wireFeeView: TextView = v.findViewById(R.id.wireFeeView) - private val closingFeeView: TextView = v.findViewById(R.id.closingFeeView) - fun bind(item: WireFee) { - validityView.text = v.context.getString( - R.string.exchange_fee_wire_fee_timespan, - item.start.ms.toShortDate(v.context), - item.end.ms.toShortDate(v.context) - ) - wireFeeView.text = - v.context.getString(R.string.exchange_fee_wire_fee_wire_fee, item.wireFee) - closingFeeView.text = - v.context.getString(R.string.exchange_fee_wire_fee_closing_fee, item.closingFee) - } - } -} diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt index ea65e7c..e14a747 100644 --- a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt +++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt @@ -17,38 +17,57 @@ package net.taler.wallet.withdraw import android.util.Log +import androidx.annotation.UiThread import androidx.lifecycle.MutableLiveData +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue import net.taler.common.Amount import net.taler.wallet.TAG import net.taler.wallet.backend.WalletBackendApi +import net.taler.wallet.exchanges.ExchangeFees import net.taler.wallet.exchanges.ExchangeItem import net.taler.wallet.withdraw.WithdrawStatus.ReceivedDetails import org.json.JSONObject sealed class WithdrawStatus { - data class Loading(val talerWithdrawUri: String) : WithdrawStatus() - data class TermsOfServiceReviewRequired( - val talerWithdrawUri: String, - val exchange: String, + data class Loading(val talerWithdrawUri: String? = null) : WithdrawStatus() + data class TosReviewRequired( + val talerWithdrawUri: String? = null, + val exchangeBaseUrl: String, + val amountRaw: Amount, + val amountEffective: Amount, val tosText: String, - val tosEtag: String, - val amount: Amount, - val fee: Amount + val tosEtag: String ) : WithdrawStatus() data class ReceivedDetails( - val talerWithdrawUri: String, - val exchange: String, - val amount: Amount, - val fee: Amount + val talerWithdrawUri: String? = null, + val exchangeBaseUrl: String, + val amountRaw: Amount, + val amountEffective: Amount ) : WithdrawStatus() - data class Withdrawing(val talerWithdrawUri: String) : WithdrawStatus() + object Withdrawing : WithdrawStatus() data class Success(val currency: String) : WithdrawStatus() data class Error(val message: String?) : WithdrawStatus() } -class WithdrawManager(private val walletBackendApi: WalletBackendApi) { +data class WithdrawalDetailsForUri( + val amount: Amount, + val defaultExchangeBaseUrl: String?, + val possibleExchanges: List +) + +data class WithdrawalDetails( + val tosAccepted: Boolean, + val amountRaw: Amount, + val amountEffective: Amount +) + +class WithdrawManager( + private val walletBackendApi: WalletBackendApi, + private val mapper: ObjectMapper +) { val withdrawStatus = MutableLiveData() val testWithdrawalInProgress = MutableLiveData(false) @@ -58,149 +77,127 @@ class WithdrawManager(private val walletBackendApi: WalletBackendApi) { fun withdrawTestkudos() { testWithdrawalInProgress.value = true - - walletBackendApi.sendRequest("withdrawTestkudos", null) { _, _ -> + walletBackendApi.sendRequest("withdrawTestkudos") { _, _ -> testWithdrawalInProgress.postValue(false) } } - fun getWithdrawalDetails(exchangeItem: ExchangeItem, amount: Amount) { + fun getWithdrawalDetails(uri: String) { + withdrawStatus.value = WithdrawStatus.Loading(uri) val args = JSONObject().apply { - put("exchangeBaseUrl", exchangeItem.exchangeBaseUrl) - put("amount", amount.toJSONString()) + put("talerWithdrawUri", uri) } - walletBackendApi.sendRequest("getWithdrawalDetailsForAmount", args) { isError, result -> - // {"rawAmount":"TESTKUDOS:5","effectiveAmount":"TESTKUDOS:4.8","paytoUris":["payto:\/\/x-taler-bank\/bank.test.taler.net\/Exchange"],"tosAccepted":false} + walletBackendApi.sendRequest("getWithdrawalDetailsForUri", args) { isError, result -> if (isError) { - Log.e(TAG, "$result") + handleError("getWithdrawalDetailsForUri", result) + return@sendRequest + } + val details: WithdrawalDetailsForUri = mapper.readValue(result.toString()) + if (details.defaultExchangeBaseUrl == null) { + // TODO go to exchange selection screen instead + val chosenExchange = details.possibleExchanges[0].exchangeBaseUrl + getWithdrawalDetails(chosenExchange, details.amount, uri) } else { - Log.e(TAG, "$result") + getWithdrawalDetails(details.defaultExchangeBaseUrl, details.amount, uri) } } } - fun getWithdrawalInfo(talerWithdrawUri: String) { + fun getWithdrawalDetails(exchangeBaseUrl: String, amount: Amount, uri: String? = null) { + withdrawStatus.value = WithdrawStatus.Loading(uri) val args = JSONObject().apply { - put("talerWithdrawUri", talerWithdrawUri) + put("exchangeBaseUrl", exchangeBaseUrl) + put("amount", amount.toJSONString()) } - withdrawStatus.value = WithdrawStatus.Loading(talerWithdrawUri) - - walletBackendApi.sendRequest("getWithdrawDetailsForUri", args) { isError, result -> + walletBackendApi.sendRequest("getWithdrawalDetailsForAmount", args) { isError, result -> if (isError) { - Log.e(TAG, "Error getWithdrawDetailsForUri ${result.toString(4)}") - val message = if (result.has("message")) result.getString("message") else null - withdrawStatus.postValue(WithdrawStatus.Error(message)) + handleError("getWithdrawalDetailsForAmount", result) return@sendRequest } - Log.v(TAG, "got getWithdrawDetailsForUri result") - val status = withdrawStatus.value - if (status !is WithdrawStatus.Loading) { - Log.v(TAG, "ignoring withdrawal info result, not loading.") - return@sendRequest - } - val wi = result.getJSONObject("bankWithdrawDetails") - val suggestedExchange = wi.getString("suggestedExchange") - // We just use the suggested exchange, in the future there will be - // a selection dialog. - getWithdrawalInfoWithExchange(talerWithdrawUri, suggestedExchange) + val details: WithdrawalDetails = mapper.readValue(result.toString()) + if (details.tosAccepted) + withdrawStatus.value = ReceivedDetails( + talerWithdrawUri = uri, + exchangeBaseUrl = exchangeBaseUrl, + amountRaw = details.amountRaw, + amountEffective = details.amountEffective + ) + else getExchangeTos(exchangeBaseUrl, details, uri) } } - private fun getWithdrawalInfoWithExchange(talerWithdrawUri: String, selectedExchange: String) { + private fun getExchangeTos(exchangeBaseUrl: String, details: WithdrawalDetails, uri: String?) { val args = JSONObject().apply { - put("talerWithdrawUri", talerWithdrawUri) - put("selectedExchange", selectedExchange) + put("exchangeBaseUrl", exchangeBaseUrl) } - - walletBackendApi.sendRequest("getWithdrawDetailsForUri", args) { isError, result -> + walletBackendApi.sendRequest("getExchangeTos", args) { isError, result -> if (isError) { - Log.e(TAG, "Error getWithdrawDetailsForUri ${result.toString(4)}") - val message = if (result.has("message")) result.getString("message") else null - withdrawStatus.postValue(WithdrawStatus.Error(message)) - return@sendRequest - } - Log.v(TAG, "got getWithdrawDetailsForUri result (with exchange details)") - val status = withdrawStatus.value - if (status !is WithdrawStatus.Loading) { - Log.w(TAG, "ignoring withdrawal info result, not loading.") + handleError("getExchangeTos", result) return@sendRequest } - val wi = result.getJSONObject("bankWithdrawDetails") - val amount = Amount.fromJsonObject(wi.getJSONObject("amount")) - - val ei = result.getJSONObject("exchangeWithdrawDetails") - val termsOfServiceAccepted = ei.getBoolean("termsOfServiceAccepted") - - exchangeFees = ExchangeFees.fromExchangeWithdrawDetailsJson(ei) - - val withdrawFee = Amount.fromJsonObject(ei.getJSONObject("withdrawFee")) - val overhead = Amount.fromJsonObject(ei.getJSONObject("overhead")) - val fee = withdrawFee + overhead - - if (!termsOfServiceAccepted) { - val exchange = ei.getJSONObject("exchangeInfo") - val tosText = exchange.getString("termsOfServiceText") - val tosEtag = exchange.optString("termsOfServiceLastEtag", "undefined") - withdrawStatus.postValue( - WithdrawStatus.TermsOfServiceReviewRequired( - status.talerWithdrawUri, - selectedExchange, tosText, tosEtag, - amount, fee - ) - ) - } else { - withdrawStatus.postValue( - ReceivedDetails( - status.talerWithdrawUri, - selectedExchange, amount, - fee - ) - ) - } + withdrawStatus.value = WithdrawStatus.TosReviewRequired( + talerWithdrawUri = uri, + exchangeBaseUrl = exchangeBaseUrl, + amountRaw = details.amountRaw, + amountEffective = details.amountEffective, + tosText = result.getString("tos"), + tosEtag = result.getString("currentEtag") + ) } } - fun acceptWithdrawal(talerWithdrawUri: String, selectedExchange: String, currency: String) { - val args = JSONObject() - args.put("talerWithdrawUri", talerWithdrawUri) - args.put("selectedExchange", selectedExchange) - - withdrawStatus.value = WithdrawStatus.Withdrawing(talerWithdrawUri) - - walletBackendApi.sendRequest("acceptWithdrawal", args) { isError, result -> + /** + * Accept the currently displayed terms of service. + */ + fun acceptCurrentTermsOfService() { + val s = withdrawStatus.value as WithdrawStatus.TosReviewRequired + val args = JSONObject().apply { + put("exchangeBaseUrl", s.exchangeBaseUrl) + put("etag", s.tosEtag) + } + walletBackendApi.sendRequest("setExchangeTosAccepted", args) { isError, result -> if (isError) { - Log.v(TAG, "got acceptWithdrawal error result: ${result.toString(2)}") - return@sendRequest - } - Log.v(TAG, "got acceptWithdrawal result") - val status = withdrawStatus.value - if (status !is WithdrawStatus.Withdrawing) { - Log.w(TAG, "ignoring acceptWithdrawal result, invalid state: $status") + handleError("setExchangeTosAccepted", result) return@sendRequest } - withdrawStatus.postValue(WithdrawStatus.Success(currency)) + withdrawStatus.value = ReceivedDetails( + talerWithdrawUri = s.talerWithdrawUri, + exchangeBaseUrl = s.exchangeBaseUrl, + amountRaw = s.amountRaw, + amountEffective = s.amountEffective + ) } } - /** - * Accept the currently displayed terms of service. - */ - fun acceptCurrentTermsOfService() { - val s = withdrawStatus.value - check(s is WithdrawStatus.TermsOfServiceReviewRequired) + @UiThread + fun acceptWithdrawal() { + val status = withdrawStatus.value as ReceivedDetails + val operation = if (status.talerWithdrawUri == null) + "acceptManualWithdrawal" else "acceptBankIntegratedWithdrawal" val args = JSONObject().apply { - put("exchangeBaseUrl", s.exchange) - put("etag", s.tosEtag) + put("exchangeBaseUrl", status.exchangeBaseUrl) + if (status.talerWithdrawUri == null) { + put("amount", status.amountRaw) + } else { + put("talerWithdrawUri", status.talerWithdrawUri) + } } - walletBackendApi.sendRequest("acceptExchangeTermsOfService", args) { isError, result -> + withdrawStatus.value = WithdrawStatus.Withdrawing + walletBackendApi.sendRequest(operation, args) { isError, result -> if (isError) { - Log.e(TAG, "Error acceptExchangeTermsOfService ${result.toString(4)}") + handleError(operation, result) return@sendRequest } - val status = ReceivedDetails(s.talerWithdrawUri, s.exchange, s.amount, s.fee) - withdrawStatus.postValue(status) + withdrawStatus.value = WithdrawStatus.Success(status.amountRaw.currency) } } + @UiThread + private fun handleError(operation: String, result: JSONObject) { + Log.e(TAG, "Error $operation ${result.toString(2)}") + val message = if (result.has("message")) result.getString("message") else null + withdrawStatus.value = WithdrawStatus.Error(message) + } + } -- cgit v1.2.3