Add Capacitor Android shell and mobile connection support#3848
Add Capacitor Android shell and mobile connection support#3848gabrielMalonso wants to merge 3 commits into
Conversation
- Scaffold Android Capacitor app - Wire mobile/web pairing and hosted connection support - Allow cleartext LAN/Tailscale access for paired devices
- Document Tailscale endpoints, pairing flow, and APK install steps - Add device notes and final validation checklist for mobile setups
- Add Ayu Black as a selectable theme - Wire syntax and diff rendering to the new custom theme - Map desktop sync to dark while preserving the app preference
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| padding-right: max(var(--app-safe-area-inset-right), 0px); | ||
| padding-bottom: max(var(--app-safe-area-inset-bottom), 0px); | ||
| padding-left: max(var(--app-safe-area-inset-left), 0px); |
There was a problem hiding this comment.
🟠 High src/index.css:420
The new right, bottom, and left safe-area padding on #root double-applies those insets on non-Capacitor clients. Components like ChatView already add var(--app-safe-area-inset-left/right/bottom) to their own header and composer padding, so on browsers where env(safe-area-inset-*) is non-zero (e.g. iPhone Safari/PWA) the whole app is inset once by #root and those surfaces are inset a second time. The visible result is oversized side gutters and an extra bottom gap above the home indicator. Consider limiting the additional #root padding to top only (as before) or gating the side/bottom insets to the Capacitor runtime, and let individual components own their own safe-area insets on other clients.
- padding-right: max(var(--app-safe-area-inset-right), 0px);
- padding-bottom: max(var(--app-safe-area-inset-bottom), 0px);
- padding-left: max(var(--app-safe-area-inset-left), 0px);🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/index.css around lines 420-422:
The new right, bottom, and left safe-area padding on `#root` double-applies those insets on non-Capacitor clients. Components like `ChatView` already add `var(--app-safe-area-inset-left/right/bottom)` to their own header and composer padding, so on browsers where `env(safe-area-inset-*)` is non-zero (e.g. iPhone Safari/PWA) the whole app is inset once by `#root` and those surfaces are inset a second time. The visible result is oversized side gutters and an extra bottom gap above the home indicator. Consider limiting the additional `#root` padding to top only (as before) or gating the side/bottom insets to the Capacitor runtime, and let individual components own their own safe-area insets on other clients.
| return items; | ||
| } | ||
|
|
||
| function androidToolbarButtonLabel(icon: unknown): string { |
There was a problem hiding this comment.
🟡 Medium native/StackHeader.tsx:256
androidToolbarButtonLabel returns "⋯" for every icon not explicitly listed, so any existing Android toolbar button using an icon like "arrow.clockwise", "chevron.left", or "sidebar.right" renders as an overflow-menu ellipsis instead of its intended affordance. The default case silently maps all unlisted icons to the same glyph, so refresh/back/sidebar buttons lose their visual meaning. Consider adding cases for the other icons used by existing buttons, or deriving the fallback from the icon name rather than defaulting to "⋯".
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/native/StackHeader.tsx around line 256:
`androidToolbarButtonLabel` returns `"⋯"` for every icon not explicitly listed, so any existing Android toolbar button using an icon like `"arrow.clockwise"`, `"chevron.left"`, or `"sidebar.right"` renders as an overflow-menu ellipsis instead of its intended affordance. The default case silently maps all unlisted icons to the same glyph, so refresh/back/sidebar buttons lose their visual meaning. Consider adding cases for the other icons used by existing buttons, or deriving the fallback from the icon name rather than defaulting to `"⋯"`.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 4 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d847c5b. Configure here.
| // Context of the app under test. | ||
| Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); | ||
|
|
||
| assertEquals("com.getcapacitor.app", appContext.getPackageName()); |
There was a problem hiding this comment.
Instrumented test wrong package
Low Severity
The instrumented test expects the package name com.getcapacitor.app, but the application's actual ID is tools.t3code.mobile. This mismatch causes the test assertion to fail.
Reviewed by Cursor Bugbot for commit d847c5b. Configure here.
| ); | ||
| })} | ||
| </View> | ||
| ); |
There was a problem hiding this comment.
Android header drops menu actions
High Severity
On Android, NativeHeaderToolbar replaces native header items with AndroidHeaderToolbar, which only renders NativeHeaderToolbarButton children. NativeHeaderToolbar.Menu and other toolbar item types are skipped, so screens that rely on header menus lose those actions on Android.
Reviewed by Cursor Bugbot for commit d847c5b. Configure here.
| padding-top: max(var(--app-safe-area-inset-top), 0px); | ||
| padding-right: max(var(--app-safe-area-inset-right), 0px); | ||
| padding-bottom: max(var(--app-safe-area-inset-bottom), 0px); | ||
| padding-left: max(var(--app-safe-area-inset-left), 0px); |
There was a problem hiding this comment.
Root safe area double padding
Medium Severity
#root now applies safe-area padding on all four sides, while chat header and composer chrome still add horizontal and bottom inset via --app-safe-area-inset-*. Outside html.capacitor-native, that stacks insets and can over-pad mobile browsers.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d847c5b. Configure here.
| return `${h}#token=${c}`; | ||
| const normalizedHost = h.includes("://") ? h : `https://${h}`; | ||
| const separator = normalizedHost.includes("#") ? "&" : "#"; | ||
| return `${normalizedHost}${separator}token=${encodeURIComponent(c)}`; |
There was a problem hiding this comment.
Invalid pairing URL hash fallback
Low Severity
When new URL() fails, buildPairingUrl appends &token= if the host string already contains #, which produces a malformed hash instead of a proper token query in the fragment.
Reviewed by Cursor Bugbot for commit d847c5b. Configure here.
ApprovabilityVerdict: Needs human review 2 blocking correctness issues found. This PR introduces a new Capacitor Android shell, mobile connection support, and a new theme - a substantial new feature with 2000+ lines of new code. Multiple unresolved high-severity review comments identify bugs (Android header menu actions dropped, CSS safe-area double-padding on non-Capacitor clients) that should be addressed. You can customize Macroscope's approvability policy. Learn more. |


