Skip to content

Fix preload VideoComponent fallback override images#3449

Merged
vegaro merged 18 commits into
mainfrom
cesar/paywall-localized-image-predownloader
May 12, 2026
Merged

Fix preload VideoComponent fallback override images#3449
vegaro merged 18 commits into
mainfrom
cesar/paywall-localized-image-predownloader

Conversation

@vegaro

@vegaro vegaro commented May 7, 2026

Copy link
Copy Markdown
Member

Why

Fixes gaps in Paywalls V2 image predownloading:

  • VideoComponent fallback-source overrides were not included in the predownload pass — only the base fallbackSource was fetched
  • CarouselComponent pages and CountdownComponent sub-stacks were being manually recursed in the when branches, but the BFS traversal in PaywallComponent.filter already visits them — resulting in double-traversal

What

  • Add VideoComponent override fallback sources to the predownload pass
  • Remove redundant manual recursion for CarouselComponent.pages and CountdownComponent sub-stacks (BFS handles them; CountdownComponent moves to the no-op group with a comment)
  • Refactor StackComponent.findImageUrisToDownload to use filter { true } with an exhaustive when (single source of truth for all component types; compiler enforces coverage when new types are added)
  • Extract a List<ComponentOverride<T>>?.imageUrisToDownload helper to deduplicate the override traversal pattern
  • Add regression coverage for video fallback images, video override fallback images, and carousel page images.

Note

Low Risk
Low risk: scoped to paywall image predownload URL collection, with added regression tests to catch missed/duplicate downloads.

Overview
Fixes Paywalls V2 image predownloading by including VideoComponent fallback-source overrides in the predownload pass.

Refactors StackComponent.findImageUrisToDownload() to rely on the existing BFS PaywallComponent.filter traversal (avoiding redundant manual recursion for carousel/countdown descendants), centralizes per-component URI extraction in an exhaustive when, and adds a small helper to dedupe override URI extraction. Updates tests to cover carousel page images plus video fallback/override fallback images.

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

@vegaro vegaro added the pr:fix A bug fix label May 7, 2026
@vegaro vegaro force-pushed the cesar/paywall-localized-image-predownloader branch from b7c835b to d24abe5 Compare May 7, 2026 13:24
Include localized image values and video fallback-source overrides when collecting Paywall Components image assets.

Also deserialize video localization payloads so components_localizations can represent ThemeVideoUrls.
@vegaro vegaro force-pushed the cesar/paywall-localized-image-predownloader branch from d24abe5 to 3640228 Compare May 7, 2026 13:28
@vegaro vegaro changed the title Fix localized paywall image preloading Fix preloading localized paywall images and videos May 7, 2026
@vegaro vegaro marked this pull request as ready for review May 7, 2026 13:28
@vegaro vegaro requested review from a team as code owners May 7, 2026 13:28
@codecov

codecov Bot commented May 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.00000% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.81%. Comparing base (1bfed5e) to head (d0d52b9).

Files with missing lines Patch % Lines
...hases/utils/PaywallComponentsImagePreDownloader.kt 60.00% 0 Missing and 14 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3449      +/-   ##
==========================================
+ Coverage   79.55%   79.81%   +0.25%     
==========================================
  Files         365      365              
  Lines       14681    14686       +5     
  Branches     2002     2007       +5     
==========================================
+ Hits        11680    11722      +42     
+ Misses       2191     2145      -46     
- Partials      810      819       +9     

☔ 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 requested a review from facumenzella May 7, 2026 13:56
@vegaro vegaro changed the title Fix preloading localized paywall images and videos Fix preloading localized paywall images May 7, 2026
@vegaro vegaro force-pushed the cesar/paywall-localized-image-predownloader branch from f209775 to 72d8c3d Compare May 7, 2026 16:06
TimelineComponent was not handled in findImageUrisToDownload, causing
icon images inside timeline items to be skipped during pre-download.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pages.flatMapTo(mutableSetOf()) {
it.findImageUrisToDownload()
} +
overrides.flatMapTo(mutableSetOf()) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this was missing

