From 3551441e42873f49d29869dd173a6ca5513b44ab Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Sun, 29 Jun 2025 20:36:45 +0800 Subject: [PATCH] manager: Provides re-editable functionality for all SuSFS path configurations --- .../ultra/ui/component/SuSFSConfigDialogs.kt | 73 +++++++++-- .../ultra/ui/component/SuSFSConfigTabs.kt | 14 ++- .../com/sukisu/ultra/ui/screen/SuSFSConfig.kt | 119 +++++++++++++++--- .../extensions/SuSFSConfigExtensions.kt | 100 +++++++++++---- .../com/sukisu/ultra/ui/util/SuSFSManager.kt | 70 +++++++++++ .../src/main/res/values-zh-rCN/strings.xml | 12 ++ manager/app/src/main/res/values/strings.xml | 12 ++ 7 files changed, 348 insertions(+), 52 deletions(-) diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigDialogs.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigDialogs.kt index 8b3c4113..ffde1db2 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigDialogs.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigDialogs.kt @@ -20,6 +20,7 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -42,10 +43,18 @@ fun AddPathDialog( isLoading: Boolean, titleRes: Int, labelRes: Int, - placeholderRes: Int + placeholderRes: Int, + initialValue: String = "" ) { var newPath by remember { mutableStateOf("") } + // 当对话框显示时,设置初始值 + LaunchedEffect(showDialog, initialValue) { + if (showDialog) { + newPath = initialValue + } + } + if (showDialog) { AlertDialog( onDismissRequest = onDismiss, @@ -77,7 +86,7 @@ fun AddPathDialog( enabled = newPath.isNotBlank() && !isLoading, shape = RoundedCornerShape(8.dp) ) { - Text(stringResource(R.string.add)) + Text(stringResource(if (initialValue.isNotEmpty()) R.string.susfs_save else R.string.add)) } }, dismissButton = { @@ -105,18 +114,28 @@ fun AddTryUmountDialog( showDialog: Boolean, onDismiss: () -> Unit, onConfirm: (String, Int) -> Unit, - isLoading: Boolean + isLoading: Boolean, + initialPath: String = "", + initialMode: Int = 0 ) { var newUmountPath by remember { mutableStateOf("") } var newUmountMode by remember { mutableIntStateOf(0) } var umountModeExpanded by remember { mutableStateOf(false) } + // 当对话框显示时,设置初始值 + LaunchedEffect(showDialog, initialPath, initialMode) { + if (showDialog) { + newUmountPath = initialPath + newUmountMode = initialMode + } + } + if (showDialog) { AlertDialog( onDismissRequest = onDismiss, title = { Text( - stringResource(R.string.susfs_add_try_umount), + stringResource(if (initialPath.isNotEmpty()) R.string.susfs_edit_try_umount else R.string.susfs_add_try_umount), style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold ) @@ -186,7 +205,7 @@ fun AddTryUmountDialog( enabled = newUmountPath.isNotBlank() && !isLoading, shape = RoundedCornerShape(8.dp) ) { - Text(stringResource(R.string.add)) + Text(stringResource(if (initialPath.isNotEmpty()) R.string.susfs_save else R.string.add)) } }, dismissButton = { @@ -214,7 +233,8 @@ fun AddKstatStaticallyDialog( showDialog: Boolean, onDismiss: () -> Unit, onConfirm: (String, String, String, String, String, String, String, String, String, String, String, String, String) -> Unit, - isLoading: Boolean + isLoading: Boolean, + initialConfig: String = "" ) { var newKstatPath by remember { mutableStateOf("") } var newKstatIno by remember { mutableStateOf("") } @@ -230,12 +250,49 @@ fun AddKstatStaticallyDialog( var newKstatBlocks by remember { mutableStateOf("") } var newKstatBlksize by remember { mutableStateOf("") } + // 当对话框显示时,解析初始配置 + LaunchedEffect(showDialog, initialConfig) { + if (showDialog && initialConfig.isNotEmpty()) { + val parts = initialConfig.split("|") + if (parts.size >= 13) { + newKstatPath = parts[0] + newKstatIno = if (parts[1] == "default") "" else parts[1] + newKstatDev = if (parts[2] == "default") "" else parts[2] + newKstatNlink = if (parts[3] == "default") "" else parts[3] + newKstatSize = if (parts[4] == "default") "" else parts[4] + newKstatAtime = if (parts[5] == "default") "" else parts[5] + newKstatAtimeNsec = if (parts[6] == "default") "" else parts[6] + newKstatMtime = if (parts[7] == "default") "" else parts[7] + newKstatMtimeNsec = if (parts[8] == "default") "" else parts[8] + newKstatCtime = if (parts[9] == "default") "" else parts[9] + newKstatCtimeNsec = if (parts[10] == "default") "" else parts[10] + newKstatBlocks = if (parts[11] == "default") "" else parts[11] + newKstatBlksize = if (parts[12] == "default") "" else parts[12] + } + } else if (showDialog && initialConfig.isEmpty()) { + // 清空所有字段 + newKstatPath = "" + newKstatIno = "" + newKstatDev = "" + newKstatNlink = "" + newKstatSize = "" + newKstatAtime = "" + newKstatAtimeNsec = "" + newKstatMtime = "" + newKstatMtimeNsec = "" + newKstatCtime = "" + newKstatCtimeNsec = "" + newKstatBlocks = "" + newKstatBlksize = "" + } + } + if (showDialog) { AlertDialog( onDismissRequest = onDismiss, title = { Text( - stringResource(R.string.add_kstat_statically_title), + stringResource(if (initialConfig.isNotEmpty()) R.string.edit_kstat_statically_title else R.string.add_kstat_statically_title), style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold ) @@ -431,7 +488,7 @@ fun AddKstatStaticallyDialog( enabled = newKstatPath.isNotBlank() && !isLoading, shape = RoundedCornerShape(8.dp) ) { - Text(stringResource(R.string.add)) + Text(stringResource(if (initialConfig.isNotEmpty()) R.string.susfs_save else R.string.add)) } }, dismissButton = { diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigTabs.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigTabs.kt index ed21a8d8..67f26bd4 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigTabs.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigTabs.kt @@ -51,7 +51,8 @@ fun SusPathsContent( susPaths: Set, isLoading: Boolean, onAddPath: () -> Unit, - onRemovePath: (String) -> Unit + onRemovePath: (String) -> Unit, + onEditPath: ((String) -> Unit)? = null ) { Box(modifier = Modifier.fillMaxSize()) { LazyColumn( @@ -70,6 +71,7 @@ fun SusPathsContent( path = path, icon = Icons.Default.Folder, onDelete = { onRemovePath(path) }, + onEdit = if (onEditPath != null) { { onEditPath(path) } } else null, isLoading = isLoading ) } @@ -116,6 +118,7 @@ fun SusMountsContent( isLoading: Boolean, onAddMount: () -> Unit, onRemoveMount: (String) -> Unit, + onEditMount: ((String) -> Unit)? = null, onToggleHideSusMountsForAllProcs: (Boolean) -> Unit ) { Box(modifier = Modifier.fillMaxSize()) { @@ -145,6 +148,7 @@ fun SusMountsContent( path = mount, icon = Icons.Default.Storage, onDelete = { onRemoveMount(mount) }, + onEdit = if (onEditMount != null) { { onEditMount(mount) } } else null, isLoading = isLoading ) } @@ -189,7 +193,8 @@ fun TryUmountContent( isLoading: Boolean, onAddUmount: () -> Unit, onRunUmount: () -> Unit, - onRemoveUmount: (String) -> Unit + onRemoveUmount: (String) -> Unit, + onEditUmount: ((String) -> Unit)? = null ) { Box(modifier = Modifier.fillMaxSize()) { LazyColumn( @@ -218,6 +223,7 @@ fun TryUmountContent( icon = Icons.Default.Storage, additionalInfo = stringResource(R.string.susfs_umount_mode_display, modeText, mode), onDelete = { onRemoveUmount(umountEntry) }, + onEdit = if (onEditUmount != null) { { onEditUmount(umountEntry) } } else null, isLoading = isLoading ) } @@ -282,7 +288,9 @@ fun KstatConfigContent( onAddKstatStatically: () -> Unit, onAddKstat: () -> Unit, onRemoveKstatConfig: (String) -> Unit, + onEditKstatConfig: ((String) -> Unit)? = null, onRemoveAddKstat: (String) -> Unit, + onEditAddKstat: ((String) -> Unit)? = null, onUpdateKstat: (String) -> Unit, onUpdateKstatFullClone: (String) -> Unit ) { @@ -347,6 +355,7 @@ fun KstatConfigContent( KstatConfigItemCard( config = config, onDelete = { onRemoveKstatConfig(config) }, + onEdit = if (onEditKstatConfig != null) { { onEditKstatConfig(config) } } else null, isLoading = isLoading ) } @@ -365,6 +374,7 @@ fun KstatConfigContent( AddKstatPathItemCard( path = path, onDelete = { onRemoveAddKstat(path) }, + onEdit = if (onEditAddKstat != null) { { onEditAddKstat(path) } } else null, onUpdate = { onUpdateKstat(path) }, onUpdateFullClone = { onUpdateKstatFullClone(path) }, isLoading = isLoading diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt index 021e301d..831e26c8 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt @@ -164,6 +164,13 @@ fun SuSFSConfigScreen( var showAddKstatStaticallyDialog by remember { mutableStateOf(false) } var showAddKstatDialog by remember { mutableStateOf(false) } + // 编辑状态 + var editingPath by remember { mutableStateOf(null) } + var editingMount by remember { mutableStateOf(null) } + var editingUmount by remember { mutableStateOf(null) } + var editingKstatConfig by remember { mutableStateOf(null) } + var editingKstatPath by remember { mutableStateOf(null) } + // 重置确认对话框状态 var showResetPathsDialog by remember { mutableStateOf(false) } var showResetMountsDialog by remember { mutableStateOf(false) } @@ -499,94 +506,148 @@ fun SuSFSConfigScreen( // 各种对话框 AddPathDialog( showDialog = showAddPathDialog, - onDismiss = { showAddPathDialog = false }, + onDismiss = { + showAddPathDialog = false + editingPath = null + }, onConfirm = { path -> coroutineScope.launch { isLoading = true - if (SuSFSManager.addSusPath(context, path)) { + val success = if (editingPath != null) { + SuSFSManager.editSusPath(context, editingPath!!, path) + } else { + SuSFSManager.addSusPath(context, path) + } + if (success) { susPaths = SuSFSManager.getSusPaths(context) } isLoading = false showAddPathDialog = false + editingPath = null } }, isLoading = isLoading, - titleRes = R.string.susfs_add_sus_path, + titleRes = if (editingPath != null) R.string.susfs_edit_sus_path else R.string.susfs_add_sus_path, labelRes = R.string.susfs_path_label, - placeholderRes = R.string.susfs_path_placeholder + placeholderRes = R.string.susfs_path_placeholder, + initialValue = editingPath ?: "" ) AddPathDialog( showDialog = showAddMountDialog, - onDismiss = { showAddMountDialog = false }, + onDismiss = { + showAddMountDialog = false + editingMount = null + }, onConfirm = { mount -> coroutineScope.launch { isLoading = true - if (SuSFSManager.addSusMount(context, mount)) { + val success = if (editingMount != null) { + SuSFSManager.editSusMount(context, editingMount!!, mount) + } else { + SuSFSManager.addSusMount(context, mount) + } + if (success) { susMounts = SuSFSManager.getSusMounts(context) } isLoading = false showAddMountDialog = false + editingMount = null } }, isLoading = isLoading, - titleRes = R.string.susfs_add_sus_mount, + titleRes = if (editingMount != null) R.string.susfs_edit_sus_mount else R.string.susfs_add_sus_mount, labelRes = R.string.susfs_mount_path_label, - placeholderRes = R.string.susfs_path_placeholder + placeholderRes = R.string.susfs_path_placeholder, + initialValue = editingMount ?: "" ) AddTryUmountDialog( showDialog = showAddUmountDialog, - onDismiss = { showAddUmountDialog = false }, + onDismiss = { + showAddUmountDialog = false + editingUmount = null + }, onConfirm = { path, mode -> coroutineScope.launch { isLoading = true - if (SuSFSManager.addTryUmount(context, path, mode)) { + val success = if (editingUmount != null) { + SuSFSManager.editTryUmount(context, editingUmount!!, path, mode) + } else { + SuSFSManager.addTryUmount(context, path, mode) + } + if (success) { tryUmounts = SuSFSManager.getTryUmounts(context) } isLoading = false showAddUmountDialog = false + editingUmount = null } }, - isLoading = isLoading + isLoading = isLoading, + initialPath = editingUmount?.split("|")?.get(0) ?: "", + initialMode = editingUmount?.split("|")?.get(1)?.toIntOrNull() ?: 0 ) AddKstatStaticallyDialog( showDialog = showAddKstatStaticallyDialog, - onDismiss = { showAddKstatStaticallyDialog = false }, + onDismiss = { + showAddKstatStaticallyDialog = false + editingKstatConfig = null + }, onConfirm = { path, ino, dev, nlink, size, atime, atimeNsec, mtime, mtimeNsec, ctime, ctimeNsec, blocks, blksize -> coroutineScope.launch { isLoading = true - if (SuSFSManager.addKstatStatically( + val success = if (editingKstatConfig != null) { + SuSFSManager.editKstatConfig( + context, editingKstatConfig!!, path, ino, dev, nlink, size, atime, atimeNsec, + mtime, mtimeNsec, ctime, ctimeNsec, blocks, blksize + ) + } else { + SuSFSManager.addKstatStatically( context, path, ino, dev, nlink, size, atime, atimeNsec, mtime, mtimeNsec, ctime, ctimeNsec, blocks, blksize - )) { + ) + } + if (success) { kstatConfigs = SuSFSManager.getKstatConfigs(context) } isLoading = false showAddKstatStaticallyDialog = false + editingKstatConfig = null } }, - isLoading = isLoading + isLoading = isLoading, + initialConfig = editingKstatConfig ?: "" ) AddPathDialog( showDialog = showAddKstatDialog, - onDismiss = { showAddKstatDialog = false }, + onDismiss = { + showAddKstatDialog = false + editingKstatPath = null + }, onConfirm = { path -> coroutineScope.launch { isLoading = true - if (SuSFSManager.addKstat(context, path)) { + val success = if (editingKstatPath != null) { + SuSFSManager.editAddKstat(context, editingKstatPath!!, path) + } else { + SuSFSManager.addKstat(context, path) + } + if (success) { addKstatPaths = SuSFSManager.getAddKstatPaths(context) } isLoading = false showAddKstatDialog = false + editingKstatPath = null } }, isLoading = isLoading, - titleRes = R.string.add_kstat_path_title, + titleRes = if (editingKstatPath != null) R.string.edit_kstat_path_title else R.string.add_kstat_path_title, labelRes = R.string.file_or_directory_path_label, - placeholderRes = R.string.susfs_path_placeholder + placeholderRes = R.string.susfs_path_placeholder, + initialValue = editingKstatPath ?: "" ) // 确认对话框 @@ -1066,6 +1127,10 @@ fun SuSFSConfigScreen( } isLoading = false } + }, + onEditPath = { path -> + editingPath = path + showAddPathDialog = true } ) } @@ -1087,6 +1152,10 @@ fun SuSFSConfigScreen( isLoading = false } }, + onEditMount = { mount -> + editingMount = mount + showAddMountDialog = true + }, onToggleHideSusMountsForAllProcs = { hideForAll -> coroutineScope.launch { isLoading = true @@ -1113,6 +1182,10 @@ fun SuSFSConfigScreen( } isLoading = false } + }, + onEditUmount = { umountEntry -> + editingUmount = umountEntry + showAddUmountDialog = true } ) } @@ -1132,6 +1205,10 @@ fun SuSFSConfigScreen( isLoading = false } }, + onEditKstatConfig = { config -> + editingKstatConfig = config + showAddKstatStaticallyDialog = true + }, onRemoveAddKstat = { path -> coroutineScope.launch { isLoading = true @@ -1141,6 +1218,10 @@ fun SuSFSConfigScreen( isLoading = false } }, + onEditAddKstat = { path -> + editingKstatPath = path + showAddKstatDialog = true + }, onUpdateKstat = { path -> coroutineScope.launch { isLoading = true diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/extensions/SuSFSConfigExtensions.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/extensions/SuSFSConfigExtensions.kt index dc3ce0f9..f92e22e0 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/extensions/SuSFSConfigExtensions.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/extensions/SuSFSConfigExtensions.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Folder import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.icons.filled.Update @@ -91,6 +92,7 @@ fun PathItemCard( path: String, icon: ImageVector, onDelete: () -> Unit, + onEdit: (() -> Unit)? = null, isLoading: Boolean = false, additionalInfo: String? = null ) { @@ -134,17 +136,35 @@ fun PathItemCard( } } } - IconButton( - onClick = onDelete, - enabled = !isLoading, - modifier = Modifier.size(32.dp) + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp) ) { - Icon( - imageVector = Icons.Default.Delete, - contentDescription = null, - tint = MaterialTheme.colorScheme.error, - modifier = Modifier.size(16.dp) - ) + if (onEdit != null) { + IconButton( + onClick = onEdit, + enabled = !isLoading, + modifier = Modifier.size(32.dp) + ) { + Icon( + imageVector = Icons.Default.Edit, + contentDescription = stringResource(R.string.edit), + tint = MaterialTheme.colorScheme.secondary, + modifier = Modifier.size(16.dp) + ) + } + } + IconButton( + onClick = onDelete, + enabled = !isLoading, + modifier = Modifier.size(32.dp) + ) { + Icon( + imageVector = Icons.Default.Delete, + contentDescription = stringResource(R.string.delete), + tint = MaterialTheme.colorScheme.error, + modifier = Modifier.size(16.dp) + ) + } } } } @@ -157,6 +177,7 @@ fun PathItemCard( fun KstatConfigItemCard( config: String, onDelete: () -> Unit, + onEdit: (() -> Unit)? = null, isLoading: Boolean = false ) { Card( @@ -208,17 +229,35 @@ fun KstatConfigItemCard( } } } - IconButton( - onClick = onDelete, - enabled = !isLoading, - modifier = Modifier.size(32.dp) + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp) ) { - Icon( - imageVector = Icons.Default.Delete, - contentDescription = null, - tint = MaterialTheme.colorScheme.error, - modifier = Modifier.size(16.dp) - ) + if (onEdit != null) { + IconButton( + onClick = onEdit, + enabled = !isLoading, + modifier = Modifier.size(32.dp) + ) { + Icon( + imageVector = Icons.Default.Edit, + contentDescription = stringResource(R.string.edit), + tint = MaterialTheme.colorScheme.secondary, + modifier = Modifier.size(16.dp) + ) + } + } + IconButton( + onClick = onDelete, + enabled = !isLoading, + modifier = Modifier.size(32.dp) + ) { + Icon( + imageVector = Icons.Default.Delete, + contentDescription = stringResource(R.string.delete), + tint = MaterialTheme.colorScheme.error, + modifier = Modifier.size(16.dp) + ) + } } } } @@ -231,6 +270,7 @@ fun KstatConfigItemCard( fun AddKstatPathItemCard( path: String, onDelete: () -> Unit, + onEdit: (() -> Unit)? = null, onUpdate: () -> Unit, onUpdateFullClone: () -> Unit, isLoading: Boolean = false @@ -269,6 +309,20 @@ fun AddKstatPathItemCard( Row( horizontalArrangement = Arrangement.spacedBy(4.dp) ) { + if (onEdit != null) { + IconButton( + onClick = onEdit, + enabled = !isLoading, + modifier = Modifier.size(32.dp) + ) { + Icon( + imageVector = Icons.Default.Edit, + contentDescription = stringResource(R.string.edit), + tint = MaterialTheme.colorScheme.secondary, + modifier = Modifier.size(16.dp) + ) + } + } IconButton( onClick = onUpdate, enabled = !isLoading, @@ -276,7 +330,7 @@ fun AddKstatPathItemCard( ) { Icon( imageVector = Icons.Default.Update, - contentDescription = null, + contentDescription = stringResource(R.string.update), tint = MaterialTheme.colorScheme.secondary, modifier = Modifier.size(16.dp) ) @@ -288,7 +342,7 @@ fun AddKstatPathItemCard( ) { Icon( imageVector = Icons.Default.PlayArrow, - contentDescription = null, + contentDescription = stringResource(R.string.susfs_update_full_clone), tint = MaterialTheme.colorScheme.tertiary, modifier = Modifier.size(16.dp) ) @@ -300,7 +354,7 @@ fun AddKstatPathItemCard( ) { Icon( imageVector = Icons.Default.Delete, - contentDescription = null, + contentDescription = stringResource(R.string.delete), tint = MaterialTheme.colorScheme.error, modifier = Modifier.size(16.dp) ) diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt index 865bd9fd..1d76d8de 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt @@ -800,6 +800,19 @@ object SuSFSManager { return true } + // 编辑SUS路径 + suspend fun editSusPath(context: Context, oldPath: String, newPath: String): Boolean { + val currentPaths = getSusPaths(context).toMutableSet() + if (currentPaths.remove(oldPath)) { + currentPaths.add(newPath) + saveSusPaths(context, currentPaths) + if (isAutoStartEnabled(context)) updateMagiskModule(context) + showToast(context, "SUS path updated: $oldPath -> $newPath") + return true + } + return false + } + // 添加SUS挂载 suspend fun addSusMount(context: Context, mount: String): Boolean { val success = executeSusfsCommand(context, "add_sus_mount '$mount'") @@ -817,6 +830,19 @@ object SuSFSManager { return true } + // 编辑SUS挂载 + suspend fun editSusMount(context: Context, oldMount: String, newMount: String): Boolean { + val currentMounts = getSusMounts(context).toMutableSet() + if (currentMounts.remove(oldMount)) { + currentMounts.add(newMount) + saveSusMounts(context, currentMounts) + if (isAutoStartEnabled(context)) updateMagiskModule(context) + showToast(context, "SUS mount updated: $oldMount -> $newMount") + return true + } + return false + } + // 添加尝试卸载 suspend fun addTryUmount(context: Context, path: String, mode: Int): Boolean { val commandSuccess = executeSusfsCommand(context, "add_try_umount '$path' $mode") @@ -839,6 +865,19 @@ object SuSFSManager { return true } + // 编辑尝试卸载 + suspend fun editTryUmount(context: Context, oldEntry: String, newPath: String, newMode: Int): Boolean { + val currentUmounts = getTryUmounts(context).toMutableSet() + if (currentUmounts.remove(oldEntry)) { + currentUmounts.add("$newPath|$newMode") + saveTryUmounts(context, currentUmounts) + if (isAutoStartEnabled(context)) updateMagiskModule(context) + showToast(context, "Try umount updated: $oldEntry -> $newPath|$newMode") + return true + } + return false + } + suspend fun runTryUmount(context: Context): Boolean = executeSusfsCommand(context, "run_try_umount") // 添加kstat配置 @@ -864,6 +903,23 @@ object SuSFSManager { return true } + // 编辑kstat配置 + @SuppressLint("StringFormatInvalid") + suspend fun editKstatConfig(context: Context, oldConfig: String, path: String, ino: String, dev: String, nlink: String, + size: String, atime: String, atimeNsec: String, mtime: String, mtimeNsec: String, + ctime: String, ctimeNsec: String, blocks: String, blksize: String): Boolean { + val currentConfigs = getKstatConfigs(context).toMutableSet() + if (currentConfigs.remove(oldConfig)) { + val newConfigEntry = "$path|$ino|$dev|$nlink|$size|$atime|$atimeNsec|$mtime|$mtimeNsec|$ctime|$ctimeNsec|$blocks|$blksize" + currentConfigs.add(newConfigEntry) + saveKstatConfigs(context, currentConfigs) + if (isAutoStartEnabled(context)) updateMagiskModule(context) + showToast(context, context.getString(R.string.kstat_config_updated, path)) + return true + } + return false + } + // 添加kstat路径 suspend fun addKstat(context: Context, path: String): Boolean { val success = executeSusfsCommand(context, "add_sus_kstat '$path'") @@ -882,6 +938,20 @@ object SuSFSManager { return true } + // 编辑kstat路径 + @SuppressLint("StringFormatInvalid") + suspend fun editAddKstat(context: Context, oldPath: String, newPath: String): Boolean { + val currentPaths = getAddKstatPaths(context).toMutableSet() + if (currentPaths.remove(oldPath)) { + currentPaths.add(newPath) + saveAddKstatPaths(context, currentPaths) + if (isAutoStartEnabled(context)) updateMagiskModule(context) + showToast(context, context.getString(R.string.kstat_path_updated, oldPath, newPath)) + return true + } + return false + } + // 更新kstat suspend fun updateKstat(context: Context, path: String): Boolean { val success = executeSusfsCommand(context, "update_sus_kstat '$path'") diff --git a/manager/app/src/main/res/values-zh-rCN/strings.xml b/manager/app/src/main/res/values-zh-rCN/strings.xml index 2f612645..9257a8fe 100644 --- a/manager/app/src/main/res/values-zh-rCN/strings.xml +++ b/manager/app/src/main/res/values-zh-rCN/strings.xml @@ -541,4 +541,16 @@ 启用隐藏Bootloader解锁状态脚本 清理工具残留 清理各种模块以及工具的残留文件和目录(可能会误删导致丢失以及无法启动,谨慎使用) + 编辑 SUS 路径 + 编辑 SUS 挂载 + 编辑尝试卸载 + 编辑 Kstat 静态配置 + 编辑 Kstat 路径 + 保存 + 编辑 + 删除 + 更新 + Kstat 配置更新 + Kstat 路径更新 + Susfs 完整克隆更新 diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index ba8d338a..b10c3c47 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -543,4 +543,16 @@ Enable Hide Bootloader Unlock Status Scripts Cleanup Residue Clean up the residual files and directories of various modules and tools (may be deleted by mistake, resulting in loss and failure to start, use with caution) + Edit SUS Path + Edit SUS Mount + Edit Try Umount + Edit Kstat Static Configuration + Edit Kstat Path + Save + Edit + Delete + Update + Kstat config update + Kstat path update + Susfs update full clone