Skip to content

chore(android): drop deprecated event and package APIs - #1219

Merged
troZee merged 2 commits into
mainfrom
chore/android-cleanup
Nov 3, 2026
Merged

troZee merged 2 commits into
mainfrom
chore/android-cleanup

Conversation

@krozniata

Copy link
Copy Markdown
Member

Summary

Test Plan

What's required for testing (prerequisites)?

What are the steps to reproduce (after prerequisites)?

Compatibility

OS Implemented
iOS ✅❌
Android ✅❌

Checklist

  • I have tested this on a device and a simulator
  • I added the documentation in README.md
  • I updated the typed files (TS and Flow)

Copilot AI lite review requested due to automatic review settings November 2, 2026 14:18
@krozniata
krozniata marked this pull request as ready for review November 2, 2026 14:18

Copilot AI 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.

🔵 Needs a closer look

The Android-only React Native migration spans package integration, generated delegate code, and Fabric event APIs, but build and runtime verification across RN 0.86–0.88 is unavailable in this review environment.

No open issues 🎉

What changed in this PR

Updates the Android implementation to use current React Native package, event, and codegen APIs while preserving existing pager behavior.

Changes:

  • Migrates package registration from ReactPackage to BaseReactPackage.
  • Updates Android events to use surface-aware constructors and getEventData().
  • Simplifies generated view-manager delegation and non-null callbacks.
  • Removes redundant pager configuration defaults.
File Description
android/​src/​main/​java/​com/​reactnativepagerview/​PagerViewViewPackage.kt Migrates package registration to BaseReactPackage.
android/​src/​main/​java/​com/​reactnativepagerview/​PagerViewViewManager.kt Uses the typed codegen delegate and simplified view-manager callbacks.
android/​src/​main/​java/​com/​reactnativepagerview/​event/​PageSelectedEvent.kt Migrates page-selection events to the surface-aware event API.
android/​src/​main/​java/​com/​reactnativepagerview/​event/​PageScrollStateChangedEvent.kt Migrates scroll-state events to the surface-aware event API.
android/​src/​main/​java/​com/​reactnativepagerview/​event/​PageScrollEvent.kt Migrates scroll events and retains finite-offset sanitization.
android/​src/​main/​java/​com/​reactnativepagerview/​ComposePagerView.kt Supplies surface IDs when dispatching events and removes redundant pager defaults.

Review effort: Lite

@apex-sentinel-staging

apex-sentinel-staging Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Apex Sentinel

Verdict: request_changes

Since the last review: 1 new · 4 still open · 2 no longer raised

5 finding(s): 1 major, 4 nit. Verdict: request_changes.

Required fixes

  • Removed receiveCommand override may stop JS commands from reaching the delegate

🟠 Major (1)

Where Finding
android/src/main/java/com/reactnativepagerview/PagerViewViewManager.kt:17 Removed receiveCommand override may stop JS commands from reaching the delegate
🔵 Nit (4)
Where Finding
android/src/main/java/com/reactnativepagerview/ComposePagerView.kt:504 Surface id resolved from the view instead of the ReactContext the dispatch already uses
android/src/main/java/com/reactnativepagerview/PagerViewViewManager.kt:113 Comment cites PagerView.tsx for a native Android prop
android/src/main/java/com/reactnativepagerview/PagerViewViewPackage.kt:17 🆕 getReactModuleInfoProvider() returns an empty map, bypassing generated module info
android/src/main/java/com/reactnativepagerview/event/PageScrollStateChangedEvent.kt:17 canCoalesce() = false added only to PageScrollStateChangedEvent is an undocumented event-delivery change

Reply under an inline comment with @apex-sentinel-staging note ... or @apex-sentinel-staging pivot ... to re-check that finding.
Comment @apex-sentinel-staging review on this conversation to run a full review.

Earlier reviews

Review of b0c60582 · 02.11.2026 14:29 UTC

Apex Sentinel

