Fix Paywalls V2 root z-layer stacks not scrolling in bounded containers#6873
Conversation
…hases-ios into monika/fix/sticky-footer
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 9929edb. Configure here.
| self | ||
| self.paywallMarkingVerticalScrollContainer(axis: axis) { | ||
| self | ||
| } |
There was a problem hiding this comment.
iOS 15 fallback omits ancestor-scroll environment propagation
Low Severity
The paywallMarkingVerticalScrollContainer call (which sets paywallAncestorScrollsVertically to true for descendants) is only added inside the if #available(iOS 16.0, ...) branches. The else fallback path (iOS 15) at lines 178–182 still creates a scroll view via .scrollable(if: true) but never propagates the environment flag. Before this PR z-layers never scrolled, so this was harmless. Now that PaywallZLayerScrollPolicy.shouldApplyScroll can enable z-layer scrolling, a nested z-layer on iOS 15 would see ancestorScrollsVertically == false and create its own conflicting vertical scroll view.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 9929edb. Configure here.


Checklist
purchases-androidand hybridsMotivation
Fixes an iPad layout bug where Paywalls V2 paywalls with a root z-layer stack (not a vertical stack wrapping a z-layer) could not scroll in bounded containers such as form sheets. Tall hero images pushed the sticky footer off-screen, while the same paywall worked on iPhone.
Previously, z-layer stacks never applied scrolling (case .zlayer: self), unlike vertical and horizontal stacks. This change enables scrolling for z-layer stacks when appropriate, using ViewThatFits so content fills the container when it fits and scrolls only when it overflows.
Resolves: https://revenuecat.slack.com/archives/C093NCRHZ0T/p1779954980296169
Before:

After:

Description
I added unit tests, and ran paywall-rendering-validation locally against paywalls from paywall-preview-resources, looked all good, no obvious regressions.
Manually verified on iPad: tall hero scrolls, footer stays reachable
Note
Medium Risk
Changes Paywalls V2 SwiftUI layout and scroll behavior for z-layer stacks; risk is mitigated by explicit scroll policy, ancestor tracking, and new unit/snapshot tests, but paywall rendering regressions are still possible across devices.
Overview
Fixes Paywalls V2 layouts where the root stack is a z-layer (not a vertical stack wrapping a z-layer): tall content could not scroll inside bounded containers (e.g. iPad form sheets), so sticky footers were pushed off-screen.
The PR adds scroll policy and environment plumbing so z-layer stacks can use the same
ViewThatFits/ vertical scroll path as other stacks when appropriate.RootViewpublishes whether the root is a z-layer; scroll views mark vertical ancestor scrolling so nested z-layers do not add competing scrollers.StackComponentViewapplies vertical scrolling to z-layers whenPaywallZLayerScrollPolicyallows it (root z-layer or stack scroll enabled, and no vertical scroll ancestor).Coverage includes unit tests for the policy and snapshot tests for sticky-footer + root z-layer on iPad sheet and iPhone sizes.
Reviewed by Cursor Bugbot for commit 94bd840. Bugbot is set up for automated code reviews on this repo. Configure here.