You've already forked KernelSU-Next
mirror of
https://github.com/KernelSU-Next/KernelSU-Next.git
synced 2025-08-27 23:46:34 +00:00
manager: add separate developer menu
This commit is contained in:
@@ -0,0 +1,185 @@
|
|||||||
|
package com.rifsxd.ksunext.ui.screen
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
|
import androidx.compose.foundation.layout.only
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.*
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.dergoogler.mmrl.platform.Platform
|
||||||
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
|
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||||
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
|
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import com.rifsxd.ksunext.Natives
|
||||||
|
import com.rifsxd.ksunext.ksuApp
|
||||||
|
import com.rifsxd.ksunext.R
|
||||||
|
import com.rifsxd.ksunext.ui.component.SwitchItem
|
||||||
|
import com.rifsxd.ksunext.ui.util.LocalSnackbarHost
|
||||||
|
import com.rifsxd.ksunext.ui.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author rifsxd
|
||||||
|
* @date 2025/6/15.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Destination<RootGraph>
|
||||||
|
@Composable
|
||||||
|
fun DeveloperScreen(navigator: DestinationsNavigator) {
|
||||||
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
|
val snackBarHost = LocalSnackbarHost.current
|
||||||
|
|
||||||
|
val isManager = Natives.becomeManager(ksuApp.packageName)
|
||||||
|
val ksuVersion = if (isManager) Natives.version else null
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopBar(
|
||||||
|
onBack = { navigator.popBackStack() },
|
||||||
|
scrollBehavior = scrollBehavior
|
||||||
|
)
|
||||||
|
},
|
||||||
|
snackbarHost = { SnackbarHost(snackBarHost) },
|
||||||
|
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
|
||||||
|
) { paddingValues ->
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(paddingValues)
|
||||||
|
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
// --- Developer Options Switch ---
|
||||||
|
var developerOptionsEnabled by rememberSaveable {
|
||||||
|
mutableStateOf(
|
||||||
|
prefs.getBoolean("enable_developer_options", false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (ksuVersion != null) {
|
||||||
|
SwitchItem(
|
||||||
|
icon = Icons.Filled.DeveloperMode,
|
||||||
|
title = stringResource(id = R.string.enable_developer_options),
|
||||||
|
summary = stringResource(id = R.string.enable_developer_options_summary),
|
||||||
|
checked = developerOptionsEnabled
|
||||||
|
) {
|
||||||
|
prefs.edit().putBoolean("enable_developer_options", it).apply()
|
||||||
|
developerOptionsEnabled = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var useWebUIX by rememberSaveable {
|
||||||
|
mutableStateOf(
|
||||||
|
prefs.getBoolean("use_webuix", true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (ksuVersion != null) {
|
||||||
|
SwitchItem(
|
||||||
|
beta = false,
|
||||||
|
enabled = Platform.isAlive && developerOptionsEnabled,
|
||||||
|
icon = Icons.Filled.WebAsset,
|
||||||
|
title = stringResource(id = R.string.use_webuix),
|
||||||
|
summary = stringResource(id = R.string.use_webuix_summary),
|
||||||
|
checked = useWebUIX
|
||||||
|
) {
|
||||||
|
prefs.edit().putBoolean("use_webuix", it).apply()
|
||||||
|
useWebUIX = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var enableWebDebugging by rememberSaveable {
|
||||||
|
mutableStateOf(
|
||||||
|
prefs.getBoolean("enable_web_debugging", false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (ksuVersion != null) {
|
||||||
|
SwitchItem(
|
||||||
|
enabled = developerOptionsEnabled,
|
||||||
|
icon = Icons.Filled.Web,
|
||||||
|
title = stringResource(id = R.string.enable_web_debugging),
|
||||||
|
summary = stringResource(id = R.string.enable_web_debugging_summary),
|
||||||
|
checked = enableWebDebugging
|
||||||
|
) {
|
||||||
|
prefs.edit().putBoolean("enable_web_debugging", it).apply()
|
||||||
|
enableWebDebugging = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var useWebUIXEruda by rememberSaveable {
|
||||||
|
mutableStateOf(
|
||||||
|
prefs.getBoolean("use_webuix_eruda", false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (ksuVersion != null) {
|
||||||
|
SwitchItem(
|
||||||
|
beta = false,
|
||||||
|
enabled = Platform.isAlive && useWebUIX && enableWebDebugging,
|
||||||
|
icon = Icons.Filled.FormatListNumbered,
|
||||||
|
title = stringResource(id = R.string.use_webuix_eruda),
|
||||||
|
summary = stringResource(id = R.string.use_webuix_eruda_summary),
|
||||||
|
checked = useWebUIXEruda
|
||||||
|
) {
|
||||||
|
prefs.edit().putBoolean("use_webuix_eruda", it).apply()
|
||||||
|
useWebUIXEruda = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun TopBar(
|
||||||
|
onBack: () -> Unit = {},
|
||||||
|
scrollBehavior: TopAppBarScrollBehavior? = null
|
||||||
|
) {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text(stringResource(R.string.developer)) }, navigationIcon = {
|
||||||
|
IconButton(
|
||||||
|
onClick = onBack
|
||||||
|
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
|
||||||
|
},
|
||||||
|
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
|
||||||
|
scrollBehavior = scrollBehavior
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun DeveloperPreview() {
|
||||||
|
DeveloperScreen(EmptyDestinationsNavigator)
|
||||||
|
}
|
||||||
@@ -67,6 +67,7 @@ import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplat
|
|||||||
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
|
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
|
||||||
import com.ramcosta.composedestinations.generated.destinations.BackupRestoreScreenDestination
|
import com.ramcosta.composedestinations.generated.destinations.BackupRestoreScreenDestination
|
||||||
import com.ramcosta.composedestinations.generated.destinations.CustomizationScreenDestination
|
import com.ramcosta.composedestinations.generated.destinations.CustomizationScreenDestination
|
||||||
|
import com.ramcosta.composedestinations.generated.destinations.DeveloperScreenDestination
|
||||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -293,78 +294,6 @@ fun SettingScreen(navigator: DestinationsNavigator) {
|
|||||||
checkUpdate = it
|
checkUpdate = it
|
||||||
}
|
}
|
||||||
|
|
||||||
var enableWebDebugging by rememberSaveable {
|
|
||||||
mutableStateOf(
|
|
||||||
prefs.getBoolean("enable_web_debugging", false)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ksuVersion != null) {
|
|
||||||
SwitchItem(
|
|
||||||
icon = Icons.Filled.Web,
|
|
||||||
title = stringResource(id = R.string.enable_web_debugging),
|
|
||||||
summary = stringResource(id = R.string.enable_web_debugging_summary),
|
|
||||||
checked = enableWebDebugging
|
|
||||||
) {
|
|
||||||
prefs.edit().putBoolean("enable_web_debugging", it).apply()
|
|
||||||
enableWebDebugging = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var developerOptionsEnabled by rememberSaveable {
|
|
||||||
mutableStateOf(
|
|
||||||
prefs.getBoolean("enable_developer_options", false)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (ksuVersion != null) {
|
|
||||||
SwitchItem(
|
|
||||||
icon = Icons.Filled.DeveloperMode,
|
|
||||||
title = stringResource(id = R.string.enable_developer_options),
|
|
||||||
summary = stringResource(id = R.string.enable_developer_options_summary),
|
|
||||||
checked = developerOptionsEnabled
|
|
||||||
) {
|
|
||||||
prefs.edit().putBoolean("enable_developer_options", it).apply()
|
|
||||||
developerOptionsEnabled = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var useWebUIX by rememberSaveable {
|
|
||||||
mutableStateOf(
|
|
||||||
prefs.getBoolean("use_webuix", true)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (ksuVersion != null) {
|
|
||||||
SwitchItem(
|
|
||||||
beta = false,
|
|
||||||
enabled = Platform.isAlive,
|
|
||||||
icon = Icons.Filled.WebAsset,
|
|
||||||
title = stringResource(id = R.string.use_webuix),
|
|
||||||
summary = stringResource(id = R.string.use_webuix_summary),
|
|
||||||
checked = useWebUIX
|
|
||||||
) {
|
|
||||||
prefs.edit().putBoolean("use_webuix", it).apply()
|
|
||||||
useWebUIX = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var useWebUIXEruda by rememberSaveable {
|
|
||||||
mutableStateOf(
|
|
||||||
prefs.getBoolean("use_webuix_eruda", false)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (ksuVersion != null) {
|
|
||||||
SwitchItem(
|
|
||||||
beta = false,
|
|
||||||
enabled = Platform.isAlive && useWebUIX && enableWebDebugging,
|
|
||||||
icon = Icons.Filled.FormatListNumbered,
|
|
||||||
title = stringResource(id = R.string.use_webuix_eruda),
|
|
||||||
summary = stringResource(id = R.string.use_webuix_eruda_summary),
|
|
||||||
checked = useWebUIXEruda
|
|
||||||
) {
|
|
||||||
prefs.edit().putBoolean("use_webuix_eruda", it).apply()
|
|
||||||
useWebUIXEruda = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOverlayAvailable && useOverlayFs) {
|
if (isOverlayAvailable && useOverlayFs) {
|
||||||
val shrink = stringResource(id = R.string.shrink_sparse_image)
|
val shrink = stringResource(id = R.string.shrink_sparse_image)
|
||||||
val shrinkMessage = stringResource(id = R.string.shrink_sparse_image_message)
|
val shrinkMessage = stringResource(id = R.string.shrink_sparse_image_message)
|
||||||
@@ -419,6 +348,20 @@ fun SettingScreen(navigator: DestinationsNavigator) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val developer = stringResource(id = R.string.developer)
|
||||||
|
ListItem(
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
Icons.Filled.DeveloperBoard,
|
||||||
|
developer
|
||||||
|
)
|
||||||
|
},
|
||||||
|
headlineContent = { Text(developer) },
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
navigator.navigate(DeveloperScreenDestination)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
val lkmMode = Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode
|
val lkmMode = Natives.version >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && Natives.isLkmMode
|
||||||
if (lkmMode) {
|
if (lkmMode) {
|
||||||
UninstallItem(navigator) {
|
UninstallItem(navigator) {
|
||||||
|
|||||||
@@ -220,4 +220,5 @@
|
|||||||
<string name="use_webuix_eruda">Inject Eruda into WebUI X</string>
|
<string name="use_webuix_eruda">Inject Eruda into WebUI X</string>
|
||||||
<string name="use_webuix_eruda_summary">Inject a debug console into WebUI X to make debugging easier. Requires web debugging to be on.</string>
|
<string name="use_webuix_eruda_summary">Inject a debug console into WebUI X to make debugging easier. Requires web debugging to be on.</string>
|
||||||
<string name="customization">Customization</string>
|
<string name="customization">Customization</string>
|
||||||
|
<string name="developer">Developer</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user