Verdict: approve

6 finding(s): 2 minor, 4 nit. Verdict: approve.

🟡 Minor (2)

Where Finding
android/src/main/java/com/reactnativepagerview/PagerViewViewManager.kt:15 receiveCommand override deleted — delegate no longer forwards commands (setPage / setPageWithoutAnimation / setScrollEnabledImperatively)
android/src/main/java/com/reactnativepagerview/PagerViewViewManager.kt:111 keyboardDismissMode prop is now a silent no-op on Android; JS dismisses it only from onPageScroll
🔵 Nit (4)
Where Finding
android/src/main/java/com/reactnativepagerview/ComposePagerView.kt:55 surfaceId captured once in the constructor from a cast that can throw
android/src/main/java/com/reactnativepagerview/ComposePagerView.kt:649 reverseLayout = false removals are unrelated to this PR's scope
android/src/main/java/com/reactnativepagerview/event/PageScrollStateChangedEvent.kt:18 canCoalesce() = false added for PageScrollStateChangedEvent only; PageScrollEvent still coalesces
android/src/main/java/com/reactnativepagerview/PagerViewViewManager.kt:106 No-op prop stubs carry inconsistent one-line comments that point outside the module

@apex-sentinel-staging apex-sentinel-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Apex Sentinel: 6 new findings on b0c6058. The verdict and the full list are in the summary comment.

@@ -19,18 +19,15 @@ class PagerViewViewManager : ViewGroupManager<ComposePagerView>(), RNCViewPagerM
const val NAME = "RNCViewPager"

@apex-sentinel-staging apex-sentinel-staging Bot Nov 2, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Major · Removed receiveCommand override may stop JS commands from reaching the delegate

The PR deletes the explicit override fun receiveCommand(root, commandId, args) { mDelegate.receiveCommand(root, commandId, args) }, leaving command dispatch to whatever the base class does with getDelegate(). Every command this library exposes goes through that path — Commands.setPage, setPageWithoutAnimation and setScrollEnabledImperatively are called from src/PagerView.tsx:93/98/106 — and the delegate (RNCViewPagerManagerDelegate) is the only thing that maps a command name string to setPage/setPageWithoutAnimation/setScrollEnabledImperatively. If the RN version's ViewGroupManager/BaseViewManager.receiveCommand does not forward to getDelegate().receiveCommand(...) (community view managers have historically had to write exactly that override, which is why it was there), all three imperative methods become silent no-ops: no crash, no error, ref.setPage(3) just does nothing. This is the more worrying case because commit ce0d489 (#​1212) just fixed setPage timing, i.e. this path is known-fragile. I could not verify the RN 0.88 base-class behaviour in this checkout (no node_modules / RN sources available), so confidence is not full — but the merge should be gated on an actual run of the example app's setPage/setPageWithoutAnimation/setScrollEnabledImperatively (e2e covers these) rather than on the Kotlin compiling.

Suggested change

Either keep the explicit receiveCommand override delegating to delegate.receiveCommand(root, commandId, args), or confirm against the RN version in example (0.88.0) that the base manager forwards commands through getDelegate(), and run the example/e2e suite exercising setPage, setPageWithoutAnimation and setScrollEnabledImperatively.

Details

persona: senior-developer

Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.

Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.

@@ -648,7 +649,6 @@ class ComposePagerView(context: Context) : FrameLayout(context) {
modifier = Modifier.fillMaxSize(),

@apex-sentinel-staging apex-sentinel-staging Bot Nov 2, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No longer raised on 58496ba.

🔵 Nit · reverseLayout = false removals are unrelated to this PR's scope

Dropping the explicit reverseLayout = false in both HorizontalPager calls is a no-op (the default is false), but it is a Compose API change bundled into a PR whose title is about deprecated event/package APIs; it also silently changes behavior on any Compose Foundation version where the parameter has no default. Split it into its own commit so a bisect over Android event regressions does not land on it.

Suggested change

Move the two reverseLayout = false removals into a separate commit (or keep them and mention them in the PR description).

Details

persona: maintainability, senior-developer

Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.

Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.

view.setOverScrollMode(value)
}
}

