Skip to content

Wire multipage workflow navigation into PaywallViewModel#3381

Merged
vegaro merged 10 commits into
mainfrom
cesar/wfl-46-paywall-viewmodel-multipage
Apr 28, 2026
Merged

Wire multipage workflow navigation into PaywallViewModel#3381
vegaro merged 10 commits into
mainfrom
cesar/wfl-46-paywall-viewmodel-multipage

Conversation

@vegaro

@vegaro vegaro commented Apr 23, 2026

Copy link
Copy Markdown
Member

Summary

  • PaywallViewModel fetches the workflow result and creates a WorkflowNavigator to manage step traversal
  • Adds an isWorkflowActive flag to PaywallState.Loaded.Components (defaults to false). No caller sets it to true yet, a follow-up PR will.
  • handleWorkflowAction(componentId) advances the navigator to the next step and re-builds paywall state with isWorkflowActive = true
  • handleBackNavigation() pops the back stack via the navigator; BackHandler and NavigateBack calls in InternalPaywall use this before closing the paywall
  • LoadingPaywall gains no-op stubs for both new interface methods

Note

Medium Risk
Introduces new navigation/state transitions for workflow-driven paywalls and changes back-button behavior, which could affect dismissal and screen rendering flow. Purchase/restore logic is untouched, but workflow step validation and action nullability may surface new configuration errors.

Overview
Adds workflow step navigation to paywalls by having PaywallViewModelImpl keep a WorkflowNavigator, rebuild paywall state from the active workflow step on handleWorkflowAction, and consume back presses via handleBackNavigation before dismissing.

Tightens workflow button handling by making WorkflowTrigger actions nullable when componentId is missing (guarding clicks), and by validating/erroing during style creation with a new PaywallValidationError.WorkflowButtonMissingComponentId to prevent misconfigured workflow buttons.

Reviewed by Cursor Bugbot for commit aa0f8ad. Bugbot is set up for automated code reviews on this repo. Configure here.

@codecov

codecov Bot commented Apr 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.39%. Comparing base (44b0a1f) to head (aa0f8ad).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3381   +/-   ##
=======================================
  Coverage   79.39%   79.39%           
=======================================
  Files         361      361           
  Lines       14473    14473           
  Branches     1968     1968           
=======================================
  Hits        11491    11491           
  Misses       2188     2188           
  Partials      794      794           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch from 2ed078b to 5d3406f Compare April 23, 2026 15:30
@vegaro vegaro force-pushed the cesar/wfl-46-button-workflow-trigger branch from b994d2e to 4a31580 Compare April 23, 2026 15:31
@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch 2 times, most recently from 83f6438 to babf7fa Compare April 23, 2026 15:51
@vegaro vegaro force-pushed the cesar/wfl-46-button-workflow-trigger branch from 687fca5 to b479a73 Compare April 23, 2026 15:54
@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch 2 times, most recently from b394e7e to 9c5ae74 Compare April 23, 2026 17:37
@vegaro vegaro force-pushed the cesar/wfl-46-button-workflow-trigger branch 2 times, most recently from 0c34228 to 8ac3fa4 Compare April 23, 2026 17:51
@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch from 9c5ae74 to b5cf345 Compare April 23, 2026 17:51
@vegaro vegaro force-pushed the cesar/wfl-46-button-workflow-trigger branch from 8ac3fa4 to a1073d3 Compare April 23, 2026 18:02
@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch from b5cf345 to ec2fadc Compare April 23, 2026 18:02
@vegaro vegaro force-pushed the cesar/wfl-46-button-workflow-trigger branch from a1073d3 to 47f4bb5 Compare April 23, 2026 18:04
@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch 2 times, most recently from 8942ab0 to 6d0bc64 Compare April 24, 2026 07:50
@vegaro vegaro force-pushed the cesar/wfl-46-button-workflow-trigger branch from 47f4bb5 to 08a6ac2 Compare April 24, 2026 07:50
@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch from fee6518 to 7e22a87 Compare April 24, 2026 10:05
@vegaro vegaro force-pushed the cesar/wfl-46-button-workflow-trigger branch from 08a6ac2 to ee0e6bf Compare April 24, 2026 10:06
@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch 2 times, most recently from 8d609dd to 6bd5ab3 Compare April 24, 2026 10:16
Base automatically changed from cesar/wfl-46-button-workflow-trigger to main April 24, 2026 14:16
@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch 4 times, most recently from e3eb2d7 to cfed953 Compare April 27, 2026 11:01
@vegaro vegaro requested a review from facumenzella April 27, 2026 15:40
PaywallAction.External.NavigateBack

