diff --git a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Developer.kt b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Developer.kt new file mode 100644 index 00000000..9c1286cf --- /dev/null +++ b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Developer.kt @@ -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 +@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) +} diff --git a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Settings.kt b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Settings.kt index 44d63d53..6f40d505 100644 --- a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Settings.kt +++ b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Settings.kt @@ -67,6 +67,7 @@ import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplat import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination import com.ramcosta.composedestinations.generated.destinations.BackupRestoreScreenDestination 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.EmptyDestinationsNavigator import kotlinx.coroutines.Dispatchers @@ -293,78 +294,6 @@ fun SettingScreen(navigator: DestinationsNavigator) { 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) { val shrink = stringResource(id = R.string.shrink_sparse_image) 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 if (lkmMode) { UninstallItem(navigator) { diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index fa4aced5..8aeedef0 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -220,4 +220,5 @@ Inject Eruda into WebUI X Inject a debug console into WebUI X to make debugging easier. Requires web debugging to be on. Customization + Developer