@apex-sentinel-staging apex-sentinel-staging Bot Nov 2, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No longer raised on 58496ba.

🔵 Nit · No-op prop stubs carry inconsistent one-line comments that point outside the module

setOverdrag and setKeyboardDismissMode keep their @ReactProp annotations and gained only an explanatory comment ("iOS only." / "Dismissed from JS on Android, see PagerView.tsx.") instead of the no-op bodies being removed. That is fine for JS compat, but the two comments use different conventions for the same kind of note and neither states what a caller should expect if they do pass the prop on Android; a reader grepping overdrag in the Android module now gets a one-line pointer to a TS file in another package. A short comment naming the JS-side file path (or a link) makes the stub self-explanatory.

Suggested change

Use one comment style for both Android no-op props and point at the file that already handles the behaviour (lib/src/PagerView.tsx) rather than a bare "see PagerView.tsx".

Details

persona: maintainability

Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.

Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

🟢 e2e: 46 passed

All 46 tests in 19 files
Test Time
🟢 tests/basic-pager.e2e.ts · 3 passed 50.6s
🟢 basic pager › in LTR › pages horizontally 18.0s
🟢 basic pager › in LTR › pages vertically 11.0s
🟢 basic pager › in RTL › pages horizontally with the reversed gesture 21.6s
🟢 tests/issues/issue-1083-modal-set-page.e2e.ts · 1 passed 9.7s
🟢 setPage called behind a native-stack modal lands on the requested page 9.7s
🟢 tests/issues/issue-1098-nested-pager.e2e.ts · 1 passed 8.2s
🟢 outer pager stays responsive after its page count changes around a nested pager 8.2s
🟢 tests/issues/issue-1154-page-change-focus.e2e.ts · 7 passed 1m 8s
🟢 leaving a page with setPage blurs its input 9.8s
🟢 setPage with an input focused lands on the target page 10.1s
🟢 leaving a page with a swipe blurs its input 8.3s
🟢 an input focused on the new page keeps focus 9.7s
🟢 an input focused on the new page keeps focus going back 10.8s
🟢 a swipe keeps the focus the new page takes from onPageSelected 9.9s
🟢 setPage keeps the focus the new page takes from onPageSelected 9.2s
🟢 tests/issues/issue-1156-nested-horizontal-scroll.e2e.ts · 3 passed 25.2s
🟢 a horizontal ScrollView in a page scrolls instead of the pager 8.4s
🟢 the pager takes the swipe once the ScrollView is at its edge 8.9s
🟢 a swipe outside the ScrollView changes the page 7.9s
🟢 tests/issues/issue-1196-set-page-after-add.e2e.ts · 6 passed 54.2s
🟢 setPageWithoutAnimation selects a page added in the same commit 7.8s
🟢 setPage animates to a page added in the same commit 8.3s
🟢 setPage from useEffect animates to a page added in the same commit 8.3s
🟢 setPageWithoutAnimation selects a page added to an empty pager in the same commit 8.2s
🟢 an index that is not there yet is ignored, not applied later 9.7s
🟢 pages that come back report the page the pager lands on once 11.8s
🟢 tests/issues/issue-1199-scroll-state.e2e.ts · 2 passed 15.6s
🟢 setPage reports settling, then idle once the page has stopped 8.1s
🟢 a swipe reports settling when the finger lifts, then idle once the page has stopped 7.5s
🟢 tests/issues/issue-1205-diagonal-swipe.e2e.ts · 2 passed 16.7s
🟢 a slanted, mostly vertical drag scrolls the list 8.5s
🟢 a slanted, mostly horizontal drag changes the page 8.2s
🟢 tests/issues/issue-219-empty-pager.e2e.ts · 3 passed 27.8s
🟢 a pager that mounts empty shows its first page when pages arrive 7.8s
🟢 a pager that loses all its pages shows them again when they come back 10.7s
🟢 setPage works as soon as pages arrive in a pager that mounted empty 9.3s
🟢 tests/issues/issue-424-swipe-cancels-press.e2e.ts · 3 passed 28.5s
🟢 a tap on a button in a page presses it 8.0s
🟢 a swipe that starts on a button in a page cancels its touch 8.1s
🟢 a swipe while the JS thread is busy does not press the button 12.4s
🟢 tests/issues/issue-965-pages-before-current.e2e.ts · 6 passed 51.5s
🟢 inserting a page before the current one keeps it visible 8.2s
🟢 inserting a page at the current index keeps the current page 8.5s
🟢 removing a page before the current one keeps it visible 8.0s
🟢 removing pages up to the current index keeps it visible 8.6s
🟢 moving the current page keeps it visible 8.6s
🟢 moving a page next to the current one keeps it rendered 9.6s
🟢 tests/issues/pr-1194-remount-initial-page.e2e.ts · 1 passed 11.5s
🟢 a pager remounted after its screen was covered starts on its own initialPage 11.5s
🟢 tests/material-top-bar.e2e.ts · 1 passed 9.5s
🟢 material top tabs survive a native-stack push and pop 9.5s
🟢 tests/native-driver-events.e2e.ts · 2 passed 10.7s
🟢 native driver events › setPage through the Animated ref drives the native value 5.7s
🟢 native driver events › a swipe drives the native value 5.0s
🟢 tests/nested-pager-view.e2e.ts · 1 passed 8.7s
🟢 nested horizontal and vertical pagers scroll independently 8.7s
🟢 tests/on-page-selected.e2e.ts · 1 passed 11.4s
🟢 onPageSelected fires an alert for every page change 11.4s
🟢 tests/scrollable-pager-view.e2e.ts · 1 passed 12.5s
🟢 pager inside a ScrollView keeps its page across vertical scrolls 12.5s
🟢 tests/smoke.e2e.ts · 1 passed 5.1s
🟢 horizontal pager pages with the panel buttons 5.1s
🟢 tests/tab-view-inside-scroll-view.e2e.ts · 1 passed 9.7s
🟢 TabView inside a ScrollView swipes tabs and scrolls the page 9.7s

