From 4a68b4add412f84e894f11bc5b121aa4ca50d290 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 18 Dec 2025 09:46:03 +0100 Subject: [PATCH] fix(android): show backdrop behind WebView --- .../steipete/clawdis/node/ui/RootScreen.kt | 101 +++++++++++++++++- .../main/res/xml/network_security_config.xml | 2 + 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/apps/android/app/src/main/java/com/steipete/clawdis/node/ui/RootScreen.kt b/apps/android/app/src/main/java/com/steipete/clawdis/node/ui/RootScreen.kt index 79def591e..51d32bb23 100644 --- a/apps/android/app/src/main/java/com/steipete/clawdis/node/ui/RootScreen.kt +++ b/apps/android/app/src/main/java/com/steipete/clawdis/node/ui/RootScreen.kt @@ -4,10 +4,15 @@ import android.annotation.SuppressLint import android.Manifest import android.content.pm.PackageManager import android.graphics.Color +import android.util.Log import android.view.View import android.webkit.WebView import android.webkit.WebSettings +import android.webkit.WebResourceError +import android.webkit.WebResourceRequest +import android.webkit.WebResourceResponse import android.webkit.WebViewClient +import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -19,6 +24,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.background import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.Icon @@ -36,7 +42,10 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color as ComposeColor import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView @@ -71,6 +80,7 @@ fun RootScreen(viewModel: MainViewModel) { PackageManager.PERMISSION_GRANTED Box(modifier = Modifier.fillMaxSize()) { + CanvasBackdrop(modifier = Modifier.fillMaxSize()) CanvasView(viewModel = viewModel, modifier = Modifier.fillMaxSize()) } @@ -143,6 +153,7 @@ private fun OverlayIconButton( @Composable private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) { val context = LocalContext.current + val isDebuggable = (context.applicationInfo.flags and android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) != 0 AndroidView( modifier = modifier, factory = { @@ -151,12 +162,98 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) // Some embedded web UIs (incl. the "background website") use localStorage/sessionStorage. settings.domStorageEnabled = true settings.mixedContentMode = WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE - webViewClient = WebViewClient() + webViewClient = + object : WebViewClient() { + override fun onReceivedError( + view: WebView, + request: WebResourceRequest, + error: WebResourceError, + ) { + if (!isDebuggable) return + if (!request.isForMainFrame) return + Log.e("ClawdisWebView", "onReceivedError: ${error.errorCode} ${error.description} ${request.url}") + } + + override fun onReceivedHttpError( + view: WebView, + request: WebResourceRequest, + errorResponse: WebResourceResponse, + ) { + if (!isDebuggable) return + if (!request.isForMainFrame) return + Log.e( + "ClawdisWebView", + "onReceivedHttpError: ${errorResponse.statusCode} ${errorResponse.reasonPhrase} ${request.url}", + ) + } + } setBackgroundColor(Color.TRANSPARENT) setBackgroundResource(0) - setLayerType(View.LAYER_TYPE_HARDWARE, null) + // WebView transparency + HW acceleration can render as solid black on some Android/WebView builds. + // Prefer correct alpha blending since we render the idle backdrop in Compose underneath. + setLayerType(View.LAYER_TYPE_SOFTWARE, null) viewModel.canvas.attach(this) } }, ) } + +@Composable +private fun CanvasBackdrop(modifier: Modifier = Modifier) { + val base = MaterialTheme.colorScheme.background + + Canvas(modifier = modifier.background(base)) { + // Subtle idle backdrop; also acts as fallback when WebView content is transparent or fails to load. + drawRect( + brush = + Brush.linearGradient( + colors = + listOf( + ComposeColor(0xFF0A2034), + ComposeColor(0xFF070A10), + ComposeColor(0xFF250726), + ), + start = Offset(0f, 0f), + end = Offset(size.width, size.height), + ), + ) + + val step = 48f * density + val lineColor = ComposeColor.White.copy(alpha = 0.028f) + var x = -step + while (x < size.width + step) { + drawLine(color = lineColor, start = Offset(x, 0f), end = Offset(x, size.height), strokeWidth = 1f) + x += step + } + var y = -step + while (y < size.height + step) { + drawLine(color = lineColor, start = Offset(0f, y), end = Offset(size.width, y), strokeWidth = 1f) + y += step + } + + drawRect( + brush = + Brush.radialGradient( + colors = listOf(ComposeColor(0xFF2A71FF).copy(alpha = 0.22f), ComposeColor.Transparent), + center = Offset(size.width * 0.15f, size.height * 0.20f), + radius = size.minDimension * 0.9f, + ), + ) + drawRect( + brush = + Brush.radialGradient( + colors = listOf(ComposeColor(0xFFFF008A).copy(alpha = 0.18f), ComposeColor.Transparent), + center = Offset(size.width * 0.85f, size.height * 0.30f), + radius = size.minDimension * 0.75f, + ), + ) + drawRect( + brush = + Brush.radialGradient( + colors = listOf(ComposeColor(0xFF00D1FF).copy(alpha = 0.14f), ComposeColor.Transparent), + center = Offset(size.width * 0.60f, size.height * 0.90f), + radius = size.minDimension * 0.85f, + ), + ) + } +} diff --git a/apps/android/app/src/main/res/xml/network_security_config.xml b/apps/android/app/src/main/res/xml/network_security_config.xml index 667745f88..68016a00b 100644 --- a/apps/android/app/src/main/res/xml/network_security_config.xml +++ b/apps/android/app/src/main/res/xml/network_security_config.xml @@ -1,5 +1,7 @@ + + clawdis.internal