From 3b6a32b2f86ac5d8c5de2cb8902655191df74793 Mon Sep 17 00:00:00 2001 From: Dorian Date: Mon, 27 Jul 2026 10:19:11 +0100 Subject: [PATCH] =?UTF-8?q?fix(companion):=20app=20webview=20content=20cle?= =?UTF-8?q?ars=20the=20status=20bar;=20HTTPS=20toggle=20on=20add/edit=20?= =?UTF-8?q?=E2=80=94=200.5.21?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - In-app browser pages (node apps) now start below the status bar again: the WebView stays edge-to-edge (page colour fills the bar) and a body{padding-top:} injection pushes content down — the pre-edge-to-edge look without the black bar. - Add/Edit server in the menu now has a Use HTTPS toggle (was scheme-locked; edit preserved the old scheme, add forced http). Co-Authored-By: Claude Fable 5 --- Android/app/build.gradle.kts | 4 +- .../archipelago/app/ui/components/NESMenu.kt | 39 ++++++++++++++++--- .../app/ui/screens/WebViewScreen.kt | 31 +++++++++++++++ 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/Android/app/build.gradle.kts b/Android/app/build.gradle.kts index cfc5c8b5..f7fbdf60 100644 --- a/Android/app/build.gradle.kts +++ b/Android/app/build.gradle.kts @@ -11,8 +11,8 @@ android { applicationId = "com.archipelago.app" minSdk = 26 targetSdk = 35 - versionCode = 40 - versionName = "0.5.20" + versionCode = 41 + versionName = "0.5.21" vectorDrawables { useSupportLibrary = true diff --git a/Android/app/src/main/java/com/archipelago/app/ui/components/NESMenu.kt b/Android/app/src/main/java/com/archipelago/app/ui/components/NESMenu.kt index 1fb283cc..2ee124bd 100644 --- a/Android/app/src/main/java/com/archipelago/app/ui/components/NESMenu.kt +++ b/Android/app/src/main/java/com/archipelago/app/ui/components/NESMenu.kt @@ -131,14 +131,15 @@ private fun MenuPanel( var nm by remember { mutableStateOf("") } var addr by remember { mutableStateOf("") } var pwd by remember { mutableStateOf("") } + var https by remember { mutableStateOf(false) } fun resetForm() { - nm = ""; addr = ""; pwd = ""; showAdd = false; editing = null + nm = ""; addr = ""; pwd = ""; https = false; showAdd = false; editing = null } fun startEdit(server: ServerEntry) { editing = server - nm = server.name; addr = server.address; pwd = server.password + nm = server.name; addr = server.address; pwd = server.password; https = server.useHttps showAdd = false } @@ -146,10 +147,10 @@ private fun MenuPanel( if (addr.isBlank()) return val orig = editing if (orig != null) { - // Preserve fields the compact form doesn't expose (scheme, port). - onEditServer(orig, orig.copy(address = addr, password = pwd, name = nm)) + // Preserve port (compact form doesn't expose it); scheme is now editable. + onEditServer(orig, orig.copy(address = addr, useHttps = https, password = pwd, name = nm)) } else { - onAddServer(ServerEntry(addr, false, password = pwd, name = nm)) + onAddServer(ServerEntry(addr, https, password = pwd, name = nm)) } resetForm() } @@ -249,6 +250,34 @@ private fun MenuPanel( contentAlignment = Alignment.Center, ) { Text("OK", color = BitcoinOrange, fontSize = 14.sp, fontWeight = FontWeight.Bold) } } + // HTTPS scheme toggle (available on both add and edit). + Row( + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(ROW_R)) + .clickable { https = !https } + .padding(vertical = 2.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text("Use HTTPS", color = TextMuted, fontSize = 13.sp) + Box( + Modifier + .width(46.dp).height(26.dp) + .clip(RoundedCornerShape(13.dp)) + .background(if (https) BitcoinOrange.copy(alpha = 0.9f) else RowBg) + .border(1.dp, if (https) BitcoinOrange else RowBorder, RoundedCornerShape(13.dp)), + contentAlignment = if (https) Alignment.CenterEnd else Alignment.CenterStart, + ) { + Box( + Modifier + .padding(horizontal = 3.dp) + .size(20.dp) + .clip(RoundedCornerShape(10.dp)) + .background(if (https) Color.White else TextMuted), + ) + } + } } } else { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(10.dp)) { diff --git a/Android/app/src/main/java/com/archipelago/app/ui/screens/WebViewScreen.kt b/Android/app/src/main/java/com/archipelago/app/ui/screens/WebViewScreen.kt index 7f44dfbc..a61e96e8 100644 --- a/Android/app/src/main/java/com/archipelago/app/ui/screens/WebViewScreen.kt +++ b/Android/app/src/main/java/com/archipelago/app/ui/screens/WebViewScreen.kt @@ -185,6 +185,35 @@ private fun injectSafeAreaVars(view: WebView) { ) } +/** In-app browser pages (node apps + same-node links) don't consume the + * neode-ui `--safe-area-top` var, so with the WebView drawing edge-to-edge + * their content ran up under the status bar. Pad the document body down by + * the status-bar height: the padded strip shows the page's OWN background + * (padding is inside the element), so the bar keeps the page colour while + * content starts below it — the pre-edge-to-edge look, without the black bar. + * Idempotent; runs on start (early) and finish (after the app rewrites head). */ +private fun injectTopInset(view: WebView) { + val insets = view.rootWindowInsets ?: return + val density = view.resources.displayMetrics.density + val sat = (insets.getInsets(android.view.WindowInsets.Type.statusBars()).top / density).toInt() + if (sat <= 0) return + view.evaluateJavascript( + """ + (function() { + var s = document.getElementById('archy-top-inset'); + if (!s) { + s = document.createElement('style'); + s.id = 'archy-top-inset'; + (document.head || document.documentElement).appendChild(s); + } + s.textContent = + 'body{padding-top:${sat}px!important;box-sizing:border-box!important;}'; + })(); + """.trimIndent(), + null, + ) +} + /** True when a TCP listener answers at [base]'s host:port within [timeoutMs]. */ private fun tcpAnswers(base: String, timeoutMs: Int): Boolean = try { val u = android.net.Uri.parse(base) @@ -1011,12 +1040,14 @@ private fun InAppBrowser( webViewClient = object : WebViewClient() { override fun onPageStarted(view: WebView?, u: String?, favicon: Bitmap?) { loading = true + view?.let { injectTopInset(it) } } override fun onPageFinished(view: WebView?, u: String?) { loading = false canGoBack = view?.canGoBack() == true canGoForward = view?.canGoForward() == true + view?.let { injectTopInset(it) } } override fun doUpdateVisitedHistory(view: WebView?, u: String?, isReload: Boolean) {