manager: Move certain settings to the Advanced Settings section.

This commit is contained in:
ShirkNeko
2025-11-17 12:37:53 +08:00
parent f48d2e6cac
commit ad2a23f55e
5 changed files with 199 additions and 144 deletions

View File

@@ -330,25 +330,6 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
)
// 强制签名验证开关
var forceSignatureVerification by rememberSaveable {
mutableStateOf(prefs.getBoolean("force_signature_verification", false))
}
SwitchItem(
icon = Icons.Filled.Security,
title = stringResource(R.string.module_signature_verification),
summary = stringResource(R.string.module_signature_verification_summary),
checked = forceSignatureVerification,
onCheckedChange = { enabled ->
prefs.edit { putBoolean("force_signature_verification", enabled) }
forceSignatureVerification = enabled
}
)
// UID 扫描开关
if (Natives.version >= Natives.MINIMAL_SUPPORTED_UID_SCANNER && Natives.version >= Natives.MINIMAL_NEW_IOCTL_KERNEL) {
UidScannerSection(prefs, snackBarHost, scope, context)
}
}
)
}
@@ -1004,124 +985,3 @@ private fun TopBar(
scrollBehavior = scrollBehavior
)
}
@Composable
private fun UidScannerSection(
prefs: SharedPreferences,
snackBarHost: SnackbarHostState,
scope: CoroutineScope,
context: Context
) {
if (Natives.version < Natives.MINIMAL_SUPPORTED_UID_SCANNER) return
val realAuto = Natives.isUidScannerEnabled()
val realMulti = getUidMultiUserScan()
var autoOn by remember { mutableStateOf(realAuto) }
var multiOn by remember { mutableStateOf(realMulti) }
LaunchedEffect(Unit) {
autoOn = realAuto
multiOn = realMulti
prefs.edit {
putBoolean("uid_auto_scan", autoOn)
putBoolean("uid_multi_user_scan", multiOn)
}
}
SwitchItem(
icon = Icons.Filled.Scanner,
title = stringResource(R.string.uid_auto_scan_title),
summary = stringResource(R.string.uid_auto_scan_summary),
checked = autoOn,
onCheckedChange = { target ->
autoOn = target
if (!target) multiOn = false
scope.launch(Dispatchers.IO) {
setUidAutoScan(target)
val actual = Natives.isUidScannerEnabled() || readUidScannerFile()
withContext(Dispatchers.Main) {
autoOn = actual
if (!actual) multiOn = false
prefs.edit {
putBoolean("uid_auto_scan", actual)
putBoolean("uid_multi_user_scan", multiOn)
}
if (actual != target) {
snackBarHost.showSnackbar(
context.getString(R.string.uid_scanner_setting_failed)
)
}
}
}
}
)
AnimatedVisibility(
visible = autoOn,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
SwitchItem(
icon = Icons.Filled.Groups,
title = stringResource(R.string.uid_multi_user_scan_title),
summary = stringResource(R.string.uid_multi_user_scan_summary),
checked = multiOn,
onCheckedChange = { target ->
scope.launch(Dispatchers.IO) {
val ok = setUidMultiUserScan(target)
withContext(Dispatchers.Main) {
if (ok) {
multiOn = target
prefs.edit { putBoolean("uid_multi_user_scan", target) }
} else {
snackBarHost.showSnackbar(
context.getString(R.string.uid_scanner_setting_failed)
)
}
}
}
}
)
}
AnimatedVisibility(
visible = autoOn,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
val confirmDialog = rememberConfirmDialog()
SettingItem(
icon = Icons.Filled.CleaningServices,
title = stringResource(R.string.clean_runtime_environment),
summary = stringResource(R.string.clean_runtime_environment_summary),
onClick = {
scope.launch {
if (confirmDialog.awaitConfirm(
title = context.getString(R.string.clean_runtime_environment),
content = context.getString(R.string.clean_runtime_environment_confirm)
) == ConfirmResult.Confirmed
) {
if (cleanRuntimeEnvironment()) {
autoOn = false
multiOn = false
prefs.edit {
putBoolean("uid_auto_scan", false)
putBoolean("uid_multi_user_scan", false)
}
Natives.setUidScannerEnabled(false)
snackBarHost.showSnackbar(
context.getString(R.string.clean_runtime_environment_success)
)
} else {
snackBarHost.showSnackbar(
context.getString(R.string.clean_runtime_environment_failed)
)
}
}
}
}
)
}
}

