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..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 @@ -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,21 +16,24 @@ 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 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 -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,64 +61,83 @@ 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 }, - ) + 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 + 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() } - Column( - modifier = - Modifier - .fillMaxSize() - .hazeSource(LocalHazeState.current), + AnimatedVisibility( + visible = event.isFailed, + enter = fadeIn(), + exit = fadeOut() + ) { Failed() } + + AnimatedVisibility( + visible = event.isSucceeded, + enter = fadeIn(), + exit = fadeOut() ) { - AnimatedVisibility( - modifier = Modifier.fillMaxSize(), - visible = event.isLoading, - enter = fadeIn(), - exit = fadeOut(), - ) { - Loading() - } + MarkdownWebView(readme, innerPadding) + } + } + } +} - AnimatedVisibility( - visible = event.isFailed, - enter = fadeIn(), - exit = fadeOut(), - ) { - Failed() - } +@Composable +private fun TopBar( + navigator: DestinationsNavigator, + scrollBehavior: TopAppBarScrollBehavior, +) = BlurToolbar( + navigationIcon = { + IconButton(onClick = { navigator.popBackStack() }) { + Icon( + painter = painterResource(id = R.drawable.arrow_left), + contentDescription = null + ) + } + }, + title = { Text(text = stringResource(id = R.string.view_module_about_this_module)) }, + scrollBehavior = scrollBehavior, +) - AnimatedVisibility( - visible = event.isSucceeded, - enter = fadeIn(), - exit = fadeOut(), - ) { - this@Scaffold.ResponsiveContent { - AndroidView( - factory = { context -> - val options = +@SuppressLint("SetJavaScriptEnabled") +@Composable +private fun MarkdownWebView( + readme: String, + 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 { + val options = WebUIOptions( context = context, isDarkMode = userPrefs.isDarkMode(), @@ -152,42 +176,24 @@ fun ViewDescriptionScreen(readmeUrl: String) = ) WebUIView(options).apply { - setLayerType(View.LAYER_TYPE_SOFTWARE, null) + setBackgroundColor(0) + //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) - - webView.addJavascriptInterface( - arrayOf(readme), - arrayOf(String::class.java), - ) + } - webView.loadUrl(launchUrl) - }, - ) - } - } + DisposableEffect(webView) { + webView.addJavascriptInterface(arrayOf(readme), arrayOf(String::class.java)) + webView.loadUrl(launchUrl) + onDispose { + (webView.parent as? ViewGroup)?.removeView(webView) + webView.apply { + stopLoading() + removeAllViews() + destroy() } } } -@Composable -private fun TopBar( - navigator: DestinationsNavigator, - scrollBehavior: TopAppBarScrollBehavior, -) = BlurToolbar( - navigationIcon = { - IconButton(onClick = { navigator.popBackStack() }) { - Icon( - painter = painterResource(id = R.drawable.arrow_left), - contentDescription = null, - ) - } - }, - title = { Text(text = stringResource(id = R.string.view_module_about_this_module)) }, - scrollBehavior = scrollBehavior, -) + AndroidView(factory = { webView }) +}