feat: optional native pull-to-refresh on iOS and Android

Merged
RI
1d ago
+625-74

Summary

Opt-in native pull-to-refresh. Off by default: nothing is attached to the WebView until setPullToRefresh({ enabled: true }), and enabled: false restores the original view setup.

await NativeNavigation.setPullToRefresh({ enabled: true, tintColor: '#007aff' });
NativeNavigation.addListener('pullToRefresh', async () => {
  await reloadData();
  await NativeNavigation.endPullToRefresh();
});
iOSAndroid
  • iOS: simultaneous pan gesture on the WebView plus the system UIActivityIndicatorView, placed below the native navbar, with a haptic when the pull arms. UIRefreshControl was tried first, but it never fires when the page scrolls an inner element (#app, Ionic content), which is the usual Capacitor setup.
  • Android: the WebView is wrapped in a SwipeRefreshLayout only while enabled (new dependency androidx.swiperefreshlayout:1.1.0, overridable with androidxSwipeRefreshLayoutVersion). The spinner sits below the status bar and navbar.
  • Both platforms use the scroll offset the page already reports (window, #app, [data-cap-native-navigation-scroll]), so the gesture only starts when the list is at the top. The offset resets on finishTransition.
  • Web: no-op.
  • Example app: "Pull to refresh" toggle in the Navbar playground.
  • README: new section with both demo clips.

Test plan

  • bun run build, bun run lint (ESLint + Prettier)
  • iOS xcodebuild test: 15 tests pass, including the new pull-to-refresh tests
  • Android ./gradlew build test
  • Recorded on the iPhone 17 simulator and the Android API 36 emulator with the example app: the refresh fires, the spinner shows below the navbar, and endPullToRefresh() hides it
  • Physical device check
  • SwiftLint: two errors in existing code (setTabbar length, large tuple); the new files lint clean

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

Summary by CodeRabbit

  • New Features
    • Added opt-in pull-to-refresh on iOS and Android. Configure spinner colors, listen for refresh events, and stop the spinner when content is ready.
    • Added pull-to-refresh controls to the example app. On the web, these controls leave refresh behavior to the browser.
  • Documentation
    • Added setup instructions, platform notes, and API references for pull-to-refresh.