From ebf700f60563099c5ef082d0ea1e59be26c4564b Mon Sep 17 00:00:00 2001 From: Der_Googler <54764558+DerGoogler@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:16:43 +0100 Subject: [PATCH 1/5] Refactor ViewDescriptionScreen for improved readability --- .../moduleView/ViewDescriptionScreen.kt | 215 ++++++++---------- 1 file changed, 101 insertions(+), 114 deletions(-) diff --git a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt index 421aeaf8..d41b1f7d 100644 --- a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt +++ b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt @@ -2,9 +2,11 @@ package com.dergoogler.mmrl.ui.screens.moduleView import android.annotation.SuppressLint import android.view.View +import android.view.ViewGroup import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize @@ -14,12 +16,14 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -28,7 +32,6 @@ import com.dergoogler.mmrl.R import com.dergoogler.mmrl.app.Event.Companion.isFailed import com.dergoogler.mmrl.app.Event.Companion.isLoading import com.dergoogler.mmrl.app.Event.Companion.isSucceeded -import com.dergoogler.mmrl.ext.none import com.dergoogler.mmrl.network.compose.requestString import com.dergoogler.mmrl.ui.activity.webui.interfaces.MarkdownInterface import com.dergoogler.mmrl.ui.component.Failed @@ -56,124 +59,52 @@ const val launchUrl = "https://mui.kernelsu.org/internal/assets/markdown.html" @SuppressLint("SetJavaScriptEnabled") @Composable @Destination -fun ViewDescriptionScreen(readmeUrl: String) = - LocalScreenProvider { - val density = LocalDensity.current - val navigator = LocalDestinationsNavigator.current - val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() - val userPrefs = LocalUserPreferences.current +fun ViewDescriptionScreen(readmeUrl: String) = LocalScreenProvider { + val density = LocalDensity.current + val navigator = LocalDestinationsNavigator.current + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + val userPrefs = LocalUserPreferences.current + val bottomBarPaddingValues = LocalMainScreenInnerPaddings.current - var readme by remember { mutableStateOf("") } - val event = - requestString( - url = readmeUrl, - onSuccess = { readme = it }, - ) - - Scaffold( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), - topBar = { - TopBar( - scrollBehavior = scrollBehavior, - navigator = navigator, - ) - }, - contentWindowInsets = WindowInsets.none, - ) { innerPadding -> - val bottomBarPaddingValues = LocalMainScreenInnerPaddings.current - - Column( - modifier = - Modifier - .fillMaxSize() - .hazeSource(LocalHazeState.current), - ) { - AnimatedVisibility( - modifier = Modifier.fillMaxSize(), - visible = event.isLoading, - enter = fadeIn(), - exit = fadeOut(), - ) { - Loading() - } - - AnimatedVisibility( - visible = event.isFailed, - enter = fadeIn(), - exit = fadeOut(), - ) { - Failed() - } - - AnimatedVisibility( - visible = event.isSucceeded, - enter = fadeIn(), - exit = fadeOut(), - ) { - this@Scaffold.ResponsiveContent { - AndroidView( - factory = { context -> - val options = - WebUIOptions( - context = context, - isDarkMode = userPrefs.isDarkMode(), - colorScheme = userPrefs.colorScheme(context), - ) + var readme by remember { mutableStateOf("") } + val event = requestString( + url = readmeUrl, + onSuccess = { readme = it }, + ) - val assetsLoader = - wxAssetLoader( - handlers = - listOf( - "/internal/" to - internalPathHandler( - options, - Insets( - top = - with(density) { - val pad = - innerPadding.calculateTopPadding() - val px = - with(density) { pad.toPx() }.toInt() - (px / this.density).toInt() - }, - bottom = - with(density) { - val pad = - bottomBarPaddingValues.calculateBottomPadding() - val px = - with(density) { pad.toPx() }.toInt() - (px / this.density).toInt() - }, - left = 0, - right = 0, - ), - ), - ), - ) + Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { TopBar(scrollBehavior = scrollBehavior, navigator = navigator) }, + contentWindowInsets = WindowInsets.none, + ) { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .hazeSource(LocalHazeState.current) + ) { + AnimatedVisibility( + modifier = Modifier.fillMaxSize(), + visible = event.isLoading, + enter = fadeIn(), + exit = fadeOut() + ) { Loading() } - WebUIView(options).apply { - setLayerType(View.LAYER_TYPE_SOFTWARE, null) - webViewClient = WXClient(options, assetsLoader) - } - }, - update = { webView -> - // Remove the interface if it already exists to prevent crashes - // when the screen is reopened (e.g., after navigating back) - webView.removeJavascriptInterface(MarkdownInterface.INTERFACE_NAME) + AnimatedVisibility( + visible = event.isFailed, + enter = fadeIn(), + exit = fadeOut() + ) { Failed() } - webView.addJavascriptInterface( - arrayOf(readme), - arrayOf(String::class.java), - ) - - webView.loadUrl(launchUrl) - }, - ) - } - } + AnimatedVisibility( + visible = event.isSucceeded, + enter = fadeIn(), + exit = fadeOut() + ) { + MarkdownWebView(readme, userPrefs, innerPadding, bottomBarPaddingValues) } } } +} @Composable private fun TopBar( @@ -184,10 +115,66 @@ private fun TopBar( IconButton(onClick = { navigator.popBackStack() }) { Icon( painter = painterResource(id = R.drawable.arrow_left), - contentDescription = null, + contentDescription = null ) } }, title = { Text(text = stringResource(id = R.string.view_module_about_this_module)) }, scrollBehavior = scrollBehavior, ) + +@SuppressLint("SetJavaScriptEnabled") +@Composable +private fun MarkdownWebView( + readme: String, + userPrefs: LocalUserPreferences, + innerPadding: androidx.compose.foundation.layout.PaddingValues, + bottomBarPaddingValues: androidx.compose.foundation.layout.PaddingValues +) { + val context = LocalContext.current + val density = LocalDensity.current + + val webView = remember { + WebUIView( + WebUIOptions( + context = context, + isDarkMode = userPrefs.isDarkMode(), + colorScheme = userPrefs.colorScheme(context) + ) + ).apply { + setLayerType(View.LAYER_TYPE_HARDWARE, null) + webViewClient = WXClient( + options = WebUIOptions(context, userPrefs.isDarkMode(), userPrefs.colorScheme(context)), + loader = wxAssetLoader( + listOf( + "/internal/" to internalPathHandler( + options = WebUIOptions(context, userPrefs.isDarkMode(), userPrefs.colorScheme(context)), + insets = Insets( + top = with(density) { innerPadding.calculateTopPadding().toPx().toInt() }, + bottom = with(density) { bottomBarPaddingValues.calculateBottomPadding().toPx().toInt() }, + left = 0, + right = 0 + ) + ) + ) + ) + ) + } + } + + DisposableEffect(webView) { + webView.addJavascriptInterface(arrayOf(readme), arrayOf(String::class.java)) + webView.loadUrl(launchUrl) + onDispose { + (webView.parent as? ViewGroup)?.removeView(webView) + webView.apply { + stopLoading() + webViewClient = null + removeAllViews() + destroy() + } + } + } + + AndroidView(factory = { webView }, modifier = Modifier.fillMaxSize()) +} From 16d3dfda47f364526784e811ec77e623f27fd6c0 Mon Sep 17 00:00:00 2001 From: Der_Googler <54764558+DerGoogler@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:34:21 +0100 Subject: [PATCH 2/5] Refactor MarkdownWebView to simplify WebUIView setup --- .../moduleView/ViewDescriptionScreen.kt | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt index d41b1f7d..d80bcfde 100644 --- a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt +++ b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt @@ -127,39 +127,57 @@ private fun TopBar( @Composable private fun MarkdownWebView( readme: String, - userPrefs: LocalUserPreferences, - innerPadding: androidx.compose.foundation.layout.PaddingValues, - bottomBarPaddingValues: androidx.compose.foundation.layout.PaddingValues + innerPadding: androidx.compose.foundation.layout.PaddingValues ) { val context = LocalContext.current val density = LocalDensity.current - + val userPrefs = LocalUserPreferences.current + val bottomBarPaddingValues = LocalMainScreenInnerPaddings.current + val webView = remember { - WebUIView( - WebUIOptions( - context = context, - isDarkMode = userPrefs.isDarkMode(), - colorScheme = userPrefs.colorScheme(context) - ) - ).apply { - setLayerType(View.LAYER_TYPE_HARDWARE, null) - webViewClient = WXClient( - options = WebUIOptions(context, userPrefs.isDarkMode(), userPrefs.colorScheme(context)), - loader = wxAssetLoader( - listOf( - "/internal/" to internalPathHandler( - options = WebUIOptions(context, userPrefs.isDarkMode(), userPrefs.colorScheme(context)), - insets = Insets( - top = with(density) { innerPadding.calculateTopPadding().toPx().toInt() }, - bottom = with(density) { bottomBarPaddingValues.calculateBottomPadding().toPx().toInt() }, - left = 0, - right = 0 - ) - ) - ) - ) - ) - } + val options = + WebUIOptions( + context = context, + isDarkMode = userPrefs.isDarkMode(), + colorScheme = userPrefs.colorScheme(context), + ) + + val assetsLoader = + wxAssetLoader( + handlers = + listOf( + "/internal/" to + internalPathHandler( + options, + Insets( + top = + with(density) { + val pad = + innerPadding.calculateTopPadding() + val px = + with(density) { pad.toPx() }.toInt() + (px / this.density).toInt() + }, + bottom = + with(density) { + val pad = + bottomBarPaddingValues.calculateBottomPadding() + val px = + with(density) { pad.toPx() }.toInt() + (px / this.density).toInt() + }, + left = 0, + right = 0, + ), + ), + ), + ) + + WebUIView(options).apply { + setBackgroundColor(0) + //setLayerType(View.LAYER_TYPE_SOFTWARE, null) + webViewClient = WXClient(options, assetsLoader) + } } DisposableEffect(webView) { @@ -176,5 +194,5 @@ private fun MarkdownWebView( } } - AndroidView(factory = { webView }, modifier = Modifier.fillMaxSize()) + AndroidView(factory = { webView }) } From a5b678a97d691f3bdb5a90867e89b8b80f32fadc Mon Sep 17 00:00:00 2001 From: Der_Googler <54764558+DerGoogler@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:35:21 +0100 Subject: [PATCH 3/5] Update ViewDescriptionScreen.kt --- .../mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt index d80bcfde..9ee9de31 100644 --- a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt +++ b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt @@ -100,7 +100,7 @@ fun ViewDescriptionScreen(readmeUrl: String) = LocalScreenProvider { enter = fadeIn(), exit = fadeOut() ) { - MarkdownWebView(readme, userPrefs, innerPadding, bottomBarPaddingValues) + MarkdownWebView(readme, innerPadding) } } } From 4d06158646ea193805fac13a8a96fc32d9dad2b0 Mon Sep 17 00:00:00 2001 From: Der_Googler <54764558+DerGoogler@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:42:40 +0100 Subject: [PATCH 4/5] Refactor webView disposal logic Removed assignment of webViewClient to null during disposal. --- .../mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt index 9ee9de31..a1ada6dd 100644 --- a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt +++ b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.viewinterop.AndroidView import com.dergoogler.mmrl.R +import com.dergoogler.mmrl.ext.none import com.dergoogler.mmrl.app.Event.Companion.isFailed import com.dergoogler.mmrl.app.Event.Companion.isLoading import com.dergoogler.mmrl.app.Event.Companion.isSucceeded @@ -187,7 +188,6 @@ private fun MarkdownWebView( (webView.parent as? ViewGroup)?.removeView(webView) webView.apply { stopLoading() - webViewClient = null removeAllViews() destroy() } From 8a977edd2df79bda6abebe8044f9db0f10eb19f6 Mon Sep 17 00:00:00 2001 From: Der_Googler <54764558+DerGoogler@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:48:25 +0100 Subject: [PATCH 5/5] Add nestedScroll import to ViewDescriptionScreen.kt --- .../mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt index a1ada6dd..76d62a7a 100644 --- a/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt +++ b/app/src/main/kotlin/com/dergoogler/mmrl/ui/screens/moduleView/ViewDescriptionScreen.kt @@ -22,6 +22,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity