mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-21 10:17:56 +00:00
Implement PayPal confirm donation sheet.
This commit is contained in:
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.components.settings.app.subscription
|
||||
import io.reactivex.rxjava3.core.Completable
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.money.FiatMoney
|
||||
import org.signal.donations.PaymentSourceType
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.paypal.PayPalConfirmationResult
|
||||
@@ -24,6 +25,8 @@ class PayPalRepository(private val donationsService: DonationsService) {
|
||||
const val ONE_TIME_RETURN_URL = "https://signaldonations.org/return/onetime"
|
||||
const val MONTHLY_RETURN_URL = "https://signaldonations.org/return/monthly"
|
||||
const val CANCEL_URL = "https://signaldonations.org/cancel"
|
||||
|
||||
private val TAG = Log.tag(PayPalRepository::class.java)
|
||||
}
|
||||
|
||||
fun createOneTimePaymentIntent(
|
||||
@@ -53,6 +56,7 @@ class PayPalRepository(private val donationsService: DonationsService) {
|
||||
paypalConfirmationResult: PayPalConfirmationResult
|
||||
): Single<PayPalConfirmPaymentIntentResponse> {
|
||||
return Single.fromCallable {
|
||||
Log.d(TAG, "Confirming one-time payment intent...", true)
|
||||
donationsService
|
||||
.confirmPayPalOneTimePaymentIntent(
|
||||
amount.currency.currencyCode,
|
||||
@@ -78,11 +82,14 @@ class PayPalRepository(private val donationsService: DonationsService) {
|
||||
|
||||
fun setDefaultPaymentMethod(paymentMethodId: String): Completable {
|
||||
return Single.fromCallable {
|
||||
Log.d(TAG, "Setting default payment method...", true)
|
||||
donationsService.setDefaultPayPalPaymentMethod(
|
||||
SignalStore.donationsValues().requireSubscriber().subscriberId,
|
||||
paymentMethodId
|
||||
)
|
||||
}.flatMap { it.flattenResult() }.ignoreElement().andThen {
|
||||
}.flatMap { it.flattenResult() }.ignoreElement().doOnComplete {
|
||||
Log.d(TAG, "Set default payment method.", true)
|
||||
Log.d(TAG, "Storing the subscription payment source type locally.", true)
|
||||
SignalStore.donationsValues().setSubscriptionPaymentSourceType(PaymentSourceType.PayPal)
|
||||
}.subscribeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
@@ -2,10 +2,19 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.donate
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.errors.DonationErrorSource
|
||||
|
||||
@Parcelize
|
||||
enum class DonateToSignalType(val requestCode: Short) : Parcelable {
|
||||
ONE_TIME(16141),
|
||||
MONTHLY(16142),
|
||||
GIFT(16143)
|
||||
GIFT(16143);
|
||||
|
||||
fun toErrorSource(): DonationErrorSource {
|
||||
return when (this) {
|
||||
ONE_TIME -> DonationErrorSource.BOOST
|
||||
MONTHLY -> DonationErrorSource.SUBSCRIPTION
|
||||
GIFT -> DonationErrorSource.GIFT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +235,12 @@ class DonationCheckoutDelegate(
|
||||
return
|
||||
}
|
||||
|
||||
if (throwable is DonationError.PayPalError.UserCancelledPaymentError) {
|
||||
Log.d(TAG, "User cancelled out of paypal flow.", true)
|
||||
fragment?.findNavController()?.popBackStack()
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "Displaying donation error dialog.", true)
|
||||
errorDialog = DonationErrorDialogs.show(
|
||||
fragment!!.requireContext(), throwable,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.subscription.donate.gateway
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
@@ -60,11 +61,7 @@ class GatewaySelectorBottomSheet : DSLSettingsBottomSheetFragment() {
|
||||
|
||||
space(12.dp)
|
||||
|
||||
when (args.request.donateToSignalType) {
|
||||
DonateToSignalType.MONTHLY -> presentMonthlyText()
|
||||
DonateToSignalType.ONE_TIME -> presentOneTimeText()
|
||||
DonateToSignalType.GIFT -> presentGiftText()
|
||||
}
|
||||
presentTitleAndSubtitle(requireContext(), args.request)
|
||||
|
||||
space(66.dp)
|
||||
|
||||
@@ -114,64 +111,72 @@ class GatewaySelectorBottomSheet : DSLSettingsBottomSheetFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun DSLConfiguration.presentMonthlyText() {
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
getString(R.string.GatewaySelectorBottomSheet__donate_s_month_to_signal, FiatMoneyUtil.format(resources, args.request.fiat)),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.TitleLargeModifier
|
||||
)
|
||||
)
|
||||
space(6.dp)
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
getString(R.string.GatewaySelectorBottomSheet__get_a_s_badge, args.request.badge.name),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.BodyLargeModifier,
|
||||
DSLSettingsText.ColorModifier(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun DSLConfiguration.presentOneTimeText() {
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
getString(R.string.GatewaySelectorBottomSheet__donate_s_to_signal, FiatMoneyUtil.format(resources, args.request.fiat)),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.TitleLargeModifier
|
||||
)
|
||||
)
|
||||
space(6.dp)
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
resources.getQuantityString(R.plurals.GatewaySelectorBottomSheet__get_a_s_badge_for_d_days, 30, args.request.badge.name, 30),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.BodyLargeModifier,
|
||||
DSLSettingsText.ColorModifier(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun DSLConfiguration.presentGiftText() {
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
getString(R.string.GatewaySelectorBottomSheet__donate_s_to_signal, FiatMoneyUtil.format(resources, args.request.fiat)),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.TitleLargeModifier
|
||||
)
|
||||
)
|
||||
space(6.dp)
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
R.string.GatewaySelectorBottomSheet__send_a_gift_badge,
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.BodyLargeModifier,
|
||||
DSLSettingsText.ColorModifier(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val REQUEST_KEY = "payment_checkout_mode"
|
||||
|
||||
fun DSLConfiguration.presentTitleAndSubtitle(context: Context, request: GatewayRequest) {
|
||||
when (request.donateToSignalType) {
|
||||
DonateToSignalType.MONTHLY -> presentMonthlyText(context, request)
|
||||
DonateToSignalType.ONE_TIME -> presentOneTimeText(context, request)
|
||||
DonateToSignalType.GIFT -> presentGiftText(context, request)
|
||||
}
|
||||
}
|
||||
|
||||
private fun DSLConfiguration.presentMonthlyText(context: Context, request: GatewayRequest) {
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
context.getString(R.string.GatewaySelectorBottomSheet__donate_s_month_to_signal, FiatMoneyUtil.format(context.resources, request.fiat)),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.TitleLargeModifier
|
||||
)
|
||||
)
|
||||
space(6.dp)
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
context.getString(R.string.GatewaySelectorBottomSheet__get_a_s_badge, request.badge.name),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.BodyLargeModifier,
|
||||
DSLSettingsText.ColorModifier(ContextCompat.getColor(context, R.color.signal_colorOnSurfaceVariant))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun DSLConfiguration.presentOneTimeText(context: Context, request: GatewayRequest) {
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
context.getString(R.string.GatewaySelectorBottomSheet__donate_s_to_signal, FiatMoneyUtil.format(context.resources, request.fiat)),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.TitleLargeModifier
|
||||
)
|
||||
)
|
||||
space(6.dp)
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
context.resources.getQuantityString(R.plurals.GatewaySelectorBottomSheet__get_a_s_badge_for_d_days, 30, request.badge.name, 30),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.BodyLargeModifier,
|
||||
DSLSettingsText.ColorModifier(ContextCompat.getColor(context, R.color.signal_colorOnSurfaceVariant))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun DSLConfiguration.presentGiftText(context: Context, request: GatewayRequest) {
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
context.getString(R.string.GatewaySelectorBottomSheet__donate_s_to_signal, FiatMoneyUtil.format(context.resources, request.fiat)),
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.TitleLargeModifier
|
||||
)
|
||||
)
|
||||
space(6.dp)
|
||||
noPadTextPref(
|
||||
title = DSLSettingsText.from(
|
||||
R.string.GatewaySelectorBottomSheet__send_a_gift_badge,
|
||||
DSLSettingsText.CenterModifier,
|
||||
DSLSettingsText.BodyLargeModifier,
|
||||
DSLSettingsText.ColorModifier(ContextCompat.getColor(context, R.color.signal_colorOnSurfaceVariant))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.subscription.donate.paypal
|
||||
|
||||
import android.content.DialogInterface
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import org.signal.core.util.dp
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.badges.models.BadgeDisplay112
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsBottomSheetFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.gateway.GatewaySelectorBottomSheet.Companion.presentTitleAndSubtitle
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
|
||||
/**
|
||||
* Bottom sheet for final order confirmation from PayPal
|
||||
*/
|
||||
class PayPalCompleteOrderBottomSheet : DSLSettingsBottomSheetFragment() {
|
||||
|
||||
companion object {
|
||||
const val REQUEST_KEY = "complete_order"
|
||||
}
|
||||
|
||||
private var didConfirmOrder = false
|
||||
private val args: PayPalCompleteOrderBottomSheetArgs by navArgs()
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
BadgeDisplay112.register(adapter)
|
||||
PayPalCompleteOrderPaymentItem.register(adapter)
|
||||
|
||||
adapter.submitList(getConfiguration().toMappingModelList())
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to didConfirmOrder))
|
||||
}
|
||||
|
||||
private fun getConfiguration(): DSLConfiguration {
|
||||
return configure {
|
||||
customPref(
|
||||
BadgeDisplay112.Model(
|
||||
badge = args.request.badge,
|
||||
withDisplayText = false
|
||||
)
|
||||
)
|
||||
|
||||
space(12.dp)
|
||||
|
||||
presentTitleAndSubtitle(requireContext(), args.request)
|
||||
|
||||
space(24.dp)
|
||||
|
||||
customPref(PayPalCompleteOrderPaymentItem.Model())
|
||||
|
||||
space(82.dp)
|
||||
|
||||
primaryButton(
|
||||
text = DSLSettingsText.from(R.string.PaypalCompleteOrderBottomSheet__donate),
|
||||
onClick = {
|
||||
didConfirmOrder = true
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
)
|
||||
|
||||
secondaryButtonNoOutline(
|
||||
text = DSLSettingsText.from(android.R.string.cancel),
|
||||
onClick = {
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
)
|
||||
|
||||
space(16.dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.subscription.donate.paypal
|
||||
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder.SimpleViewHolder
|
||||
|
||||
/**
|
||||
* Line item on the PayPal order confirmation screen.
|
||||
*/
|
||||
object PayPalCompleteOrderPaymentItem {
|
||||
fun register(mappingAdapter: MappingAdapter) {
|
||||
mappingAdapter.registerFactory(Model::class.java, LayoutFactory(::SimpleViewHolder, R.layout.paypal_complete_order_payment_item))
|
||||
}
|
||||
|
||||
class Model : MappingModel<Model> {
|
||||
override fun areItemsTheSame(newItem: Model): Boolean = true
|
||||
|
||||
override fun areContentsTheSame(newItem: Model): Boolean = true
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import android.webkit.WebViewClient
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
@@ -47,7 +49,9 @@ class PayPalConfirmationDialogFragment : DialogFragment(R.layout.donation_webvie
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
binding.webView.webViewClient = PayPalWebClient()
|
||||
val client = PayPalWebClient()
|
||||
viewLifecycleOwner.lifecycle.addObserver(client)
|
||||
binding.webView.webViewClient = client
|
||||
binding.webView.settings.javaScriptEnabled = true
|
||||
binding.webView.settings.cacheMode = WebSettings.LOAD_NO_CACHE
|
||||
binding.webView.loadUrl(args.uri.toString())
|
||||
@@ -59,21 +63,31 @@ class PayPalConfirmationDialogFragment : DialogFragment(R.layout.donation_webvie
|
||||
setFragmentResult(REQUEST_KEY, result ?: Bundle())
|
||||
}
|
||||
|
||||
private inner class PayPalWebClient : WebViewClient() {
|
||||
private inner class PayPalWebClient : WebViewClient(), DefaultLifecycleObserver {
|
||||
|
||||
private var isDestroyed = false
|
||||
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
isDestroyed = true
|
||||
}
|
||||
|
||||
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
|
||||
if (!isFinished) {
|
||||
if (!isDestroyed) {
|
||||
binding.progress.visible = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageCommitVisible(view: WebView?, url: String?) {
|
||||
if (!isFinished) {
|
||||
if (!isDestroyed) {
|
||||
binding.progress.visible = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
if (isDestroyed) {
|
||||
return
|
||||
}
|
||||
|
||||
if (url?.startsWith(PayPalRepository.ONE_TIME_RETURN_URL) == true) {
|
||||
val confirmationResult = PayPalConfirmationResult.fromUrl(url)
|
||||
if (confirmationResult != null) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.components.ViewBinderDelegate
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.DonationProcessorAction
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.DonationProcessorActionResult
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.DonationProcessorStage
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.errors.DonationError
|
||||
import org.thoughtcrime.securesms.databinding.DonationInProgressFragmentBinding
|
||||
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
@@ -57,7 +58,7 @@ class PayPalPaymentInProgressFragment : DialogFragment(R.layout.donation_in_prog
|
||||
viewModel.onBeginNewAction()
|
||||
when (args.action) {
|
||||
DonationProcessorAction.PROCESS_NEW_DONATION -> {
|
||||
viewModel.processNewDonation(args.request, this::routeToOneTimeConfirmation, this::routeToMonthlyConfirmation)
|
||||
viewModel.processNewDonation(args.request, this::oneTimeConfirmationPipeline, this::monthlyConfirmationPipeline)
|
||||
}
|
||||
DonationProcessorAction.UPDATE_SUBSCRIPTION -> {
|
||||
viewModel.updateSubscription(args.request)
|
||||
@@ -110,6 +111,18 @@ class PayPalPaymentInProgressFragment : DialogFragment(R.layout.donation_in_prog
|
||||
}
|
||||
}
|
||||
|
||||
private fun oneTimeConfirmationPipeline(createPaymentIntentResponse: PayPalCreatePaymentIntentResponse): Single<PayPalConfirmationResult> {
|
||||
return routeToOneTimeConfirmation(createPaymentIntentResponse).flatMap {
|
||||
displayCompleteOrderSheet(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun monthlyConfirmationPipeline(createPaymentIntentResponse: PayPalCreatePaymentMethodResponse): Single<PayPalPaymentMethodId> {
|
||||
return routeToMonthlyConfirmation(createPaymentIntentResponse).flatMap {
|
||||
displayCompleteOrderSheet(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun routeToOneTimeConfirmation(createPaymentIntentResponse: PayPalCreatePaymentIntentResponse): Single<PayPalConfirmationResult> {
|
||||
return Single.create<PayPalConfirmationResult> { emitter ->
|
||||
val listener = FragmentResultListener { _, bundle ->
|
||||
@@ -117,10 +130,11 @@ class PayPalPaymentInProgressFragment : DialogFragment(R.layout.donation_in_prog
|
||||
if (result != null) {
|
||||
emitter.onSuccess(result)
|
||||
} else {
|
||||
emitter.onError(Exception("User did not complete paypal confirmation."))
|
||||
emitter.onError(DonationError.PayPalError.UserCancelledPaymentError(args.request.donateToSignalType.toErrorSource()))
|
||||
}
|
||||
}
|
||||
|
||||
parentFragmentManager.clearFragmentResult(PayPalConfirmationDialogFragment.REQUEST_KEY)
|
||||
parentFragmentManager.setFragmentResultListener(PayPalConfirmationDialogFragment.REQUEST_KEY, this, listener)
|
||||
|
||||
findNavController().safeNavigate(
|
||||
@@ -130,6 +144,8 @@ class PayPalPaymentInProgressFragment : DialogFragment(R.layout.donation_in_prog
|
||||
)
|
||||
|
||||
emitter.setCancellable {
|
||||
Log.d(TAG, "Clearing one-time confirmation result listener.")
|
||||
parentFragmentManager.clearFragmentResult(PayPalConfirmationDialogFragment.REQUEST_KEY)
|
||||
parentFragmentManager.clearFragmentResultListener(PayPalConfirmationDialogFragment.REQUEST_KEY)
|
||||
}
|
||||
}.subscribeOn(AndroidSchedulers.mainThread()).observeOn(Schedulers.io())
|
||||
@@ -138,14 +154,15 @@ class PayPalPaymentInProgressFragment : DialogFragment(R.layout.donation_in_prog
|
||||
private fun routeToMonthlyConfirmation(createPaymentIntentResponse: PayPalCreatePaymentMethodResponse): Single<PayPalPaymentMethodId> {
|
||||
return Single.create<PayPalPaymentMethodId> { emitter ->
|
||||
val listener = FragmentResultListener { _, bundle ->
|
||||
val result: Boolean = bundle.getBoolean(REQUEST_KEY)
|
||||
val result: Boolean = bundle.getBoolean(PayPalConfirmationDialogFragment.REQUEST_KEY)
|
||||
if (result) {
|
||||
emitter.onSuccess(PayPalPaymentMethodId(createPaymentIntentResponse.token))
|
||||
} else {
|
||||
emitter.onError(Exception("User did not confirm paypal setup."))
|
||||
emitter.onError(DonationError.PayPalError.UserCancelledPaymentError(args.request.donateToSignalType.toErrorSource()))
|
||||
}
|
||||
}
|
||||
|
||||
parentFragmentManager.clearFragmentResult(PayPalConfirmationDialogFragment.REQUEST_KEY)
|
||||
parentFragmentManager.setFragmentResultListener(PayPalConfirmationDialogFragment.REQUEST_KEY, this, listener)
|
||||
|
||||
findNavController().safeNavigate(
|
||||
@@ -155,8 +172,37 @@ class PayPalPaymentInProgressFragment : DialogFragment(R.layout.donation_in_prog
|
||||
)
|
||||
|
||||
emitter.setCancellable {
|
||||
Log.d(TAG, "Clearing monthly confirmation result listener.")
|
||||
parentFragmentManager.clearFragmentResult(PayPalConfirmationDialogFragment.REQUEST_KEY)
|
||||
parentFragmentManager.clearFragmentResultListener(PayPalConfirmationDialogFragment.REQUEST_KEY)
|
||||
}
|
||||
}.subscribeOn(AndroidSchedulers.mainThread()).observeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
private fun <T : Any> displayCompleteOrderSheet(confirmationData: T): Single<T> {
|
||||
return Single.create<T> { emitter ->
|
||||
val listener = FragmentResultListener { _, bundle ->
|
||||
val result: Boolean = bundle.getBoolean(PayPalCompleteOrderBottomSheet.REQUEST_KEY)
|
||||
if (result) {
|
||||
Log.d(TAG, "User confirmed order. Continuing...")
|
||||
emitter.onSuccess(confirmationData)
|
||||
} else {
|
||||
emitter.onError(DonationError.PayPalError.UserCancelledPaymentError(args.request.donateToSignalType.toErrorSource()))
|
||||
}
|
||||
}
|
||||
|
||||
parentFragmentManager.clearFragmentResult(PayPalCompleteOrderBottomSheet.REQUEST_KEY)
|
||||
parentFragmentManager.setFragmentResultListener(PayPalCompleteOrderBottomSheet.REQUEST_KEY, this, listener)
|
||||
|
||||
findNavController().safeNavigate(
|
||||
PayPalPaymentInProgressFragmentDirections.actionPaypalPaymentInProgressFragmentToPaypalCompleteOrderBottomSheet(args.request)
|
||||
)
|
||||
|
||||
emitter.setCancellable {
|
||||
Log.d(TAG, "Clearing complete order result listener.")
|
||||
parentFragmentManager.clearFragmentResult(PayPalCompleteOrderBottomSheet.REQUEST_KEY)
|
||||
parentFragmentManager.clearFragmentResultListener(PayPalCompleteOrderBottomSheet.REQUEST_KEY)
|
||||
}
|
||||
}.subscribeOn(AndroidSchedulers.mainThread()).observeOn(Schedulers.io())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ sealed class DonationError(val source: DonationErrorSource, cause: Throwable) :
|
||||
class RequestTokenError(source: DonationErrorSource, cause: Throwable) : GooglePayError(source, cause)
|
||||
}
|
||||
|
||||
sealed class PayPalError(source: DonationErrorSource, cause: Throwable) : DonationError(source, cause) {
|
||||
class UserCancelledPaymentError(source: DonationErrorSource) : DonationError(source, Exception("User cancelled payment."))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gifting recipient validation errors, which occur before the user could be charged for a gift.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user