From 4a146f874a3ec2aadec5ad126a3cf6dde0262521 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 15:00:24 +0000 Subject: [PATCH] fix(browser): show load progress once, on the pill grabber The full-screen nsite/napplet and web browser windows drew two progress indicators while a page loaded: the 3dp View ProgressBar pinned to the top edge (added in June, before the pill existed) and the progress line under the pill's grabber that the Compose pill redesign added. The redesign moved loading state onto the grabber but never removed the old bar, which also painted over the grabber's top edge. Drop the old View bar from NappletHostActivity and NappletBrowserActivity. The grabber line (and the ring around Stop in the open pill) is now the only indicator, which matches the embedded tabs and the design doc. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01JmY5pZFXST3LWsEr9hcHHr --- .../napplethost/NappletBrowserActivity.kt | 24 ++------------ .../napplethost/NappletHostActivity.kt | 32 +++---------------- 2 files changed, 7 insertions(+), 49 deletions(-) diff --git a/nappletHost/src/main/kotlin/com/vitorpamplona/amethyst/napplethost/NappletBrowserActivity.kt b/nappletHost/src/main/kotlin/com/vitorpamplona/amethyst/napplethost/NappletBrowserActivity.kt index 1d7bfc3308..3000dfb1a9 100644 --- a/nappletHost/src/main/kotlin/com/vitorpamplona/amethyst/napplethost/NappletBrowserActivity.kt +++ b/nappletHost/src/main/kotlin/com/vitorpamplona/amethyst/napplethost/NappletBrowserActivity.kt @@ -27,7 +27,6 @@ import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.content.pm.PackageManager -import android.content.res.ColorStateList import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.Color @@ -142,10 +141,6 @@ class NappletBrowserActivity : ComponentActivity() { // The pill, find, console and page dialogs — the shared Compose chrome (see BrowserChromeHost). private var chrome: BrowserChromeHost? = null - // A thin determinate progress bar pinned to the top edge (browser-style), driven by the chrome - // client's onProgressChanged; hidden at 100%. - private val topProgressBar by lazy { buildTopProgressBar() } - // The NIP-07 shim + browser extras, injected at document start in this window and in its popups. private var shimJs: String = "" @@ -348,8 +343,6 @@ class NappletBrowserActivity : ComponentActivity() { } this.root = root chrome = buildChrome().also { it.attach(root) } - // Added last so the thin loading bar paints above the content (and over the grabber's top edge). - root.addView(topProgressBar) setContentView(root) // Pad by the system bars + cutout AND the IME: on an edge-to-edge window (enforced for targetSdk // 35+ on Android 15+) windowSoftInputMode=adjustResize no longer shrinks the window, so without @@ -1840,26 +1833,13 @@ class NappletBrowserActivity : ComponentActivity() { } /** - * A thin determinate progress bar pinned to the top edge, like a browser's. Driven by - * [BrowserChromeClient.onProgressChanged]: visible while the page loads and gone at 100%. + * Feeds the page's load progress to the pill, which draws it under the grabber (and as a ring around + * Stop when open); cleared at 100%. */ - private fun buildTopProgressBar(): ProgressBar = - ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal).apply { - max = 100 - isIndeterminate = false - visibility = View.GONE - progressTintList = ColorStateList.valueOf(resolveThemeColor(android.R.attr.colorPrimary)) - layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dp(3), Gravity.TOP) - } - - /** Shows the thin top bar at [progress]% while loading, hiding it once the page is fully loaded. */ private fun updateLoadProgress(progress: Int) { if (progress >= 100) { - topProgressBar.visibility = View.GONE updateUi { copy(loadProgress = null, chrome = chrome.copy(isLoading = false)) } } else { - topProgressBar.progress = progress - topProgressBar.visibility = View.VISIBLE updateUi { copy(loadProgress = progress / 100f) } } } diff --git a/nappletHost/src/main/kotlin/com/vitorpamplona/amethyst/napplethost/NappletHostActivity.kt b/nappletHost/src/main/kotlin/com/vitorpamplona/amethyst/napplethost/NappletHostActivity.kt index 03cfe11266..1195275a40 100644 --- a/nappletHost/src/main/kotlin/com/vitorpamplona/amethyst/napplethost/NappletHostActivity.kt +++ b/nappletHost/src/main/kotlin/com/vitorpamplona/amethyst/napplethost/NappletHostActivity.kt @@ -24,7 +24,6 @@ import android.annotation.SuppressLint import android.content.ComponentName import android.content.Intent import android.content.ServiceConnection -import android.content.res.ColorStateList import android.content.res.Configuration import android.net.Uri import android.os.Bundle @@ -198,10 +197,6 @@ class NappletHostActivity : ComponentActivity() { // first paint, so there's never a blank/dark gap between the index probe and the shell's first frame. private var loadingView: View? = null - // A thin determinate progress bar pinned to the top edge (browser-style), driven by the - // WebChromeClient's onProgressChanged; hidden at 100%. - private val topProgressBar by lazy { buildTopProgressBar() } - // The trusted pull-down pill, find and the developer console — the shared Compose chrome. private var chrome: BrowserChromeHost? = null @@ -354,9 +349,6 @@ class NappletHostActivity : ComponentActivity() { addView(contentFrame, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)) } chrome = buildChrome().also { it.attach(root) } - // Added last so the thin loading bar paints above the content (and over the grabber's top edge); it's - // GONE except while loading, so it never obscures the trusted chrome. - root.addView(topProgressBar) setContentView(root) // Activities are edge-to-edge by default on recent Android; pad by the system bar, display-cutout // and IME insets so neither the chrome nor the applet draws under the system bars or the soft @@ -736,7 +728,7 @@ class NappletHostActivity : ComponentActivity() { } } - /** Drives the top loading bar, opens the file picker, and forwards `console.*` output to the panel. */ + /** Feeds load progress to the pill, opens the file picker, and forwards `console.*` output to the panel. */ private inner class NappletWebChromeClient : WebChromeClient() { /** * Without this override WebView's base implementation returns false and shows no picker at all, so @@ -784,14 +776,14 @@ class NappletHostActivity : ComponentActivity() { return true } - /** Shows the thin top bar at [progress]% while loading, hiding it once the page is fully loaded. */ + /** + * Feeds the page's load progress to the pill, which draws it under the grabber (and as a ring around + * Stop when open); cleared at 100%. + */ private fun updateLoadProgress(progress: Int) { if (progress >= 100) { - topProgressBar.visibility = View.GONE chrome?.let { it.ui = it.ui.copy(loadProgress = null, chrome = it.ui.chrome.copy(isLoading = false)) } } else { - topProgressBar.progress = progress - topProgressBar.visibility = View.VISIBLE chrome?.let { it.ui = it.ui.copy(loadProgress = progress / 100f, chrome = it.ui.chrome.copy(isLoading = true)) } } } @@ -1082,20 +1074,6 @@ class NappletHostActivity : ComponentActivity() { if (brokerMessenger != null) sendToBroker(msg) } - /** - * A thin determinate progress bar pinned to the top edge, like a browser's. Driven by - * [NappletWebChromeClient.onProgressChanged]: visible while the shell + verified blobs load and gone - * at 100%, so a slow load (e.g. a large bundle over Tor) shows progress instead of a blank dark WebView. - */ - private fun buildTopProgressBar(): ProgressBar = - ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal).apply { - max = 100 - isIndeterminate = false - visibility = View.GONE - progressTintList = ColorStateList.valueOf(resolveThemeColor(android.R.attr.colorPrimary)) - layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dp(3), Gravity.TOP) - } - /** Persists the new routing choice in the main process, then relaunches this screen to apply it. */ private fun setNetworkMode(newUseTor: Boolean) { val msg =