is ButtonComponentStyle.Action.WorkflowTrigger -> componentId?.let {
PaywallAction.External.WorkflowTrigger(it, WorkflowTriggerType.ON_PRESS)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Silent null fallback replaces error logging for misconfiguration

Low Severity

The WorkflowTrigger branch in toPaywallAction silently returns null when componentId is null. This case is expected to be intercepted earlier by StyleFactory validation, making it a "should not be reached" scenario at runtime. The previous code explicitly logged an error via Logger.e(...) for this misconfiguration. Removing that logging makes it harder to diagnose if the validation is ever bypassed. A warnLog or errorLog call before returning null would preserve observability.

Fix in Cursor Fix in Web

Triggered by learned rule: Defensive "should not reach" when branches must log, not silently fallback

Reviewed by Cursor Bugbot for commit b1695e5160ef39eea217f51f7dc94c073ee7faab. Configure here.

@facumenzella facumenzella left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would tweak those tests, feels like we're adding a bunch that could be simplified / removed.

vegaro commented Apr 28, 2026

Copy link
Copy Markdown
Member Author

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 64b2aa1f6028853a1c7472d2e51708209e23db56. Configure here.

matteinn pushed a commit to matteinn/purchases-android that referenced this pull request Apr 28, 2026
Groundwork for
RevenueCat#3381 to keep the
review simpler.

I am just extracting a private function 

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk refactor that only reorganizes `NavigateTo` action mapping
logic without changing behavior. Main risk is accidental regression in
`NavigateTo` destination handling, but the moved code remains identical.
> 
> **Overview**
> Refactors `ButtonComponentState` by extracting the
`ButtonComponentStyle.Action.NavigateTo` → `PaywallAction` conversion
into a dedicated private `NavigateTo.toPaywallAction(localeId)` helper.
> 
> The main `Action.toPaywallAction` mapping now delegates `NavigateTo`
handling to this helper, keeping behavior (including locale-specific URL
selection) unchanged.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8d7dbb1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
matteinn pushed a commit to matteinn/purchases-android that referenced this pull request Apr 28, 2026
Groundwork for
RevenueCat#3381

Passing `triggerType` to `WorkflowTrigger`, which for now it's always
`ON_PRESS`, but could be different in the future. The idea is that the
button (or other component) is the one that indicates the workflow
trigger type.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: small, internal data-shape change that currently only
affects workflow-trigger action construction and logging.
> 
> **Overview**
> Adds a `triggerType` field to `PaywallAction.External.WorkflowTrigger`
and introduces `WorkflowTriggerType` to represent how the workflow was
triggered.
> 
> Updates button action creation to emit `WorkflowTrigger(componentId,
WorkflowTriggerType.ON_PRESS)` and updates the paywall action handler
logging to include the new trigger type.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
9e0e0f5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@vegaro vegaro enabled auto-merge April 28, 2026 12:07
vegaro and others added 10 commits April 28, 2026 14:16
Removed test for back press behavior on regular paywall.
Removed test for handling workflow action when no workflow is loaded.
…n; fix FQN inline reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vegaro vegaro force-pushed the cesar/wfl-46-paywall-viewmodel-multipage branch from 195e7ce to aa0f8ad Compare April 28, 2026 12:16
@vegaro vegaro added this pull request to the merge queue Apr 28, 2026
Merged via the queue into main with commit 9baf20a Apr 28, 2026
37 checks passed
@vegaro vegaro deleted the cesar/wfl-46-paywall-viewmodel-multipage branch April 28, 2026 12:55
matteinn pushed a commit to matteinn/purchases-android that referenced this pull request May 5, 2026
**This is an automatic release.**

## RevenueCat SDK
### ✨ New Features
* Unified StoreReplacementMode API (RevenueCat#3234) via Will Taylor
(@fire-at-will)
* Add placement and targeting context to paywall events (RevenueCat#3253) via Dan
Pannasch (@dpannasch)
### 🐞 Bugfixes
* Fix null Placements when offering_ids_by_placement is absent (RevenueCat#3254)
via Dan Pannasch (@dpannasch)

## RevenueCatUI SDK
### Paywallv2
#### ✨ New Features
* Wire multipage workflow navigation into PaywallViewModel (RevenueCat#3381) via
Cesar de la Vega (@vegaro)

### 🔄 Other Changes
* Add `triggerType` to `WorkflowTrigger` (RevenueCat#3393) via Cesar de la Vega
(@vegaro)
* Extract private function `NavigateTo.toPaywallAction` (RevenueCat#3392) via
Cesar de la Vega (@vegaro)
* Bump revenucatui-tests gradle cache key (RevenueCat#3391) via Toni Rico
(@tonidero)
* Create `WorkflowTriggerType` and `WorkflowTriggerActionType` (RevenueCat#3386)
via Cesar de la Vega (@vegaro)
* Update baseline profiles (RevenueCat#3390) via RevenueCat Git Bot (@RCGitBot)
* Plumb `componentId` through buttons on workflow interactions (RevenueCat#3380)
via Cesar de la Vega (@vegaro)
* Add `ButtonComponent.Action.Workflow` (RevenueCat#3385) via Cesar de la Vega
(@vegaro)
* Add `componentId` to `ButtonCoomponentStyle` (RevenueCat#3384) via Cesar de la
Vega (@vegaro)
* Migrate all suspendCoroutine usages to suspendCancellableCoroutine
(RevenueCat#3365) via Jaewoong Eum (@skydoves)
* Add `WorkflowNavigator` for multipage workflow step navigation (RevenueCat#3379)
via Cesar de la Vega (@vegaro)
* build(deps): bump fastlane-plugin-revenuecat_internal from `b822f01`
to `d24ab26` (RevenueCat#3383) via dependabot[bot] (@dependabot[bot])
* Add `id` field to `ButtonComponent` (RevenueCat#3377) via Cesar de la Vega
(@vegaro)
* Add CI workflows for generating Baseline Profiles (RevenueCat#3372) via Jaewoong
Eum (@skydoves)
* add min sdk level for paywalls and customer center (RevenueCat#2465) via
Muhammad-Sharif Moustafa (@mshmoustafa)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk release bookkeeping: updates version strings, changelogs, and
documentation deployment targets without changing runtime logic beyond
the reported version identifier.
> 
> **Overview**
> Cuts the `10.3.0` release by updating all version references from
`10.3.0-SNAPSHOT` to `10.3.0` across build config (`gradle.properties`,
`.version`, `Config.frameworkVersion`) and sample/test app dependency
pins.
> 
> Updates release documentation publishing to sync Dokka output to the
`10.3.0` S3 path and changes `docs/index.html` to redirect to `10.3.0`.
Also promotes release notes by moving `CHANGELOG.latest.md` entries into
a new `CHANGELOG.md` section for `10.3.0`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
056ce62. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants