diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/InAppDonations.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/InAppDonations.kt index 2c3ad7ab86..8cdec90c05 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/InAppDonations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/InAppDonations.kt @@ -1,5 +1,7 @@ package org.thoughtcrime.securesms.components.settings.app.subscription +import org.signal.donations.PaymentSourceType +import org.thoughtcrime.securesms.components.settings.app.subscription.donate.DonateToSignalType import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.LocaleFeatureFlags @@ -21,18 +23,34 @@ object InAppDonations { return isCreditCardAvailable() || isPayPalAvailable() || isGooglePayAvailable() } + fun isPaymentSourceAvailable(paymentSourceType: PaymentSourceType, donateToSignalType: DonateToSignalType): Boolean { + return when (paymentSourceType) { + PaymentSourceType.PayPal -> isPayPalAvailableForDonateToSignalType(donateToSignalType) + PaymentSourceType.Stripe.CreditCard -> isCreditCardAvailable() + PaymentSourceType.Stripe.GooglePay -> isGooglePayAvailable() + PaymentSourceType.Unknown -> false + } + } + + private fun isPayPalAvailableForDonateToSignalType(donateToSignalType: DonateToSignalType): Boolean { + return when (donateToSignalType) { + DonateToSignalType.ONE_TIME, DonateToSignalType.GIFT -> FeatureFlags.paypalOneTimeDonations() + DonateToSignalType.MONTHLY -> FeatureFlags.paypalRecurringDonations() + } && !LocaleFeatureFlags.isPayPalDisabled() + } + /** * Whether the user is in a region that supports credit cards, based off local phone number. */ - fun isCreditCardAvailable(): Boolean { + private fun isCreditCardAvailable(): Boolean { return FeatureFlags.creditCardPayments() && !LocaleFeatureFlags.isCreditCardDisabled() } /** * Whether the user is in a region that supports PayPal, based off local phone number. */ - fun isPayPalAvailable(): Boolean { - return FeatureFlags.paypalDonations() && !LocaleFeatureFlags.isPayPalDisabled() + private fun isPayPalAvailable(): Boolean { + return (FeatureFlags.paypalOneTimeDonations() || FeatureFlags.paypalRecurringDonations()) && !LocaleFeatureFlags.isPayPalDisabled() } /** diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonationCheckoutDelegate.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonationCheckoutDelegate.kt index 68e2de5121..619f1cd2ee 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonationCheckoutDelegate.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonationCheckoutDelegate.kt @@ -86,10 +86,14 @@ class DonationCheckoutDelegate( } private fun handleGatewaySelectionResponse(gatewayResponse: GatewayResponse) { - when (gatewayResponse.gateway) { - GatewayResponse.Gateway.GOOGLE_PAY -> launchGooglePay(gatewayResponse) - GatewayResponse.Gateway.PAYPAL -> launchPayPal(gatewayResponse) - GatewayResponse.Gateway.CREDIT_CARD -> launchCreditCard(gatewayResponse) + if (InAppDonations.isPaymentSourceAvailable(gatewayResponse.gateway.toPaymentSourceType(), gatewayResponse.request.donateToSignalType)) { + when (gatewayResponse.gateway) { + GatewayResponse.Gateway.GOOGLE_PAY -> launchGooglePay(gatewayResponse) + GatewayResponse.Gateway.PAYPAL -> launchPayPal(gatewayResponse) + GatewayResponse.Gateway.CREDIT_CARD -> launchCreditCard(gatewayResponse) + } + } else { + error("Unsupported combination! ${gatewayResponse.gateway} ${gatewayResponse.request.donateToSignalType}") } } @@ -131,11 +135,7 @@ class DonationCheckoutDelegate( } private fun launchPayPal(gatewayResponse: GatewayResponse) { - if (InAppDonations.isPayPalAvailable()) { - callback.navigateToPayPalPaymentInProgress(gatewayResponse.request) - } else { - error("PayPal is not currently enabled.") - } + callback.navigateToPayPalPaymentInProgress(gatewayResponse.request) } private fun launchGooglePay(gatewayResponse: GatewayResponse) { @@ -148,11 +148,7 @@ class DonationCheckoutDelegate( } private fun launchCreditCard(gatewayResponse: GatewayResponse) { - if (InAppDonations.isCreditCardAvailable()) { - callback.navigateToCreditCardForm(gatewayResponse.request) - } else { - error("Credit cards are not currently enabled.") - } + callback.navigateToCreditCardForm(gatewayResponse.request) } private fun registerGooglePayCallback() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewayResponse.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewayResponse.kt index 01537328da..533fa83c8e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewayResponse.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewayResponse.kt @@ -2,12 +2,21 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.donate.g import android.os.Parcelable import kotlinx.parcelize.Parcelize +import org.signal.donations.PaymentSourceType @Parcelize data class GatewayResponse(val gateway: Gateway, val request: GatewayRequest) : Parcelable { enum class Gateway { GOOGLE_PAY, PAYPAL, - CREDIT_CARD + CREDIT_CARD; + + fun toPaymentSourceType(): PaymentSourceType { + return when (this) { + GOOGLE_PAY -> PaymentSourceType.Stripe.GooglePay + PAYPAL -> PaymentSourceType.PayPal + CREDIT_CARD -> PaymentSourceType.Stripe.CreditCard + } + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorBottomSheet.kt index 32f4ce8d0d..0cda79c750 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorBottomSheet.kt @@ -16,7 +16,6 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon import org.thoughtcrime.securesms.components.settings.DSLSettingsText import org.thoughtcrime.securesms.components.settings.NO_TINT import org.thoughtcrime.securesms.components.settings.app.subscription.DonationPaymentComponent -import org.thoughtcrime.securesms.components.settings.app.subscription.InAppDonations import org.thoughtcrime.securesms.components.settings.app.subscription.donate.DonateToSignalType import org.thoughtcrime.securesms.components.settings.app.subscription.models.GooglePayButton import org.thoughtcrime.securesms.components.settings.app.subscription.models.PayPalButton @@ -82,7 +81,7 @@ class GatewaySelectorBottomSheet : DSLSettingsBottomSheetFragment() { ) } - if (InAppDonations.isPayPalAvailable()) { + if (state.isPayPalAvailable) { space(8.dp) customPref( @@ -97,7 +96,7 @@ class GatewaySelectorBottomSheet : DSLSettingsBottomSheetFragment() { ) } - if (InAppDonations.isCreditCardAvailable()) { + if (state.isCreditCardAvailable) { space(8.dp) primaryButton( diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorState.kt index 4a7ecc77cd..96c50b5879 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorState.kt @@ -4,5 +4,7 @@ import org.thoughtcrime.securesms.badges.models.Badge data class GatewaySelectorState( val badge: Badge, - val isGooglePayAvailable: Boolean = false + val isGooglePayAvailable: Boolean = false, + val isPayPalAvailable: Boolean = false, + val isCreditCardAvailable: Boolean = false ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorViewModel.kt index 073fc46916..a2658a96fa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/gateway/GatewaySelectorViewModel.kt @@ -5,6 +5,8 @@ import androidx.lifecycle.ViewModelProvider import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.subscribeBy +import org.signal.donations.PaymentSourceType +import org.thoughtcrime.securesms.components.settings.app.subscription.InAppDonations import org.thoughtcrime.securesms.components.settings.app.subscription.StripeRepository import org.thoughtcrime.securesms.util.rx.RxStore @@ -13,7 +15,14 @@ class GatewaySelectorViewModel( private val repository: StripeRepository ) : ViewModel() { - private val store = RxStore(GatewaySelectorState(args.request.badge)) + private val store = RxStore( + GatewaySelectorState( + badge = args.request.badge, + isGooglePayAvailable = InAppDonations.isPaymentSourceAvailable(PaymentSourceType.Stripe.GooglePay, args.request.donateToSignalType), + isCreditCardAvailable = InAppDonations.isPaymentSourceAvailable(PaymentSourceType.Stripe.CreditCard, args.request.donateToSignalType), + isPayPalAvailable = InAppDonations.isPaymentSourceAvailable(PaymentSourceType.PayPal, args.request.donateToSignalType) + ) + ) private val disposables = CompositeDisposable() val state = store.stateFlowable diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java index 4589b26190..24316913cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java @@ -106,7 +106,8 @@ public final class FeatureFlags { public static final String PAYPAL_DISABLED_REGIONS = "global.donations.paypalDisabledRegions"; private static final String CDS_HARD_LIMIT = "android.cds.hardLimit"; private static final String CHAT_FILTERS = "android.chat.filters"; - private static final String PAYPAL_DONATIONS = "android.donations.paypal"; + private static final String PAYPAL_ONE_TIME_DONATIONS = "android.oneTimePayPalDonations"; + private static final String PAYPAL_RECURRING_DONATIONS = "android.recurringPayPalDonations"; /** * We will only store remote values for flags in this set. If you want a flag to be controllable @@ -166,7 +167,8 @@ public final class FeatureFlags { KEEP_MUTED_CHATS_ARCHIVED, CDS_HARD_LIMIT, CHAT_FILTERS, - PAYPAL_DONATIONS + PAYPAL_ONE_TIME_DONATIONS, + PAYPAL_RECURRING_DONATIONS ); @VisibleForTesting @@ -590,10 +592,17 @@ public final class FeatureFlags { } /** - * Whether or not we should allow PayPal payments for donations + * Whether or not we should allow PayPal payments for one-time donations */ - public static boolean paypalDonations() { - return getBoolean(PAYPAL_DONATIONS, Environment.IS_STAGING); + public static boolean paypalOneTimeDonations() { + return getBoolean(PAYPAL_ONE_TIME_DONATIONS, Environment.IS_STAGING); + } + + /** + * Whether or not we should allow PayPal payments for recurring donations + */ + public static boolean paypalRecurringDonations() { + return getBoolean(PAYPAL_RECURRING_DONATIONS, false); } /** Only for rendering debug info. */