android icon indicating copy to clipboard operation
android copied to clipboard

Make the navigation bar and status bar transparent (edge-to-edge)

Open MathisP75 opened this issue 1 year ago • 2 comments

Is your feature request related to a problem? Please describe. Both the navigation bar and the status bar are solid colors and do not allow for other elements to go under them, making the application feel less polished.

Describe the solution you'd like Making the application display edge-to-edge content, as described here: https://developer.android.com/develop/ui/views/layout/edge-to-edge

Describe alternatives you've considered, if any Not applicable.

Additional context Example of an app handling edge-to-edge incorrectly (notice how the side menu goes under the navigation bar and the status bar): Screenshot_20240801-192313.png

Example of an app handling edge-to-edge correctly (notice how the side menu goes under both the navigation bar and the status bar, since they are truly transparent): Screenshot_20240801-192429.png

MathisP75 avatar Aug 01 '24 23:08 MathisP75

Unfortunately this isn't as easy as you might think because of the WebView. Last time I tried the problem was that information about insets wasn't set correctly on the WebView, making it impossible for the frontend to adapt. That means content will end up behind the system navigation, which is especially problematic when using button navigation or when you have a tall status bar due to a camera/cutout. It looks like the bug is still unresolved: https://issuetracker.google.com/issues/40699457.

(I thought we already had an issue for this, but can't find it.)

jpelgrom avatar Aug 02 '24 05:08 jpelgrom

Ah well that sucks, it would have been neat. Let's hope Google does something about it.

MathisP75 avatar Aug 02 '24 10:08 MathisP75

What do you think about passing this inset values from android activity to webview on page load? I created a quick demo in Android Compose:

Scaffold (modifier = Modifier.fillMaxSize()) { padding ->
    AndroidView(
        factory = { context ->
            WebView(context).apply {
                settings.javaScriptEnabled = true
                webViewClient = object : WebViewClient() {
                    override fun onPageFinished(view: WebView?, url: String?) {
                        super.onPageFinished(view, url)
                        val safeInsetTop = (padding.calculateTopPadding().value)
                        val safeInsetBottom = (padding.calculateBottomPadding().value)
                        val safeAreaJs = """
                        document.documentElement.style.setProperty('--android-safe-area-inset-top', '${safeInsetTop}px');
                        document.documentElement.style.setProperty('--android-safe-area-inset-bottom', '${safeInsetBottom}px');
                    """.trimIndent()
                        evaluateJavascript(safeAreaJs, null)
                    }
                }
            }
        },
        update = { webView ->
            webView.loadUrl("http://10.0.2.2:8000")
        },
    )
}

In above snippet we can see that Scaffold component (edge-to-edge) give us padding property (our insets) and we are executing JS after page load that sets css properties. Then HA page instead of relying on env() can have custom property that works on both android and ios.

:root {
  --insets-top: var(--android-safe-area-inset-top, env(safe-area-inset-top));
  --insets-bottom: var(--android-safe-area-inset-bottom, env(safe-area-inset-bottom));
}
.main {
      padding-top: var(--insets-top);
}
.bottom {
   position: fixed;
   bottom: 0;
   padding-bottom: var(--insets-bottom);
   background-color: white;
   display: block;
   width: 100%;
  }

Below we can see that text have proper padding on top and bottom of screen

Image Image

Gregman-js avatar Jan 19 '25 13:01 Gregman-js

This looks a bit hacked together to me but considering how the WebView still doesn't do inset support correctly (it now kinda works on first load, but breaks after navigation) if the frontend team is OK, I think we can consider it as well.

Not as easy as you might think however because HA/frontend version is decoupled from the app and users might have multiple servers on different HA versions.

jpelgrom avatar Jan 21 '25 16:01 jpelgrom

I created this PR with your comment in mind. So WebView will be renedered under navigation bar only if below condition is matched (version value will depend on this relese)

serverManager.getServer()?.version?.isAtLeast(2024, 1)

Gregman-js avatar Jan 25 '25 22:01 Gregman-js