View File

@@ -17,6 +17,9 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.getValue
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -25,6 +28,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.core.content.edit
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -33,8 +37,8 @@ import com.sukisu.ultra.Natives
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.theme.component.ImageEditorDialog
import com.sukisu.ultra.ui.component.KsuIsValid
import com.sukisu.ultra.ui.screen.SwitchItem
import com.sukisu.ultra.ui.theme.*
import com.sukisu.ultra.ui.util.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -45,6 +49,7 @@ import zako.zako.zako.zakoui.screen.moreSettings.component.SettingItem
import zako.zako.zako.zakoui.screen.moreSettings.component.SettingsCard
import zako.zako.zako.zakoui.screen.moreSettings.component.SettingsDivider
import zako.zako.zako.zakoui.screen.moreSettings.component.SwitchSettingItem
import zako.zako.zako.zakoui.screen.moreSettings.component.UidScannerSection
import zako.zako.zako.zakoui.screen.moreSettings.state.MoreSettingsState
import kotlin.math.roundToInt
@@ -341,6 +346,11 @@ private fun AdvancedSettings(
state: MoreSettingsState,
handlers: MoreSettingsHandlers
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val snackBarHost = remember { SnackbarHostState() }
val prefs = remember { context.getSharedPreferences("settings", Context.MODE_PRIVATE) }
SettingsCard(title = stringResource(R.string.advanced_settings)) {
// SELinux 开关
SwitchSettingItem(
@@ -353,6 +363,27 @@ private fun AdvancedSettings(
onChange = handlers::handleSelinuxChange
)
var forceSignatureVerification by rememberSaveable {
mutableStateOf(prefs.getBoolean("force_signature_verification", false))
}
// 强制签名验证开关
SwitchItem(
icon = Icons.Filled.Security,
title = stringResource(R.string.module_signature_verification),
summary = stringResource(R.string.module_signature_verification_summary),
checked = forceSignatureVerification,
onCheckedChange = { enabled ->
prefs.edit { putBoolean("force_signature_verification", enabled) }
forceSignatureVerification = enabled
}
)
// UID 扫描开关
if (Natives.version >= Natives.MINIMAL_SUPPORTED_UID_SCANNER && Natives.version >= Natives.MINIMAL_NEW_IOCTL_KERNEL) {
UidScannerSection(prefs, snackBarHost, scope, context)
}
// 动态管理器设置
if (Natives.version >= Natives.MINIMAL_SUPPORTED_DYNAMIC_MANAGER && Natives.version >= Natives.MINIMAL_NEW_IOCTL_KERNEL) {
SettingItem(

View File

@@ -6,15 +6,38 @@ import android.content.SharedPreferences
import android.content.res.Configuration
import android.net.Uri
import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CleaningServices
import androidx.compose.material.icons.filled.Groups
import androidx.compose.material.icons.filled.Scanner
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.content.edit
import com.sukisu.ultra.Natives
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.component.ConfirmResult
import com.sukisu.ultra.ui.component.rememberConfirmDialog
import com.sukisu.ultra.ui.screen.SettingItem
import com.sukisu.ultra.ui.screen.SwitchItem
import com.sukisu.ultra.ui.theme.*
import com.sukisu.ultra.ui.util.*
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import zako.zako.zako.zakoui.screen.moreSettings.state.MoreSettingsState
import zako.zako.zako.zakoui.screen.moreSettings.util.toggleLauncherIcon

View File

@@ -1,13 +1,23 @@
package zako.zako.zako.zakoui.screen.moreSettings.component
import android.content.Context
import android.content.SharedPreferences
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.CleaningServices
import androidx.compose.material.icons.filled.Groups
import androidx.compose.material.icons.filled.Scanner
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
@@ -20,9 +30,22 @@ import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.sukisu.ultra.Natives
import zako.zako.zako.zakoui.screen.moreSettings.util.LocaleHelper
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.component.ConfirmResult
import com.sukisu.ultra.ui.component.rememberConfirmDialog
import com.sukisu.ultra.ui.screen.SwitchItem
import com.sukisu.ultra.ui.theme.*
import com.sukisu.ultra.ui.util.cleanRuntimeEnvironment
import com.sukisu.ultra.ui.util.getUidMultiUserScan
import com.sukisu.ultra.ui.util.readUidScannerFile
import com.sukisu.ultra.ui.util.setUidAutoScan
import com.sukisu.ultra.ui.util.setUidMultiUserScan
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import zako.zako.zako.zakoui.screen.moreSettings.MoreSettingsHandlers
import zako.zako.zako.zakoui.screen.moreSettings.state.MoreSettingsState
@@ -473,4 +496,125 @@ fun DynamicManagerDialog(
}
}
)
}
@Composable
fun UidScannerSection(
prefs: SharedPreferences,
snackBarHost: SnackbarHostState,
scope: CoroutineScope,
context: Context
) {
if (Natives.version < Natives.MINIMAL_SUPPORTED_UID_SCANNER) return
val realAuto = Natives.isUidScannerEnabled()
val realMulti = getUidMultiUserScan()
var autoOn by remember { mutableStateOf(realAuto) }
var multiOn by remember { mutableStateOf(realMulti) }
LaunchedEffect(Unit) {
autoOn = realAuto
multiOn = realMulti
prefs.edit {
putBoolean("uid_auto_scan", autoOn)
putBoolean("uid_multi_user_scan", multiOn)
}
}
SwitchItem(
icon = Icons.Filled.Scanner,
title = stringResource(R.string.uid_auto_scan_title),
summary = stringResource(R.string.uid_auto_scan_summary),
checked = autoOn,
onCheckedChange = { target ->
autoOn = target
if (!target) multiOn = false
scope.launch(Dispatchers.IO) {
setUidAutoScan(target)
val actual = Natives.isUidScannerEnabled() || readUidScannerFile()
withContext(Dispatchers.Main) {
autoOn = actual
if (!actual) multiOn = false
prefs.edit {
putBoolean("uid_auto_scan", actual)
putBoolean("uid_multi_user_scan", multiOn)
}
if (actual != target) {
snackBarHost.showSnackbar(
context.getString(R.string.uid_scanner_setting_failed)
)
}
}
}
}
)
AnimatedVisibility(
visible = autoOn,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
SwitchItem(
icon = Icons.Filled.Groups,
title = stringResource(R.string.uid_multi_user_scan_title),
summary = stringResource(R.string.uid_multi_user_scan_summary),
checked = multiOn,
onCheckedChange = { target ->
scope.launch(Dispatchers.IO) {
val ok = setUidMultiUserScan(target)
withContext(Dispatchers.Main) {
if (ok) {
multiOn = target
prefs.edit { putBoolean("uid_multi_user_scan", target) }
} else {
snackBarHost.showSnackbar(
context.getString(R.string.uid_scanner_setting_failed)
)
}
}
}
}
)
}
AnimatedVisibility(
visible = autoOn,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
val confirmDialog = rememberConfirmDialog()
com.sukisu.ultra.ui.screen.SettingItem(
icon = Icons.Filled.CleaningServices,
title = stringResource(R.string.clean_runtime_environment),
summary = stringResource(R.string.clean_runtime_environment_summary),
onClick = {
scope.launch {
if (confirmDialog.awaitConfirm(
title = context.getString(R.string.clean_runtime_environment),
content = context.getString(R.string.clean_runtime_environment_confirm)
) == ConfirmResult.Confirmed
) {
if (cleanRuntimeEnvironment()) {
autoOn = false
multiOn = false
prefs.edit {
putBoolean("uid_auto_scan", false)
putBoolean("uid_multi_user_scan", false)
}
Natives.setUidScannerEnabled(false)
snackBarHost.showSnackbar(
context.getString(R.string.clean_runtime_environment_success)
)
} else {
snackBarHost.showSnackbar(
context.getString(R.string.clean_runtime_environment_failed)
)
}
}
}
}
)
}
}

View File

@@ -70,9 +70,6 @@ class MoreSettingsState(
// SELinux状态
var selinuxEnabled by mutableStateOf(false)
// SuSFS 状态
var isSusFSEnabled by mutableStateOf(true)
// 卡片配置状态
var cardAlpha by mutableFloatStateOf(CardConfig.cardAlpha)
var cardDim by mutableFloatStateOf(CardConfig.cardDim)