Skip to content

[Installments] - Add winback and trial offers#5000

Merged
sztomek merged 11 commits intomainfrom
feat/installments-offers
Feb 24, 2026
Merged

[Installments] - Add winback and trial offers#5000
sztomek merged 11 commits intomainfrom
feat/installments-offers

Conversation

@sztomek
Copy link
Contributor

@sztomek sztomek commented Feb 16, 2026

Description

This PR adds the two new offers under the installment plan.
We now support installment trials: plus-yearly-installments-trial-30days and winbacks: plus-yearly-installments-winback
I also had to update the upgrade screen to properly display the name of the installments plan alongside with the price and discount calculations.
The winback screen has been also adjusted to accomodate installments, now the text are clearer.

p2: pdeCcb-aGD-p2
slack: p1771529147990719-slack-C0A0PJSLGBT

Fixes PCDROID-425

Testing Instructions

A - Trial

  1. Make sure Google Play Billing Lab is donwloaded
  2. Make sure you're signed in with your subscription tester account
  3. Setup Billing Lab - change your country to one of the supported (Brazil, Italy, Spain, France)
  4. Make sure you tick the checkbox for trials and intro offers
  5. Apply patch and build the app debug-as-proddd.patch
  6. Navigate to the upgrade screen
  7. Make sure you're seeing the trial offer (Save XX label is visible, or just check logcat logs)
  8. Purchase the trial offer
    Caveat: you can only claim trial once per pocket casts accounts

