diff options
author | Torsten Grote <t@grobox.de> | 2020-03-18 14:24:41 -0300 |
---|---|---|
committer | Torsten Grote <t@grobox.de> | 2020-03-18 14:24:41 -0300 |
commit | a4796ec47d89a851b260b6fc195494547208a025 (patch) | |
tree | d2941b68ff2ce22c523e7aa634965033b1100560 /wallet/src/main/java/net/taler/wallet/withdraw | |
download | taler-android-a4796ec47d89a851b260b6fc195494547208a025.tar.gz taler-android-a4796ec47d89a851b260b6fc195494547208a025.tar.bz2 taler-android-a4796ec47d89a851b260b6fc195494547208a025.zip |
Merge all three apps into one repository
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/withdraw')
5 files changed, 506 insertions, 0 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/ErrorFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/ErrorFragment.kt new file mode 100644 index 0000000..f0f6610 --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/withdraw/ErrorFragment.kt @@ -0,0 +1,64 @@ +/* + * 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 <http://www.gnu.org/licenses/> + */ + +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.View.VISIBLE +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_error.* +import net.taler.wallet.R +import net.taler.wallet.WalletViewModel + +class ErrorFragment : Fragment() { + + private val model: WalletViewModel 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_error, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + errorTitle.setText(R.string.withdraw_error_title) + errorMessage.setText(R.string.withdraw_error_message) + + // show dev error message if dev mode is on + val status = withdrawManager.withdrawStatus.value + if (model.devMode.value == true && status is WithdrawStatus.Error) { + errorDevMessage.visibility = VISIBLE + errorDevMessage.text = status.message + } else { + errorDevMessage.visibility = GONE + } + + backButton.setOnClickListener { + findNavController().navigateUp() + } + } + +} diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt new file mode 100644 index 0000000..454816b --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt @@ -0,0 +1,109 @@ +/* + * 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 <http://www.gnu.org/licenses/> + */ + +package net.taler.wallet.withdraw + +import android.annotation.SuppressLint +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.lifecycle.Observer +import androidx.navigation.fragment.findNavController +import kotlinx.android.synthetic.main.fragment_prompt_withdraw.* +import net.taler.wallet.R +import net.taler.wallet.WalletViewModel +import net.taler.wallet.fadeIn +import net.taler.wallet.fadeOut +import net.taler.wallet.withdraw.WithdrawStatus.Loading +import net.taler.wallet.withdraw.WithdrawStatus.TermsOfServiceReviewRequired +import net.taler.wallet.withdraw.WithdrawStatus.Withdrawing + +class PromptWithdrawFragment : Fragment() { + + private val model: WalletViewModel 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_prompt_withdraw, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + button_cancel_withdraw.setOnClickListener { + withdrawManager.cancelCurrentWithdraw() + findNavController().navigateUp() + } + + button_confirm_withdraw.setOnClickListener { + val status = withdrawManager.withdrawStatus.value + if (status !is WithdrawStatus.ReceivedDetails) throw AssertionError() + it.fadeOut() + confirmProgressBar.fadeIn() + withdrawManager.acceptWithdrawal(status.talerWithdrawUri, status.suggestedExchange) + } + + withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer { + showWithdrawStatus(it) + }) + } + + private fun showWithdrawStatus(status: WithdrawStatus?) = when (status) { + is WithdrawStatus.ReceivedDetails -> { + model.showProgressBar.value = false + progressBar.fadeOut() + + introView.fadeIn() + @SuppressLint("SetTextI18n") + withdrawAmountView.text = "${status.amount.amount} ${status.amount.currency}" + withdrawAmountView.fadeIn() + feeView.fadeIn() + + exchangeIntroView.fadeIn() + withdrawExchangeUrl.text = status.suggestedExchange + withdrawExchangeUrl.fadeIn() + + button_confirm_withdraw.isEnabled = true + } + is WithdrawStatus.Success -> { + model.showProgressBar.value = false + withdrawManager.withdrawStatus.value = null + findNavController().navigate(R.id.action_promptWithdraw_to_withdrawSuccessful) + } + is Loading -> { + model.showProgressBar.value = true + } + is Withdrawing -> { + model.showProgressBar.value = true + } + is TermsOfServiceReviewRequired -> { + model.showProgressBar.value = false + findNavController().navigate(R.id.action_promptWithdraw_to_reviewExchangeTOS) + } + is WithdrawStatus.Error -> { + model.showProgressBar.value = false + findNavController().navigate(R.id.action_promptWithdraw_to_errorFragment) + } + null -> model.showProgressBar.value = false + } + +} diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt new file mode 100644 index 0000000..cd01a33 --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/withdraw/ReviewExchangeTosFragment.kt @@ -0,0 +1,80 @@ +/* + * 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 <http://www.gnu.org/licenses/> + */ + +package net.taler.wallet.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.lifecycle.Observer +import androidx.navigation.fragment.findNavController +import kotlinx.android.synthetic.main.fragment_review_exchange_tos.* +import net.taler.wallet.R +import net.taler.wallet.WalletViewModel +import net.taler.wallet.fadeIn +import net.taler.wallet.fadeOut + +class ReviewExchangeTosFragment : Fragment() { + + private val model: WalletViewModel 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_review_exchange_tos, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + acceptTosCheckBox.isChecked = false + acceptTosCheckBox.setOnCheckedChangeListener { _, isChecked -> + acceptTosButton.isEnabled = isChecked + } + abortTosButton.setOnClickListener { + withdrawManager.cancelCurrentWithdraw() + findNavController().navigateUp() + } + acceptTosButton.setOnClickListener { + withdrawManager.acceptCurrentTermsOfService() + } + withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer { + when (it) { + is WithdrawStatus.TermsOfServiceReviewRequired -> { + tosTextView.text = it.tosText + tosTextView.fadeIn() + acceptTosCheckBox.fadeIn() + progressBar.fadeOut() + } + is WithdrawStatus.Loading -> { + findNavController().navigate(R.id.action_reviewExchangeTOS_to_promptWithdraw) + } + is WithdrawStatus.ReceivedDetails -> { + findNavController().navigate(R.id.action_reviewExchangeTOS_to_promptWithdraw) + } + else -> { + } + } + }) + } + +} diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt new file mode 100644 index 0000000..e3af757 --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt @@ -0,0 +1,209 @@ +/* + * 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 <http://www.gnu.org/licenses/> + */ + +package net.taler.wallet.withdraw + +import android.util.Log +import androidx.lifecycle.MutableLiveData +import net.taler.wallet.Amount +import net.taler.wallet.TAG +import net.taler.wallet.backend.WalletBackendApi +import org.json.JSONObject + +sealed class WithdrawStatus { + data class Loading(val talerWithdrawUri: String) : WithdrawStatus() + data class TermsOfServiceReviewRequired( + val talerWithdrawUri: String, + val exchangeBaseUrl: String, + val tosText: String, + val tosEtag: String, + val amount: Amount, + val suggestedExchange: String + ) : WithdrawStatus() + + data class ReceivedDetails( + val talerWithdrawUri: String, + val amount: Amount, + val suggestedExchange: String + ) : WithdrawStatus() + + data class Withdrawing(val talerWithdrawUri: String) : WithdrawStatus() + + object Success : WithdrawStatus() + data class Error(val message: String?) : WithdrawStatus() +} + +class WithdrawManager(private val walletBackendApi: WalletBackendApi) { + + val withdrawStatus = MutableLiveData<WithdrawStatus>() + val testWithdrawalInProgress = MutableLiveData(false) + + private var currentWithdrawRequestId = 0 + + fun withdrawTestkudos() { + testWithdrawalInProgress.value = true + + walletBackendApi.sendRequest("withdrawTestkudos", null) { _, _ -> + testWithdrawalInProgress.postValue(false) + } + } + + fun getWithdrawalInfo(talerWithdrawUri: String) { + val args = JSONObject() + args.put("talerWithdrawUri", talerWithdrawUri) + + withdrawStatus.value = WithdrawStatus.Loading(talerWithdrawUri) + + this.currentWithdrawRequestId++ + val myWithdrawRequestId = this.currentWithdrawRequestId + + walletBackendApi.sendRequest("getWithdrawDetailsForUri", 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 + } + if (myWithdrawRequestId != this.currentWithdrawRequestId) { + val mismatch = "$myWithdrawRequestId != ${this.currentWithdrawRequestId}" + Log.w(TAG, "Got withdraw result for different request id $mismatch") + 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) + } + } + + private fun getWithdrawalInfoWithExchange(talerWithdrawUri: String, selectedExchange: String) { + val args = JSONObject() + args.put("talerWithdrawUri", talerWithdrawUri) + args.put("selectedExchange", selectedExchange) + + this.currentWithdrawRequestId++ + val myWithdrawRequestId = this.currentWithdrawRequestId + + walletBackendApi.sendRequest("getWithdrawDetailsForUri", 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 + } + if (myWithdrawRequestId != this.currentWithdrawRequestId) { + val mismatch = "$myWithdrawRequestId != ${this.currentWithdrawRequestId}" + Log.w(TAG, "Got withdraw result for different request id $mismatch") + return@sendRequest + } + Log.v(TAG, "got getWithdrawDetailsForUri result (with exchange details)") + 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") + val amount = Amount.fromJson(wi.getJSONObject("amount")) + + val ei = result.getJSONObject("exchangeWithdrawDetails") + val termsOfServiceAccepted = ei.getBoolean("termsOfServiceAccepted") + + 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, + suggestedExchange + ) + ) + } else { + withdrawStatus.postValue( + WithdrawStatus.ReceivedDetails( + status.talerWithdrawUri, + amount, + suggestedExchange + ) + ) + } + } + } + + fun acceptWithdrawal(talerWithdrawUri: String, selectedExchange: String) { + val args = JSONObject() + args.put("talerWithdrawUri", talerWithdrawUri) + args.put("selectedExchange", selectedExchange) + + withdrawStatus.value = WithdrawStatus.Withdrawing(talerWithdrawUri) + + walletBackendApi.sendRequest("acceptWithdrawal", args) { isError, _ -> + if (isError) { + Log.v(TAG, "got acceptWithdrawal error result") + return@sendRequest + } + Log.v(TAG, "got acceptWithdrawal result") + val status = withdrawStatus.value + if (status !is WithdrawStatus.Withdrawing) { + Log.v(TAG, "ignoring acceptWithdrawal result, invalid state") + } + withdrawStatus.postValue(WithdrawStatus.Success) + } + } + + /** + * Accept the currently displayed terms of service. + */ + fun acceptCurrentTermsOfService() { + when (val s = withdrawStatus.value) { + is WithdrawStatus.TermsOfServiceReviewRequired -> { + val args = JSONObject() + args.put("exchangeBaseUrl", s.exchangeBaseUrl) + args.put("etag", s.tosEtag) + walletBackendApi.sendRequest("acceptExchangeTermsOfService", args) { isError, _ -> + if (isError) { + return@sendRequest + } + withdrawStatus.postValue( + WithdrawStatus.ReceivedDetails( + s.talerWithdrawUri, + s.amount, + s.suggestedExchange + ) + ) + } + } + } + } + + fun cancelCurrentWithdraw() { + currentWithdrawRequestId++ + withdrawStatus.value = null + } + +} diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawSuccessfulFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawSuccessfulFragment.kt new file mode 100644 index 0000000..5daeff1 --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawSuccessfulFragment.kt @@ -0,0 +1,44 @@ +/* + * 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 <http://www.gnu.org/licenses/> + */ + +package net.taler.wallet.withdraw + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import kotlinx.android.synthetic.main.fragment_withdraw_successful.* +import net.taler.wallet.R + +class WithdrawSuccessfulFragment : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_withdraw_successful, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + backButton.setOnClickListener { + findNavController().navigateUp() + } + } + +} |