Summary
apps/mobile-capacitor.MOBILE_CONNECTION_RUNBOOK.md.Testing
vp checkvp run typecheckNote
Medium Risk
Touches credentialed dev CORS and mobile auth/pairing paths while enabling Android cleartext for private hosts; large new surface but pairing remains required. The runbook commits personal Tailscale hostnames reviewers may want sanitized before merge.
Overview
Introduces
apps/mobile-capacitor, a Capacitor 8 Android package (tools.t3code.mobile) that buildsapps/webinto a WebView shell with cleartext/Tailscale-friendly networking, SystemBars CSS insets, and Gradle project wiring.The web app gains native-shell detection (
isCapacitorNativeApp), treats Capacitor as a hosted static client for pairing/connections, reports mobile client metadata, and addshtml.capacitor-nativelayout/safe-area handling (including--app-safe-area-inset-*). Dev server CORS now allowshttp://localhostandcapacitor://localhostwith credentials, with matching server tests.Also adds an Ayu Black theme (settings, CSS tokens, Shiki/diff theme registration) and small React Native fixes: safer pairing URL token encoding and an Android-specific header toolbar so actions clear Samsung edge affordances.
MOBILE_CONNECTION_RUNBOOK.mddocuments Tailscale pairing, APK build/install, and RN vs Capacitor flows (operator-specific hostnames; no secrets stored).Reviewed by Cursor Bugbot for commit d847c5b. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add Capacitor Android shell and mobile connection support
apps/mobile-capacitorpackage containing an Android Capacitor shell that serves the web app via../web/distover cleartext HTTP, with aMainActivityextendingBridgeActivityisCapacitorNativeAppdetection and uses it to set device metadata, adjust layout classes, and enable Capacitor-specific CSS safe-area inset handling at bootstraphttp://localhostandcapacitor://localhostorigins in developmentbuildPairingUrlto normalize hosts without a scheme, preserve existing hashes, and percent-encode tokensandroidScheme: httpenables cleartext traffic in the WebView, which applies in all builds unless restricted by network security config📊 Macroscope summarized d847c5b. 27 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.