From 24582128c5b9034a6925abaf88f9dc9922b0cfbb Mon Sep 17 00:00:00 2001 From: Dorian Date: Mon, 27 Jul 2026 17:10:26 +0100 Subject: [PATCH] fix(ui): re-pad mobile dashboard when Android injects safe-area top MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mobile nav sampled --safe-area-top once at mount, but the companion WebView injects it asynchronously. An authenticated session mounts the dashboard before the injection lands (fresh installs mount after login, long after it), so the content padding baked in 0 while the fixed tab bar grew by the real inset — content slid underneath by exactly the status-bar height, the update-install-only overlap. Re-read on the WebView's new archy-insets event, with a retry ladder as fallback for APKs that predate the event. Co-Authored-By: Claude Fable 5 --- .../views/dashboard/DashboardMobileNav.vue | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/neode-ui/src/views/dashboard/DashboardMobileNav.vue b/neode-ui/src/views/dashboard/DashboardMobileNav.vue index dbe88cd8..12f5dc3b 100644 --- a/neode-ui/src/views/dashboard/DashboardMobileNav.vue +++ b/neode-ui/src/views/dashboard/DashboardMobileNav.vue @@ -208,6 +208,11 @@ function onResize() { updateTabBarHeight() } +function onInsetsInjected() { + readSafeAreaTop() + updateTabBarHeight() +} + onMounted(() => { updateTabBarHeight() // Re-measure after the first paint: on mount the bar may not have its final @@ -216,13 +221,21 @@ onMounted(() => { requestAnimationFrame(updateTabBarHeight) readSafeAreaTop() window.addEventListener('resize', onResize) - // Re-read after WebView injection has had time to run. The injected - // safe-area-bottom padding changes the bar's height, so re-measure too. - setTimeout(() => { readSafeAreaTop(); updateTabBarHeight() }, 500) + // The Android WebView injects --safe-area-top asynchronously and fires this + // event when it lands. An authenticated session mounts the dashboard BEFORE + // the injection (fresh installs mount after login, long after it), so a + // one-shot read here bakes in 0 and content slides under the growing fixed + // tab bar — the update-install-only overlap bug. + window.addEventListener('archy-insets', onInsetsInjected) + // Fallback retry ladder for APKs that predate the event. + for (const delay of [500, 1500, 3000, 6000]) { + setTimeout(onInsetsInjected, delay) + } }) onBeforeUnmount(() => { window.removeEventListener('resize', onResize) + window.removeEventListener('archy-insets', onInsetsInjected) }) // Re-measure on route changes