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) --- .../net/taler/wallet/exchanges/ExchangeFees.kt | 95 ++++++++++++++ .../net/taler/wallet/exchanges/ExchangeManager.kt | 3 +- .../wallet/exchanges/SelectExchangeFragment.kt | 144 +++++++++++++++++++++ 3 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFees.kt create mode 100644 wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt (limited to 'wallet/src/main/java/net/taler/wallet/exchanges') diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFees.kt b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFees.kt new file mode 100644 index 0000000..ae90b98 --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeFees.kt @@ -0,0 +1,95 @@ +/* + * 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.exchanges + +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/exchanges/ExchangeManager.kt b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt index 41c8f2c..9d31b5f 100644 --- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt +++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt @@ -21,7 +21,6 @@ import androidx.lifecycle.LiveData 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.common.Event import net.taler.common.toEvent import net.taler.wallet.TAG @@ -46,7 +45,7 @@ class ExchangeManager( private fun list(): LiveData> { mProgress.value = true - walletBackendApi.sendRequest("listExchanges", JSONObject()) { isError, result -> + walletBackendApi.sendRequest("listExchanges") { isError, result -> if (isError) { throw AssertionError("Wallet core failed to return exchanges!") } else { diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt b/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt new file mode 100644 index 0000000..ef4894d --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/exchanges/SelectExchangeFragment.kt @@ -0,0 +1,144 @@ +/* + * 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.exchanges + +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.exchanges.CoinFeeAdapter.CoinFeeViewHolder +import net.taler.wallet.exchanges.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) + } + } +} -- cgit v1.2.3