From 55f8f2da9036f5ee252ddce04633f5e29d74ba4e Mon Sep 17 00:00:00 2001 From: weishu Date: Tue, 20 Feb 2024 23:25:57 +0800 Subject: [PATCH] manager: support full screen for webui --- .../me/weishu/kernelsu/ui/MainActivity.kt | 6 +- .../me/weishu/kernelsu/ui/screen/WebScreen.kt | 65 +++++++++++++++---- manager/app/src/main/res/values/themes.xml | 1 + 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt index c5a7e671..5d1efdb9 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController +import androidx.navigation.compose.currentBackStackEntryAsState import com.google.accompanist.navigation.animation.rememberAnimatedNavController import com.ramcosta.composedestinations.DestinationsNavHost import com.ramcosta.composedestinations.navigation.popBackStack @@ -44,8 +45,11 @@ class MainActivity : ComponentActivity() { KernelSUTheme { val navController = rememberAnimatedNavController() val snackbarHostState = remember { SnackbarHostState() } + val navBackStackEntry by navController.currentBackStackEntryAsState() + val route = navBackStackEntry?.destination?.route + val showBottomBar = route == null || !route.startsWith("web_screen") Scaffold( - bottomBar = { BottomBar(navController) }, + bottomBar = { if (showBottomBar) BottomBar(navController) }, snackbarHost = { SnackbarHost(snackbarHostState) } ) { innerPadding -> CompositionLocalProvider( diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/WebScreen.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/WebScreen.kt index d9d5a2df..e38ea11b 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/WebScreen.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/WebScreen.kt @@ -1,18 +1,24 @@ package me.weishu.kernelsu.ui.screen import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.view.Window import android.webkit.JavascriptInterface import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import androidx.lifecycle.lifecycleScope import com.google.accompanist.web.WebView import com.google.accompanist.web.rememberWebViewState @@ -26,7 +32,6 @@ import me.weishu.kernelsu.ui.util.createRootShell import me.weishu.kernelsu.ui.util.serveModule import java.net.ServerSocket - @SuppressLint("SetJavaScriptEnabled") @Destination @Composable @@ -38,18 +43,20 @@ fun WebScreen(navigator: DestinationsNavigator, moduleId: String, moduleName: St } val lifecycleOwner = LocalLifecycleOwner.current + val context = LocalContext.current DisposableEffect(Unit) { onDispose { + if (WebViewInterface.isHideSystemUI && context is Activity) { + showSystemUI(context.window) + } lifecycleOwner.lifecycleScope.launch { stopServer(port) } } } - Scaffold(topBar = { - TopBar(moduleName) - }) { innerPadding -> + Scaffold { innerPadding -> WebView( state = rememberWebViewState(url = "http://localhost:$port"), Modifier @@ -59,25 +66,38 @@ fun WebScreen(navigator: DestinationsNavigator, moduleId: String, moduleName: St android.webkit.WebView(context).apply { settings.javaScriptEnabled = true settings.domStorageEnabled = true - addJavascriptInterface(WebViewInterface(), "ksu") + addJavascriptInterface(WebViewInterface(context), "ksu") } }) } } -class WebViewInterface { +class WebViewInterface(val context: Context) { + + companion object { + var isHideSystemUI: Boolean = false + } + @JavascriptInterface fun exec(cmd: String): String { val shell = createRootShell() return ShellUtils.fastCmd(shell, cmd) } -} + @JavascriptInterface + fun fullScreen(enable: Boolean) { + if (context is Activity) { + Handler(Looper.getMainLooper()).post { + if (enable) { + hideSystemUI(context.window) + } else { + showSystemUI(context.window) + } + isHideSystemUI = enable + } + } + } -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun TopBar(title: String) { - TopAppBar(title = { Text(title) }) } private suspend fun getFreePort(): Int { @@ -94,4 +114,21 @@ private suspend fun stopServer(port: Int) { .execute() } } +} + +private fun hideSystemUI(window: Window) { + WindowCompat.setDecorFitsSystemWindows(window, false) + WindowInsetsControllerCompat(window, window.decorView).let { controller -> + controller.hide(WindowInsetsCompat.Type.systemBars()) + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } +} + +private fun showSystemUI(window: Window) { + WindowCompat.setDecorFitsSystemWindows(window, true) + WindowInsetsControllerCompat( + window, + window.decorView + ).show(WindowInsetsCompat.Type.systemBars()) } \ No newline at end of file diff --git a/manager/app/src/main/res/values/themes.xml b/manager/app/src/main/res/values/themes.xml index bf6e252f..325416c0 100644 --- a/manager/app/src/main/res/values/themes.xml +++ b/manager/app/src/main/res/values/themes.xml @@ -2,5 +2,6 @@ \ No newline at end of file