manager: make action execution screen have the same behavior as Magisk
based on pr https://github.com/tiann/KernelSU/pull/2321 * Magisk's behavior: Hide Bottom Navbar, Show close button if failed or success and removed automatic exit when module execution success.
This commit is contained in:
@@ -24,6 +24,7 @@ import androidx.navigation.compose.rememberNavController
|
|||||||
import com.ramcosta.composedestinations.DestinationsNavHost
|
import com.ramcosta.composedestinations.DestinationsNavHost
|
||||||
import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationStyle
|
import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationStyle
|
||||||
import com.ramcosta.composedestinations.generated.NavGraphs
|
import com.ramcosta.composedestinations.generated.NavGraphs
|
||||||
|
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
|
||||||
import com.ramcosta.composedestinations.spec.NavHostGraphSpec
|
import com.ramcosta.composedestinations.spec.NavHostGraphSpec
|
||||||
import com.ramcosta.composedestinations.spec.RouteOrDirection
|
import com.ramcosta.composedestinations.spec.RouteOrDirection
|
||||||
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
|
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
|
||||||
@@ -39,6 +40,10 @@ import androidx.core.content.edit
|
|||||||
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
|
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
|
||||||
import com.sukisu.ultra.ui.webui.initPlatform
|
import com.sukisu.ultra.ui.webui.initPlatform
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
private inner class ThemeChangeContentObserver(
|
private inner class ThemeChangeContentObserver(
|
||||||
@@ -94,6 +99,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
// 确保应用正确的语言设置
|
// 确保应用正确的语言设置
|
||||||
applyLanguageSetting()
|
applyLanguageSetting()
|
||||||
|
|
||||||
|
// 应用自定义 DPI
|
||||||
applyCustomDpi()
|
applyCustomDpi()
|
||||||
|
|
||||||
// Enable edge to edge
|
// Enable edge to edge
|
||||||
@@ -152,6 +158,12 @@ class MainActivity : ComponentActivity() {
|
|||||||
KernelSUTheme {
|
KernelSUTheme {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
val snackBarHostState = remember { SnackbarHostState() }
|
val snackBarHostState = remember { SnackbarHostState() }
|
||||||
|
val currentDestination = navController.currentBackStackEntryAsState().value?.destination
|
||||||
|
|
||||||
|
val showBottomBar = when (currentDestination?.route) {
|
||||||
|
ExecuteModuleActionScreenDestination.route -> false // Hide for ExecuteModuleActionScreen
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
|
||||||
// pre-init platform to faster start WebUI X activities
|
// pre-init platform to faster start WebUI X activities
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@@ -159,7 +171,15 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
bottomBar = { BottomBar(navController) },
|
bottomBar = {
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = showBottomBar,
|
||||||
|
enter = slideInVertically(initialOffsetY = { it }) + fadeIn(),
|
||||||
|
exit = slideOutVertically(targetOffsetY = { it }) + fadeOut()
|
||||||
|
) {
|
||||||
|
BottomBar(navController)
|
||||||
|
}
|
||||||
|
},
|
||||||
contentWindowInsets = WindowInsets(0, 0, 0, 0)
|
contentWindowInsets = WindowInsets(0, 0, 0, 0)
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
package com.sukisu.ultra.ui.screen
|
package com.sukisu.ultra.ui.screen
|
||||||
|
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
|
import androidx.compose.foundation.layout.defaultMinSize
|
||||||
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
|
import androidx.compose.foundation.layout.only
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.Save
|
import androidx.compose.material.icons.filled.Save
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -30,7 +37,6 @@ import androidx.compose.ui.input.key.key
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.dropUnlessResumed
|
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
@@ -55,7 +61,11 @@ fun ExecuteModuleActionScreen(navigator: DestinationsNavigator, moduleId: String
|
|||||||
val snackBarHost = LocalSnackbarHost.current
|
val snackBarHost = LocalSnackbarHost.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
var actionResult: Boolean
|
var isActionRunning by rememberSaveable { mutableStateOf(true) }
|
||||||
|
|
||||||
|
BackHandler(enabled = isActionRunning) {
|
||||||
|
// Disable back button if action is running
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
if (text.isNotEmpty()) {
|
if (text.isNotEmpty()) {
|
||||||
@@ -76,33 +86,43 @@ fun ExecuteModuleActionScreen(navigator: DestinationsNavigator, moduleId: String
|
|||||||
onStderr = {
|
onStderr = {
|
||||||
logContent.append(it).append("\n")
|
logContent.append(it).append("\n")
|
||||||
}
|
}
|
||||||
).let {
|
)
|
||||||
actionResult = it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (actionResult) navigator.popBackStack()
|
isActionRunning = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopBar(
|
TopBar(
|
||||||
onBack = dropUnlessResumed {
|
isActionRunning = isActionRunning,
|
||||||
navigator.popBackStack()
|
|
||||||
},
|
|
||||||
onSave = {
|
onSave = {
|
||||||
scope.launch {
|
if (!isActionRunning) {
|
||||||
val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault())
|
scope.launch {
|
||||||
val date = format.format(Date())
|
val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault())
|
||||||
val file = File(
|
val date = format.format(Date())
|
||||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
|
val file = File(
|
||||||
"KernelSU_module_action_log_${date}.log"
|
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
|
||||||
)
|
"KernelSU_module_action_log_${date}.log"
|
||||||
file.writeText(logContent.toString())
|
)
|
||||||
snackBarHost.showSnackbar("Log saved to ${file.absolutePath}")
|
file.writeText(logContent.toString())
|
||||||
|
snackBarHost.showSnackbar("Log saved to ${file.absolutePath}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
floatingActionButton = {
|
||||||
|
if (!isActionRunning) {
|
||||||
|
ExtendedFloatingActionButton(
|
||||||
|
text = { Text(text = stringResource(R.string.close)) },
|
||||||
|
icon = { Icon(Icons.Filled.Close, contentDescription = null) },
|
||||||
|
onClick = {
|
||||||
|
navigator.popBackStack()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contentWindowInsets = WindowInsets.safeDrawing,
|
||||||
snackbarHost = { SnackbarHost(snackBarHost) }
|
snackbarHost = { SnackbarHost(snackBarHost) }
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
KeyEventBlocker {
|
KeyEventBlocker {
|
||||||
@@ -130,16 +150,14 @@ fun ExecuteModuleActionScreen(navigator: DestinationsNavigator, moduleId: String
|
|||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
|
private fun TopBar(isActionRunning: Boolean, onSave: () -> Unit = {}) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text(stringResource(R.string.action)) },
|
title = { Text(stringResource(R.string.action)) },
|
||||||
navigationIcon = {
|
|
||||||
IconButton(
|
|
||||||
onClick = onBack
|
|
||||||
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
|
|
||||||
},
|
|
||||||
actions = {
|
actions = {
|
||||||
IconButton(onClick = onSave) {
|
IconButton(
|
||||||
|
onClick = onSave,
|
||||||
|
enabled = !isActionRunning
|
||||||
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.Save,
|
imageVector = Icons.Filled.Save,
|
||||||
contentDescription = stringResource(id = R.string.save_log),
|
contentDescription = stringResource(id = R.string.save_log),
|
||||||
@@ -147,4 +165,4 @@ private fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,7 @@
|
|||||||
<string name="install_inactive_slot">Instal ke slot nonaktif (setelah OTA)</string>
|
<string name="install_inactive_slot">Instal ke slot nonaktif (setelah OTA)</string>
|
||||||
<string name="grant_root_failed">Gagal memberikan akses root!</string>
|
<string name="grant_root_failed">Gagal memberikan akses root!</string>
|
||||||
<string name="open">Buka</string>
|
<string name="open">Buka</string>
|
||||||
|
<string name="close">Tutup</string>
|
||||||
<string name="settings_check_update">Cek terbaru</string>
|
<string name="settings_check_update">Cek terbaru</string>
|
||||||
<string name="settings_check_update_summary">Cek terbaru setiap membuka aplikasi</string>
|
<string name="settings_check_update_summary">Cek terbaru setiap membuka aplikasi</string>
|
||||||
<string name="settings_uninstall_permanent_message">Hapus permanen KernelSU (root dan modul).</string>
|
<string name="settings_uninstall_permanent_message">Hapus permanen KernelSU (root dan modul).</string>
|
||||||
|
|||||||
@@ -113,6 +113,7 @@
|
|||||||
<string name="grant_root_failed">获取 root 失败!</string>
|
<string name="grant_root_failed">获取 root 失败!</string>
|
||||||
<string name="action">执行</string>
|
<string name="action">执行</string>
|
||||||
<string name="open">打开</string>
|
<string name="open">打开</string>
|
||||||
|
<string name="close">关闭</string>
|
||||||
<string name="enable_web_debugging">启用 WebView 调试</string>
|
<string name="enable_web_debugging">启用 WebView 调试</string>
|
||||||
<string name="enable_web_debugging_summary">可用于调试 WebUI 。请仅在需要时启用。</string>
|
<string name="enable_web_debugging_summary">可用于调试 WebUI 。请仅在需要时启用。</string>
|
||||||
<string name="direct_install">直接安装(推荐)</string>
|
<string name="direct_install">直接安装(推荐)</string>
|
||||||
|
|||||||
@@ -115,6 +115,7 @@
|
|||||||
<string name="grant_root_failed">Failed to grant root!</string>
|
<string name="grant_root_failed">Failed to grant root!</string>
|
||||||
<string name="action">Action</string>
|
<string name="action">Action</string>
|
||||||
<string name="open">Open</string>
|
<string name="open">Open</string>
|
||||||
|
<string name="close">Close</string>
|
||||||
<string name="enable_web_debugging">Enable WebView debugging</string>
|
<string name="enable_web_debugging">Enable WebView debugging</string>
|
||||||
<string name="enable_web_debugging_summary">Can be used to debug WebUI. Please enable only when needed.</string>
|
<string name="enable_web_debugging_summary">Can be used to debug WebUI. Please enable only when needed.</string>
|
||||||
<string name="direct_install">Direct install (Recommended)</string>
|
<string name="direct_install">Direct install (Recommended)</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user