From 1294a90e5246b87f38cc148d6ecae30b6ed876e6 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Wed, 9 Sep 2026 09:01:27 +0300 Subject: [PATCH] fix(mobile): keep Android content clear of the navigation bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Android 15+ enforces edge-to-edge, and Capacitor stops padding the WebView once it can hand the insets to the page instead — so the app draws under the gesture/navigation bar. Only the top inset was ever consumed: full cover surfaces ignored the bottom one entirely, which is why a settings list ran under the bar, and the chat shell reserved half of it, which is enough for a home indicator but not for a bar that swallows taps. Reserve the full inset in the shell on Android and give the surfaces that own the bottom edge — fullscreen surfaces, the workspace drawer, bottom sheets — an opt-in class that pads them. The sessions drawer already did this through its footer, so it stays as it is. Capacitor reports a zero bottom inset while the keyboard is up, so none of this stacks with the keyboard inset. iOS deliberately keeps its softer visual inset. Testing: package type-check and lint; drove the mobile surface in a browser with the Android platform class and a simulated 48px inset (shell and surfaces reserve exactly that, drawer footer unchanged, and removing the class returns every surface to zero). --- packages/ui/src/apps/MobileFullscreenSurface.tsx | 4 ++-- packages/ui/src/apps/MobileWorkspaceDrawer.tsx | 2 +- .../ui/src/components/ui/MobileOverlayPanel.tsx | 2 +- packages/ui/src/styles/mobile.css | 16 ++++++++++++++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/apps/MobileFullscreenSurface.tsx b/packages/ui/src/apps/MobileFullscreenSurface.tsx index 26d58bdd..4c5a4034 100644 --- a/packages/ui/src/apps/MobileFullscreenSurface.tsx +++ b/packages/ui/src/apps/MobileFullscreenSurface.tsx @@ -175,7 +175,7 @@ export const MobileFullscreenSurface: React.FC = ( 'flex flex-col bg-background text-foreground', isDialog ? 'h-[min(88dvh,860px)] w-full max-w-[720px] overflow-hidden rounded-2xl border border-border/70 shadow-[0_24px_64px_rgb(0_0_0_/_0.32)]' - : 'oc-keyboard-inset-surface fixed inset-0 z-50', + : 'oc-keyboard-inset-surface oc-bottom-safe-surface fixed inset-0 z-50', )} style={isDialog ? { // Scale/fade instead of the push slide: the card is not a navigation @@ -249,7 +249,7 @@ export const MobileFullscreenSurface: React.FC = ( return createPortal(
= ({ const content = (