(fallback?.findImageUrisToDownload().orEmpty())
}
is TimelineComponent -> {
items.flatMapTo(mutableSetOf()) { item ->

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

we were also missing this

vegaro and others added 3 commits May 8, 2026 09:38
The when expression in findImageUrisToDownload is the single source of
truth for which components produce URIs. The predicate was a duplicate
that needed to stay in sync.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@facumenzella

Copy link
Copy Markdown
Member

iOS equivalent: RevenueCat/purchases-ios#6752

Replace the else branch with explicit cases for every PaywallComponent
subtype. New subtypes will now fail to compile until they are handled,
preventing silent regressions like the TimelineComponent one.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vegaro vegaro requested a review from facumenzella May 8, 2026 09:09
@vegaro vegaro force-pushed the cesar/paywall-localized-image-predownloader branch from 430ad53 to 02a90a3 Compare May 11, 2026 05:47
}
is VideoComponent -> {
component.fallbackSource?.findImageUrisToDownload().orEmpty() +
component.overrides.orEmpty().flatMapTo(mutableSetOf()) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this was missing

component.fallbackSource?.findImageUrisToDownload().orEmpty()
}
is CountdownComponent -> {
component.countdownStack.findImageUrisToDownload() +

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this wasn't needed, the filter { true } BFS search already "visits" the stacks

@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 f7afcc9. Configure here.

it is TabsComponent ||
it is ImageComponent ||
it is CountdownComponent
}.flatMapTo(mutableSetOf()) { component ->

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.

Localized images never preloaded — production code missing

High Severity

PaywallComponentsImagePreDownloader.preDownloadImages only accepts a PaywallComponentsConfig (the component tree), and OfferingImagePreDownloader.downloadV2Images only passes componentsConfig.base — never reading componentsLocalizations. Localized image values (LocalizationData.Image) are therefore never discovered or pre-downloaded. The test expects test_localized_image_low_res.webp from the localizations map to be downloaded, but the production code has no localization handling at all, directly contradicting the PR's stated goal.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f7afcc9. Configure here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is fine, it's not a regression

@vegaro vegaro changed the title Fix preloading localized paywall images fix: preload VideoComponent fallback override images in Paywalls V2 May 11, 2026
@vegaro vegaro changed the title fix: preload VideoComponent fallback override images in Paywalls V2 Fix preload VideoComponent fallback override images May 11, 2026
@vegaro

vegaro commented May 11, 2026

Copy link
Copy Markdown
Member Author

@facumenzella I've updated the PR to just fix the couple things that I found:

  • Video overrides were not being transversed
  • Changed the when to be exhaustive
  • Cleaned up CountdownComponent being transversed on the wrong things

@vegaro vegaro requested a review from facumenzella May 11, 2026 07:27

@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 think this is correct! I wonder if we should focus on preloading stuff before launch or we should just wait for optimizations, but overall it looks legit to me

@vegaro

vegaro commented May 12, 2026

Copy link
Copy Markdown
Member Author

@facumenzella yeah this ended up being unrelated to workflows in the end. But thought including those fixes still made sense

@vegaro vegaro added this pull request to the merge queue May 12, 2026
Merged via the queue into main with commit 0af22b1 May 12, 2026
39 checks passed
@vegaro vegaro deleted the cesar/paywall-localized-image-predownloader branch May 12, 2026 16:12
github-merge-queue Bot pushed a commit that referenced this pull request May 13, 2026
**This is an automatic release.**

## RevenueCat SDK
### 📦 Dependency Updates
* [RENOVATE] Update dependency gradle to v8.14.5 (#3459) via RevenueCat
Git Bot (@RCGitBot)

## RevenueCatUI SDK
### ✨ New Features
* Pre-warm image cache for workflow step states (#3447) via Cesar de la
Vega (@vegaro)
### Paywallv2
#### ✨ New Features
* Add `close_workflow` button action (#3453) via Cesar de la Vega
(@vegaro)
#### 🐞 Bugfixes
* Fix preload VideoComponent fallback override images (#3449) via Cesar
de la Vega (@vegaro)

### 🔄 Other Changes
* Select blob source by priority and weighted random (#3458) via Toni
Rico (@tonidero)
* [AUTOMATIC] Update golden test files for backend integration tests
(#3473) via RevenueCat Git Bot (@RCGitBot)
* Clean up unreferenced topic files after successful remote-config
refresh (#3439) via Toni Rico (@tonidero)
* Cache remote config response in memory with TTL and persist to disk
(#3457) via Toni Rico (@tonidero)
* build(deps): bump fastlane from 2.233.1 to 2.234.0 (#3463) via
dependabot[bot] (@dependabot[bot])
* Update codelabs links (#3460) via Jaewoong Eum (@skydoves)
* Add RemoteConfigManager and TopicFetcher (#3437) via Toni Rico
(@tonidero)
* Add exit offers support to workflows (#3452) via Cesar de la Vega
(@vegaro)
* Update baseline profiles (#3461) via RevenueCat Git Bot (@RCGitBot)
* Add network scaffolding for remote config endpoint (#3435) via Toni
Rico (@tonidero)
* test: cover singleStepFallbackId == initialStepId edge case (#3445)
via Facundo Menzella (@facumenzella)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: this is a release/versioning update (SNAPSHOT -> final) plus
docs deployment path changes, with no functional code changes beyond
version constants.
> 
> **Overview**
> Finalizes the `10.6.0` release by switching all version references
from `10.6.0-SNAPSHOT` to `10.6.0` (root `.version`,
`gradle.properties`, `Config.frameworkVersion`, and sample/test app
`libs.versions.toml` files).
> 
> Updates documentation publishing to point at the `10.6.0` docs path
(CircleCI S3 sync target and `docs/index.html` redirect), and prepends
the `10.6.0` section to `CHANGELOG.md`/`CHANGELOG.latest.md`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
4da1697. 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