Skip to content

Fix paywall layout direction for RTL locale overrides (PWENG-39)#3425

Merged
MonikaMateska merged 2 commits into
mainfrom
monika/fix/layout-direction-override
May 1, 2026
Merged

Fix paywall layout direction for RTL locale overrides (PWENG-39)#3425
MonikaMateska merged 2 commits into
mainfrom
monika/fix/layout-direction-override

Conversation

@MonikaMateska

@MonikaMateska MonikaMateska commented May 1, 2026

Copy link
Copy Markdown
Member

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-ios and hybrids PR

Motivation

Fixes paywall layout direction when preferredUILocaleOverride resolves to an RTL locale while the device/system locale is LTR.
Previously, Android paywalls could use the overridden locale for localized strings while still inheriting the system Compose LocalLayoutDirection, so RTL languages like Hebrew and Arabic could render translated text but keep LTR layout behavior.

Resolves: PWENG-39

Changes

  • Adds a locale-to-Compose-layout-direction helper backed by Android Configuration.layoutDirection.
  • Applies the resolved locale layout direction to legacy paywalls.
  • Applies the resolved locale layout direction to V2/components paywalls.
  • Adds unit coverage for RTL and LTR locale direction resolution.
Screen_recording_20260501_134422.webm

Note

Medium Risk
Changes paywall composition locals to force LocalLayoutDirection based on the resolved/overridden locale, which could subtly affect layout/alignment across both legacy and components paywalls. Risk is limited to UI rendering (no purchase/auth logic), but may introduce visual regressions in LTR/RTL edge cases.

Overview
Fixes paywall rendering when a preferredUILocaleOverride resolves to an RTL language by deriving a Compose LayoutDirection from the resolved locale and providing it via LocalLayoutDirection.

Applies this override in both legacy template paywalls (InternalPaywall) and V2/components paywalls (LoadedPaywallComponents), and adds a new Locale.toLayoutDirection() helper with Android instrumentation tests covering RTL (Hebrew/Arabic/Farsi) and LTR locales.

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

@MonikaMateska MonikaMateska requested a review from a team as a code owner May 1, 2026 11:47
@MonikaMateska MonikaMateska added the pr:fix A bug fix label May 1, 2026

@JayShortway JayShortway 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.

Thanks for fixing this!

) {
ComponentView(
style = state.stack,
CompositionLocalProvider(LocalLayoutDirection provides state.locale.toJavaLocale().toLayoutDirection()) {

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.

This is probably fine, but at the risk of premature optimization: we could remember the layout direction, to avoid creating a new Configuration object on every recomposition. Something like:

val layoutDirection = remember(state.locale) { state.locale.toJavaLocale().toLayoutDirection() }
CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {

Again, feel free to ignore.

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.

That's a great recommendation, will apply it, thanks!

@codecov

codecov Bot commented May 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.45%. Comparing base (0e387a3) to head (8fc3352).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3425   +/-   ##
=======================================
  Coverage   79.45%   79.45%           
=======================================
  Files         362      362           
  Lines       14539    14539           
  Branches     1976     1976           
=======================================
  Hits        11552    11552           
  Misses       2190     2190           
  Partials      797      797           

☔ 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.

@MonikaMateska MonikaMateska added this pull request to the merge queue May 1, 2026
Merged via the queue into main with commit 93b74fd May 1, 2026
37 checks passed
@MonikaMateska MonikaMateska deleted the monika/fix/layout-direction-override branch May 1, 2026 13:24
github-merge-queue Bot pushed a commit that referenced this pull request May 19, 2026
### Motivation
After #3425 was merged, the affected customer identified layout bugs in
RTL mode.
This PR fixes the main one reported (timeline), as well as other
quick-win ones.

### Description
- Fixes timeline text constraints in RTL so text starts from the correct
edge without overlapping the icon.
- Makes workflow slide transitions respect RTL layout direction.
- Replaces remaining physical custom-layout placement calls with
`placeRelative`.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are limited to Compose layout/constraint behavior
and transition direction math, primarily affecting RTL rendering and
slide animations.
> 
> **Overview**
> Fixes several RTL rendering issues in paywall UI.
> 
> Workflow step slide animations now account for `LayoutDirection` so
horizontal transitions reverse correctly in RTL, and call sites pass the
current layout direction into `workflowTransition`.
> 
> Custom `Modifier.layout` usages were updated to use `placeRelative`
(instead of physical `place`) for header overlay and top-padding
helpers, and timeline constraints were rewritten to use `linkTo(...)`
(removing end-barrier usage) so title/description text aligns from the
correct edge without overlapping icons in RTL.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
9710048. 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 Jun 5, 2026
**This is an automatic release.**

## RevenueCat SDK
### ✨ New Features
* Add optional support for setting obfuscated account id to product
changes (RevenueCat#3428) via Mark Villacampa (@MarkVillacampa)

## RevenueCatUI SDK
### Paywallv2
#### ✨ New Features
* Add slide transition to workflow paywalls (RevenueCat#3418) via Cesar de la Vega
(@vegaro)
* Workflow state & ViewModel infrastructure (RevenueCat#3416) via Cesar de la Vega
(@vegaro)
#### 🐞 Bugfixes
* Fix paywall layout direction for RTL locale overrides (PWENG-39)
(RevenueCat#3425) via Monika Mateska (@MonikaMateska)
* Apply ripple shape clip on a sibling Box to avoid clipping content
(RevenueCat#3395) via Toni Rico (@tonidero)

### 🔄 Other Changes
* build(deps): bump fastlane-plugin-revenuecat_internal from `21e02ec`
to `af7bb5c` (RevenueCat#3442) via dependabot[bot] (@dependabot[bot])
* Abstract workflow page transition animation behind sealed class
(RevenueCat#3430) via Cesar de la Vega (@vegaro)
* Add `single_step_fallback_id` field to `PublishedWorkflow` (RevenueCat#3436) via
Cesar de la Vega (@vegaro)
* build(deps): bump fastlane-plugin-revenuecat_internal from `2d11430`
to `21e02ec` (RevenueCat#3429) via dependabot[bot] (@dependabot[bot])
* Generalize `PaywallComponentsScaffold` for workflow reuse (RevenueCat#3417) via
Cesar de la Vega (@vegaro)
* perf: pre-warm workflow paywall step states off-thread (RevenueCat#3420) via
Cesar de la Vega (@vegaro)
* Update baseline profiles (RevenueCat#3427) via RevenueCat Git Bot (@RCGitBot)
* build(deps): bump fastlane-plugin-revenuecat_internal from `d24ab26`
to `2d11430` (RevenueCat#3426) via dependabot[bot] (@dependabot[bot])
* Replace unauthenticated SDKMAN install with SHA-pinned orb command
(RevenueCat#3407) via Rick (@rickvdl)
* Auto load paywall in paywall tester via local.properties (RevenueCat#3405) via
Cesar de la Vega (@vegaro)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: this is a version/release cut that mainly updates version
strings, changelogs, and doc deployment targets with no functional logic
changes beyond version identifiers.
> 
> **Overview**
> Cuts the `10.4.0` release by removing `-SNAPSHOT` across the project
(core `VERSION_NAME`, `Config.frameworkVersion`, sample/test app
dependency versions, and the root `.version` file).
> 
> Updates release collateral and publishing to point at `10.4.0`,
including changelogs (`CHANGELOG.md`/`CHANGELOG.latest.md`), docs
redirect (`docs/index.html`), and the CircleCI `docs-deploy` S3 sync
path (from `10.4.0-SNAPSHOT` to `10.4.0`).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f7b3604. 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.

4 participants