Skip to content

Add new HeaderComponent#3290

Open
vegaro wants to merge 10 commits intomainfrom
cesar/wfl-15-header-component
Open

Add new HeaderComponent#3290
vegaro wants to merge 10 commits intomainfrom
cesar/wfl-15-header-component

Conversation

@vegaro
Copy link
Copy Markdown
Member

@vegaro vegaro commented Mar 31, 2026

  • Add HeaderComponent data model mirroring the existing StickyFooterComponent pattern, a wrapper around a StackComponent pinned above the scrollable body content.
  • Add HeaderComponentStyle and HeaderComponentView on the UI side, with full style factory and rendering support
  • Wire header through the validation pipeline (OfferingToStateMapperPaywallValidationResultPaywallStateLoadedPaywallComponents)
  • Header is an optional field in components_config.base, rendered above the scrollable stack when present, below it the sticky footer (layout: header | scrollable body | footer)

Note

Medium Risk
Adds a new paywall component type and threads it through JSON deserialization, validation/state mapping, and Compose rendering, which can affect paywall layout and inset handling. Risk is moderate due to new UI composition/scroll padding logic and expanded component traversal, but changes are additive and covered by new/updated tests.

Overview
Adds a new HeaderComponent (a StackComponent wrapper) to the paywalls data model, including JSON deserialization support (type: "header") and config wiring via an optional header field in PaywallComponentsConfig.

On the UI side, introduces HeaderComponentStyle/HeaderComponentView, updates StyleFactory to build header styles (including window-insets handling and hero-image tracking), and threads the header through OfferingToStateMapperPaywallValidationResultPaywallState.

Updates LoadedPaywallComponents to render the header pinned above the scrollable main content (adding top padding equal to the measured header height when appropriate) while keeping the sticky footer behavior, and extends component traversal/unsupported-condition detection plus test coverage to include headers.

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

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 1, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.19%. Comparing base (0fa5aca) to head (e57d603).

Files with missing lines Patch % Lines
...t/purchases/paywalls/components/HeaderComponent.kt 33.33% 1 Missing and 1 partial ⚠️
...purchases/utils/PaywallComponentFilterExtension.kt 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3290      +/-   ##
==========================================
- Coverage   79.20%   79.19%   -0.02%     
==========================================
  Files         352      353       +1     
  Lines       14099    14105       +6     
  Branches     1939     1941       +2     
==========================================
+ Hits        11167    11170       +3     
- Misses       2136     2137       +1     
- Partials      796      798       +2     

☔ 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 April 1, 2026 14:19
@vegaro vegaro marked this pull request as ready for review April 1, 2026 14:19
@vegaro vegaro requested review from a team as code owners April 1, 2026 14:19
Copy link
Copy Markdown
Contributor

@tonidero tonidero left a comment

Choose a reason for hiding this comment

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

I think mostly cursor's comments + one of my own but depends on what we want the header to be able to do for this feature.

modifier = Modifier
.fillMaxWidth(),
)
}
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.

So we won't support transparent background header that allows the main content to scroll behind the header with this correct? Not sure if that's something we would want to do... If we do, I think we basically would need to draw the main content below the header, to the top, and then add a top padding to the content the size of the header.

FWIW, I know we don't do this for footers... But feels to me that this pattern might be more requested for headers?

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.

It took me a bit but I managed to get it working. The main content is drawn from the top inside a Box, with the header overlaid on top via Alignment.TopCenter. We measure the header height with onSizeChanged and conditionally add padding(top = headerHeightDp) to the scroll modifier, but only when there’s no hero image because I learnt that we handle that differently 😄 .

When there IS a hero image (we have a mainStackHasHeroImage), we skip the padding so the image renders behind the header. This way transparent headers with content scrolling behind are supported with and without hero images.

- Add HeaderComponentStyle handling to applyTopWindowInsetsIfNotYetApplied
  so the header's inner stack receives top insets (status bar / camera cutouts)
- Add HeaderComponentStyle handling to applyHorizontalWindowInsetsIfNecessary
  so landscape horizontal insets propagate through the header, mirroring
  the existing StickyFooterComponentStyle handling
- Add applyTopWindowInsets parameter to StyleFactory.create() (default true)
  so callers can opt out when another component owns the top edge
- Pass applyTopWindowInsets = config.header == null for the main scrollable
  stack in OfferingToStateMapper, preventing double top-padding when a
  header is rendered above the stack

Fixes two bugs reported in review:
  - Header missing window insets handling (cursor[bot], High severity)
  - Main stack gets top insets with header present (cursor[bot]/tonidero, Medium severity)
@emerge-tools
Copy link
Copy Markdown

emerge-tools bot commented Apr 7, 2026

📸 Snapshot Test

582 unchanged

Name Added Removed Modified Renamed Unchanged Errored Approval
TestPurchasesUIAndroidCompatibility Paparazzi
com.revenuecat.testpurchasesuiandroidcompatibility.paparazzi
0 0 0 0 257 0 N/A
TestPurchasesUIAndroidCompatibility
com.revenuecat.testpurchasesuiandroidcompatibility
0 0 0 0 325 0 N/A

🛸 Powered by Emerge Tools

@vegaro vegaro force-pushed the cesar/wfl-15-header-component branch from 9865c44 to b15fceb Compare April 8, 2026 11:39
Copy link
Copy Markdown

@cursor cursor bot left a comment

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.

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 b15fceb. Configure here.

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