From 91115fa0bd3535cd2a7773be1b4f650df903c5cd Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Wed, 2 Oct 2024 15:23:15 -0300 Subject: [PATCH] Allow users to cancel during pending donation. --- ...outFlowActivityTest__RecurringDonations.kt | 48 +++++++++++++++++++ .../donate/DonateToSignalFragment.kt | 2 +- .../donate/DonateToSignalState.kt | 3 +- .../donate/DonateToSignalViewModel.kt | 2 + .../manage/ManageDonationsFragment.kt | 4 +- 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/CheckoutFlowActivityTest__RecurringDonations.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/CheckoutFlowActivityTest__RecurringDonations.kt index b3d233f4ec..0b75e87c36 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/CheckoutFlowActivityTest__RecurringDonations.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/CheckoutFlowActivityTest__RecurringDonations.kt @@ -5,6 +5,7 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isNotEnabled import androidx.test.espresso.matcher.ViewMatchers.isSelected import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText @@ -79,6 +80,16 @@ class CheckoutFlowActivityTest__RecurringDonations { onView(withText(R.string.StripePaymentInProgressFragment__cancelling)).check(matches(isDisplayed())) } + @Test + fun givenAPendingRecurringDonation_whenILoadScreen_thenIExpectDisabledUpgradeButton() { + initialiseConfigurationResponse() + initialisePendingSubscription() + + ActivityScenario.launch(intent) + onView(withText(R.string.SubscribeFragment__update_subscription)).check(matches(isDisplayed())) + onView(withText(R.string.SubscribeFragment__update_subscription)).check(matches(isNotEnabled())) + } + private fun initialiseConfigurationResponse() { InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers( Get("/v1/subscription/configuration") { @@ -130,4 +141,41 @@ class CheckoutFlowActivityTest__RecurringDonations { } ) } + + private fun initialisePendingSubscription() { + val currency = Currency.getInstance("USD") + val subscriber = InAppPaymentSubscriberRecord( + subscriberId = SubscriberId.generate(), + currency = currency, + type = InAppPaymentSubscriberRecord.Type.DONATION, + requiresCancel = false, + paymentMethodType = InAppPaymentData.PaymentMethodType.CARD + ) + + InAppPaymentsRepository.setSubscriber(subscriber) + SignalStore.inAppPayments.setSubscriberCurrency(currency, subscriber.type) + + InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers( + Get("/v1/subscription/${subscriber.subscriberId.serialize()}") { + MockResponse().success( + ActiveSubscription( + ActiveSubscription.Subscription( + 200, + currency.currencyCode, + BigDecimal.ONE, + System.currentTimeMillis().milliseconds.inWholeSeconds + 30.days.inWholeSeconds, + false, + System.currentTimeMillis().milliseconds.inWholeSeconds + 30.days.inWholeSeconds, + false, + "incomplete", + "STRIPE", + "CARD", + false + ), + null + ) + ) + } + ) + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalFragment.kt index 65be79c59a..a0e4146443 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalFragment.kt @@ -277,7 +277,7 @@ class DonateToSignalFragment : space(20.dp) - if (state.inAppPaymentType == InAppPaymentType.RECURRING_DONATION && state.monthlyDonationState.isSubscriptionActive) { + if (state.inAppPaymentType == InAppPaymentType.RECURRING_DONATION && (state.monthlyDonationState.isSubscriptionActive || state.monthlyDonationState.isSubscriptionInProgress)) { primaryButton( text = DSLSettingsText.from(R.string.SubscribeFragment__update_subscription), isEnabled = state.canUpdate, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalState.kt index ebc49aee02..4019515aea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalState.kt @@ -82,7 +82,7 @@ data class DonateToSignalState( val canUpdate: Boolean get() = when (inAppPaymentType) { InAppPaymentType.ONE_TIME_DONATION -> false - InAppPaymentType.RECURRING_DONATION -> areFieldsEnabled && monthlyDonationState.isSelectionValid + InAppPaymentType.RECURRING_DONATION -> areFieldsEnabled && monthlyDonationState.isSelectionValid && monthlyDonationState.isSubscriptionActive && !monthlyDonationState.transactionState.isInProgress else -> error("This flow does not support $inAppPaymentType") } @@ -124,6 +124,7 @@ data class DonateToSignalState( val transactionState: TransactionState = TransactionState() ) { val isSubscriptionActive: Boolean = _activeSubscription?.isActive == true + val isSubscriptionInProgress: Boolean = _activeSubscription?.isInProgress == true val activeLevel: Int? = _activeSubscription?.activeSubscription?.level val activeSubscription: ActiveSubscription.Subscription? = _activeSubscription?.activeSubscription val isActiveSubscriptionEnding: Boolean = _activeSubscription?.isActive == true && _activeSubscription.activeSubscription.willCancelAtPeriodEnd() diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalViewModel.kt index 3c9324973a..1311bcf4aa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/donate/DonateToSignalViewModel.kt @@ -119,6 +119,8 @@ class DonateToSignalViewModel( fun updateSubscription() { val snapshot = store.state + + check(snapshot.canUpdate) if (snapshot.areFieldsEnabled) { actionDisposable += createInAppPayment(snapshot).subscribeBy { _actions.onNext(DonateToSignalAction.UpdateSubscription(it, snapshot.isUpdateLongRunning)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt index 55a7c69522..c3cf911d5c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt @@ -278,9 +278,7 @@ class ManageDonationsFragment : activeSubscription = activeSubscription, subscriberRequiresCancel = state.subscriberRequiresCancel, onRowClick = { - if (it != ManageDonationsState.RedemptionState.IN_PROGRESS) { - launcher.launch(InAppPaymentType.RECURRING_DONATION) - } + launcher.launch(InAppPaymentType.RECURRING_DONATION) }, onPendingClick = { displayPendingDialog(it)