e2e 0.21.3 · 7m 16s · android · run artifacts

@apex-sentinel-staging apex-sentinel-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Apex Sentinel: 1 new finding and 2 moved to a new line on 58496ba. The verdict and the full list are in the summary comment.


// The package only provides a view manager.
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = null

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🆕 🔵 Nit · getReactModuleInfoProvider() returns an empty map, bypassing generated module info

PagerViewPackage now extends BaseReactPackage but overrides getReactModuleInfoProvider() to return ReactModuleInfoProvider { emptyMap() }. RN's BaseReactPackage implements this by returning the annotation-processor-generated ReactPackageSupport.getReactModuleInfo(...) map, so this override throws away generated metadata for any @​ReactModule-annotated class in this package (PagerViewViewManager carries @​ReactModule(NAME)) and will silently swallow the metadata of every module a future version adds here — the module lookup/info path has to be updated by hand, and the empty map is exactly the kind of thing that drifts. Returning the inherited implementation (i.e. deleting this override) keeps the package module-free today and stays correct later.

Suggested change

Drop the getReactModuleInfoProvider() override and rely on BaseReactPackage's generated ReactPackageSupport-backed implementation; only supply a custom provider if a native module is actually added to this package.

Details

persona: maintainability

Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.

Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.

@krozniata
krozniata requested a review from troZee November 3, 2026 13:48
@troZee
troZee merged commit be9be24 into main Nov 3, 2026
10 of 11 checks passed
@troZee
troZee deleted the chore/android-cleanup branch November 3, 2026 17:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants