Implement gateway ordering.

This commit is contained in:
Alex Hart 2023-10-11 08:55:18 -04:00 committed by Cody Henthorne
parent 5285dd1665
commit c17d6c2334
4 changed files with 131 additions and 54 deletions

View file

@ -0,0 +1,47 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.components.settings.app.subscription.donate.gateway
import com.google.i18n.phonenumbers.PhoneNumberUtil
import org.signal.core.util.orNull
import org.thoughtcrime.securesms.recipients.Recipient
sealed interface GatewayOrderStrategy {
val orderedGateways: Set<GatewayResponse.Gateway>
private object Default : GatewayOrderStrategy {
override val orderedGateways: Set<GatewayResponse.Gateway> = setOf(
GatewayResponse.Gateway.CREDIT_CARD,
GatewayResponse.Gateway.PAYPAL,
GatewayResponse.Gateway.GOOGLE_PAY,
GatewayResponse.Gateway.SEPA_DEBIT
)
}
private object NorthAmerica : GatewayOrderStrategy {
override val orderedGateways: Set<GatewayResponse.Gateway> = setOf(
GatewayResponse.Gateway.GOOGLE_PAY,
GatewayResponse.Gateway.PAYPAL,
GatewayResponse.Gateway.CREDIT_CARD,
GatewayResponse.Gateway.SEPA_DEBIT
)
}
companion object {
fun getStrategy(): GatewayOrderStrategy {
val self = Recipient.self()
val e164 = self.e164.orNull() ?: return Default
return if (PhoneNumberUtil.getInstance().parse(e164, "").countryCode == 1) {
NorthAmerica
} else {
Default
}
}
}
}

View file

@ -72,66 +72,94 @@ class GatewaySelectorBottomSheet : DSLSettingsBottomSheetFragment() {
return@configure
}
if (state.isGooglePayAvailable) {
customPref(
GooglePayButton.Model(
isEnabled = true,
onClick = {
findNavController().popBackStack()
val response = GatewayResponse(GatewayResponse.Gateway.GOOGLE_PAY, args.request)
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to response))
}
)
)
}
if (state.isPayPalAvailable) {
space(8.dp)
customPref(
PayPalButton.Model(
onClick = {
findNavController().popBackStack()
val response = GatewayResponse(GatewayResponse.Gateway.PAYPAL, args.request)
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to response))
},
isEnabled = true
)
)
}
if (state.isCreditCardAvailable) {
space(8.dp)
primaryButton(
text = DSLSettingsText.from(R.string.GatewaySelectorBottomSheet__credit_or_debit_card),
icon = DSLSettingsIcon.from(R.drawable.credit_card, R.color.signal_colorOnPrimary),
onClick = {
findNavController().popBackStack()
val response = GatewayResponse(GatewayResponse.Gateway.CREDIT_CARD, args.request)
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to response))
}
)
}
if (state.isSEPADebitAvailable) {
space(8.dp)
tonalButton(
text = DSLSettingsText.from(R.string.GatewaySelectorBottomSheet__bank_transfer),
icon = DSLSettingsIcon.from(R.drawable.bank_transfer),
onClick = {
findNavController().popBackStack()
val response = GatewayResponse(GatewayResponse.Gateway.SEPA_DEBIT, args.request)
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to response))
}
)
state.gatewayOrderStrategy.orderedGateways.forEachIndexed { index, gateway ->
val isFirst = index == 0
when (gateway) {
GatewayResponse.Gateway.GOOGLE_PAY -> renderGooglePayButton(state, isFirst)
GatewayResponse.Gateway.PAYPAL -> renderPayPalButton(state, isFirst)
GatewayResponse.Gateway.CREDIT_CARD -> renderCreditCardButton(state, isFirst)
GatewayResponse.Gateway.SEPA_DEBIT -> renderSEPADebitButton(state, isFirst)
}
}
space(16.dp)
}
}
private fun DSLConfiguration.renderGooglePayButton(state: GatewaySelectorState, isFirstButton: Boolean) {
if (state.isGooglePayAvailable) {
if (!isFirstButton) {
space(8.dp)
}
customPref(
GooglePayButton.Model(
isEnabled = true,
onClick = {
findNavController().popBackStack()
val response = GatewayResponse(GatewayResponse.Gateway.GOOGLE_PAY, args.request)
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to response))
}
)
)
}
}
private fun DSLConfiguration.renderPayPalButton(state: GatewaySelectorState, isFirstButton: Boolean) {
if (state.isPayPalAvailable) {
if (!isFirstButton) {
space(8.dp)
}
customPref(
PayPalButton.Model(
onClick = {
findNavController().popBackStack()
val response = GatewayResponse(GatewayResponse.Gateway.PAYPAL, args.request)
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to response))
},
isEnabled = true
)
)
}
}
private fun DSLConfiguration.renderCreditCardButton(state: GatewaySelectorState, isFirstButton: Boolean) {
if (state.isCreditCardAvailable) {
if (!isFirstButton) {
space(8.dp)
}
primaryButton(
text = DSLSettingsText.from(R.string.GatewaySelectorBottomSheet__credit_or_debit_card),
icon = DSLSettingsIcon.from(R.drawable.credit_card, R.color.signal_colorOnCustom),
onClick = {
findNavController().popBackStack()
val response = GatewayResponse(GatewayResponse.Gateway.CREDIT_CARD, args.request)
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to response))
}
)
}
}
private fun DSLConfiguration.renderSEPADebitButton(state: GatewaySelectorState, isFirstButton: Boolean) {
if (state.isSEPADebitAvailable) {
if (!isFirstButton) {
space(8.dp)
}
tonalButton(
text = DSLSettingsText.from(R.string.GatewaySelectorBottomSheet__bank_transfer),
icon = DSLSettingsIcon.from(R.drawable.bank_transfer),
onClick = {
findNavController().popBackStack()
val response = GatewayResponse(GatewayResponse.Gateway.SEPA_DEBIT, args.request)
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to response))
}
)
}
}
companion object {
const val REQUEST_KEY = "payment_checkout_mode"

View file

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.donate.g
import org.thoughtcrime.securesms.badges.models.Badge
data class GatewaySelectorState(
val gatewayOrderStrategy: GatewayOrderStrategy,
val loading: Boolean = true,
val badge: Badge,
val isGooglePayAvailable: Boolean = false,

View file

@ -21,6 +21,7 @@ class GatewaySelectorViewModel(
private val store = RxStore(
GatewaySelectorState(
gatewayOrderStrategy = GatewayOrderStrategy.getStrategy(),
badge = args.request.badge,
isGooglePayAvailable = InAppDonations.isPaymentSourceAvailable(PaymentSourceType.Stripe.GooglePay, args.request.donateToSignalType),
isCreditCardAvailable = InAppDonations.isPaymentSourceAvailable(PaymentSourceType.Stripe.CreditCard, args.request.donateToSignalType),