B - Winback

  1. Same as A.1-A.3
  2. Navigate to Account>Cancel subscription
  3. Get to the winback offer screen (if your PC account has ever claimed winback, it won't be offered again)
  4. Check texts and prices
  5. Accept winback offer

Screenshots or Screencast

Trial offer on upgrade screen Winback offer
Screenshot_20260219_204235 Screenshot_20260219_202237

Checklist

  • If this is a user-facing change, I have added an entry in CHANGELOG.md
  • Ensure the linter passes (./gradlew spotlessApply to automatically apply formatting/linting)
  • I have considered whether it makes sense to add tests for my changes
  • All strings that need to be localized are in modules/services/localization/src/main/res/values/strings.xml
  • Any jetpack compose components I added or changed are covered by compose previews
  • I have updated (or requested that someone edit) the spreadsheet to reflect any new or changed analytics.

Copilot AI review requested due to automatic review settings February 16, 2026 14:27
@dangermattic
Copy link
Collaborator

dangermattic commented Feb 16, 2026

1 Warning
⚠️ This PR is larger than 500 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.

Generated by 🚫 Danger

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for promotional offers (Trial and Winback) on installment subscription plans, specifically for the Plus Yearly Installment plan. Previously, installment plans only supported base plans without offers, but this change enables the system to apply trial periods and winback offers to installment payment plans.

Changes:

  • Extended the subscription plan data model to support offers on installment plans by adding isInstallment parameter to SubscriptionPlan.WithOffer and findOfferPlan method
  • Added comprehensive test coverage for installment offer functionality including trial and winback offers
  • Updated analytics tracking across multiple features to include installment status
  • Enhanced UI components to properly display installment plans with offers, including custom display names and correct price calculations

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
modules/services/payment/src/main/kotlin/au/com/shiftyjelly/pocketcasts/payment/Data.kt Extended data model to support offers on installment plans by adding isInstallment parameter to SubscriptionPlan.WithOffer, findOfferPlan, and SubscriptionOffer.offerId methods
modules/services/payment/src/test/kotlin/au/com/shiftyjelly/pocketcasts/payment/SubscriptionPlansTest.kt Added test data for installment plans with offers and comprehensive test cases validating offer ID generation, plan finding, and unsupported offer types
modules/features/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModel.kt Updated winback flow to support installment offers by checking both installment and non-installment variants and adding installment tracking to analytics
modules/features/profile/src/test/kotlin/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModelTest.kt Updated test expectations to include isInstallment parameter in winback offer assertions and analytics verification
modules/features/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackOfferPage.kt Updated Compose preview parameters to include isInstallment field for proper preview rendering
modules/features/account/src/main/java/au/com/shiftyjelly/pocketcasts/account/viewmodel/OnboardingUpgradeFeaturesViewModel.kt Modified to support finding offer plans for installment subscriptions when feature flag is enabled and added installment tracking to analytics
modules/features/account/src/main/java/au/com/shiftyjelly/pocketcasts/account/onboarding/components/SubscriptionPlanRow.kt Enhanced UI to handle installment offers including custom display names, correct price-per-period calculations, and savings percentage logic
modules/services/localization/src/main/res/values/strings.xml Added new string resource for Plus yearly trial installments display name

@wpmobilebot
Copy link
Collaborator

App Icon📲 You can test the changes from this Pull Request in 📱 Mobile by scanning the QR code below to install the corresponding build.

App Name📱 Mobile
Build TypePrototype
Build Number9406
Version8.5-rc-2
Application IDau.com.shiftyjelly.pocketcasts
Commit3e120eb
Installation URL7jial4hllipr0
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot
Copy link
Collaborator

App Icon📲 You can test the changes from this Pull Request in ⌚ Wear by scanning the QR code below to install the corresponding build.
App Name⌚ Wear
Build TypeDebugProd
Build Number9406
Version8.5-rc-2
Application IDau.com.shiftyjelly.pocketcasts
Commit3e120eb
Direct Downloadpocketcasts-wear-prototype-build-pr5000-3e120eb.apk
Installation URL7jial4hllipr0
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.
App Icon📲 You can test the changes from this Pull Request in 🚗 Automotive by scanning the QR code below to install the corresponding build.
App Name🚗 Automotive
Build TypeDebugProd
Build Number9406
Version8.5-rc-2
Application IDau.com.shiftyjelly.pocketcasts
Commit3e120eb
Direct Downloadpocketcasts-automotive-prototype-build-pr5000-3e120eb.apk
Installation URL7jial4hllipr0
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@sztomek sztomek force-pushed the feat/installments-offers branch from 3e120eb to a207e55 Compare February 18, 2026 20:37
Copilot AI review requested due to automatic review settings February 19, 2026 16:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

modules/features/profile/src/test/kotlin/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModelTest.kt:710

  • Missing test coverage for analytics tracking when claiming an installment winback offer. The existing tests only verify is_installment = "false" scenarios. Consider adding a test that verifies the analytics event when a user claims an installment winback offer (e.g., Plus Yearly Installment with a winback offer), to ensure is_installment = "true" is correctly tracked.
    @Test
    fun `track claim patron yearly offer tapped`() = runTest {
        paymentDataSource.loadedPurchases = listOf(
            createPurchase(productIds = listOf(SubscriptionPlan.PATRON_YEARLY_PRODUCT_ID)),
        )

        viewModel.loadWinbackData()
        viewModel.claimOffer(mock<Activity>())

        val event = tracker.events.single()
        assertEquals(
            TrackedEvent(
                AnalyticsEvent.WINBACK_MAIN_SCREEN_ROW_TAP,
                mapOf(
                    "row" to "claim_offer",
                    "tier" to "patron",
                    "frequency" to "yearly",
                    "is_installment" to "false",
                ),
            ),
            event,
        )
    }

@sztomek sztomek changed the title DRAFT - Installment offers [Installments] - Add winback and trial offers Feb 19, 2026
@sztomek sztomek added this to the 8.7 milestone Feb 19, 2026
@sztomek sztomek added [Type] Feature Adding a new feature. [Area] Subscriptions Plus or Patron issue labels Feb 19, 2026
@sztomek sztomek marked this pull request as ready for review February 19, 2026 19:44
@sztomek sztomek requested a review from a team as a code owner February 19, 2026 19:44
@sztomek sztomek requested review from MiSikora and removed request for a team February 19, 2026 19:44
Copy link
Contributor

@MiSikora MiSikora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation looks good. The only thing that needs changing is mapping of Product to SubscriptionPlan that doesn't use installment data for validation.

I also found one issue that needs to be addressed before releasing but it can be addressed in a separate PR. During the Winback flow the plan change isn't aware of installements.

Image

@sztomek sztomek requested a review from MiSikora February 23, 2026 20:36
@sztomek
Copy link
Contributor Author

sztomek commented Feb 23, 2026

@MiSikora i've updated the code in sync with your comments, please have another look. i'll address the plan change issue you noticed in an upcoming PR.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

@sztomek sztomek merged commit 27b1144 into main Feb 24, 2026
22 checks passed
@sztomek sztomek deleted the feat/installments-offers branch February 24, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Area] Subscriptions Plus or Patron issue [Type] Feature Adding a new feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants