Skip to content

feat(mobile): deep links + system share + external browser (Phase 6a)#36

Merged
JohnMcLear merged 3 commits into
mainfrom
feat/mobile-phase6a-deeplinks-share-browser
May 11, 2026
Merged

feat(mobile): deep links + system share + external browser (Phase 6a)#36
JohnMcLear merged 3 commits into
mainfrom
feat/mobile-phase6a-deeplinks-share-browser

Conversation

@JohnMcLear

Copy link
Copy Markdown
Member

Summary

Phase 6a of the mobile rollout (Phase 6 split, see plan
docs/superpowers/plans/2026-05-11-etherpad-mobile-phase6a-deeplinks-share-browser.md):

  • System share — floating "📤" button in the top-right of the active
    iframe calls @capacitor/share. Web fallback uses navigator.share
    when present.
  • External browser — adjacent "↗" button opens the current pad URL in
    a Chrome Custom Tab via @capacitor/browser. Doubles as the user-driven
    X-Frame-Options DENY escape hatch (auto-detection of DENY needs a
    native hook on WebChromeClient — that's Phase 6b).
  • Deep links@capacitor/app's appUrlOpen listener parses
    etherpad://... and https://*/p/... URLs using the shell's existing
    parsePadUrl. Matches by origin against persisted workspaces — opens
    the pad on match, prompts addWorkspace (with initialServerUrl +
    initialPadName in dialogContext) on miss.
  • AndroidManifest intent filters declare the etherpad custom scheme
    • an HTTPS app-link filter for /p/* with android:autoVerify="true".
  • Mobile bundle exposes window.__test_handleUrl for Playwright; the
    Capacitor appUrlOpen event itself is harder to fire from a browser
    test, but the URL routing logic is what we actually want to verify.

Deferred to Phase 6b (needs hardware to validate)

  • Custom Android PadWebviewPermissionsPlugin (Kotlin) that overrides
    WebChromeClient.onPermissionRequest and maps the WebView's
    VIDEO_CAPTURE / AUDIO_CAPTURE to runtime CAMERA /
    RECORD_AUDIO. Lands when a real Android device is available for
    ep_webrtc smoke testing.
  • iOS equivalent (WKUIDelegate.requestMediaCapturePermissionFor) —
    same constraint, plus the iOS GA is a v2 milestone.
  • Auto-detect X-Frame DENY → switch the user into the in-app browser
    automatically rather than waiting for the manual "↗" tap. Requires
    the same WebChromeClient hook.

Smoke tests

6 mobile Playwright cases now (added 2 in this PR):

# Test
1 empty state → AddWorkspaceDialog
2 persisted workspace → rail
3 open pad → iframe with right src + lang
4 open dialog → iframes hidden
5 share + external-browser actions appear over the active pad
6 deep link to a known workspace opens the pad in that workspace

Test plan

  • CI green on pnpm typecheck across shell + desktop + mobile
  • CI green on pnpm test (204 shell + 281 desktop + 6 mobile = 491 total)
  • CI green on pnpm test:e2e (Playwright Electron, unchanged surface)

🤖 Generated with Claude Code

…nk handler

- AndroidManifest: etherpad:// custom scheme + https /p/* with autoVerify.
- main.tsx wires App.addListener('appUrlOpen') → parsePadUrl → either
  open in matching workspace's tab store or prompt to add the workspace.
- PadActionsOverlay (share + external-browser) renders on the active iframe.

Native permissions plugin (Android Kotlin, camera/mic delegation) lands
separately as Phase 6b once a real device is available to validate.
Adds two Playwright cases:
- share + external-browser actions appear over the active pad
- deep link to a known workspace opens the pad in that workspace

main.tsx also exposes window.__test_handleUrl so Playwright can invoke
the deep-link entry point without needing to fire a real appUrlOpen.
@qodo-code-review

Copy link
Copy Markdown
ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@JohnMcLear
JohnMcLear merged commit bbdebc3 into main May 11, 2026
7 of 9 checks passed
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.

1 participant