manager: Provides re-editable functionality for all SuSFS path configurations
This commit is contained in:
@@ -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 = {
|
||||
|
||||
@@ -51,7 +51,8 @@ fun SusPathsContent(
|
||||
susPaths: Set<String>,
|
||||
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
|
||||
|
||||
@@ -164,6 +164,13 @@ fun SuSFSConfigScreen(
|
||||
var showAddKstatStaticallyDialog by remember { mutableStateOf(false) }
|
||||
var showAddKstatDialog by remember { mutableStateOf(false) }
|
||||
|
||||
// 编辑状态
|
||||
var editingPath by remember { mutableStateOf<String?>(null) }
|
||||
var editingMount by remember { mutableStateOf<String?>(null) }
|
||||
var editingUmount by remember { mutableStateOf<String?>(null) }
|
||||
var editingKstatConfig by remember { mutableStateOf<String?>(null) }
|
||||
var editingKstatPath by remember { mutableStateOf<String?>(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
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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'")
|
||||
|
||||
@@ -541,4 +541,16 @@
|
||||
<string name="hide_bl_script_description">启用隐藏Bootloader解锁状态脚本</string>
|
||||
<string name="cleanup_residue">清理工具残留</string>
|
||||
<string name="cleanup_residue_description">清理各种模块以及工具的残留文件和目录(可能会误删导致丢失以及无法启动,谨慎使用)</string>
|
||||
<string name="susfs_edit_sus_path">编辑 SUS 路径</string>
|
||||
<string name="susfs_edit_sus_mount">编辑 SUS 挂载</string>
|
||||
<string name="susfs_edit_try_umount">编辑尝试卸载</string>
|
||||
<string name="edit_kstat_statically_title">编辑 Kstat 静态配置</string>
|
||||
<string name="edit_kstat_path_title">编辑 Kstat 路径</string>
|
||||
<string name="susfs_save">保存</string>
|
||||
<string name="edit">编辑</string>
|
||||
<string name="delete">删除</string>
|
||||
<string name="update">更新</string>
|
||||
<string name="kstat_config_updated">Kstat 配置更新</string>
|
||||
<string name="kstat_path_updated">Kstat 路径更新</string>
|
||||
<string name="susfs_update_full_clone">Susfs 完整克隆更新</string>
|
||||
</resources>
|
||||
|
||||
@@ -543,4 +543,16 @@
|
||||
<string name="hide_bl_script_description">Enable Hide Bootloader Unlock Status Scripts</string>
|
||||
<string name="cleanup_residue">Cleanup Residue</string>
|
||||
<string name="cleanup_residue_description">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)</string>
|
||||
<string name="susfs_edit_sus_path">Edit SUS Path</string>
|
||||
<string name="susfs_edit_sus_mount">Edit SUS Mount</string>
|
||||
<string name="susfs_edit_try_umount">Edit Try Umount</string>
|
||||
<string name="edit_kstat_statically_title">Edit Kstat Static Configuration</string>
|
||||
<string name="edit_kstat_path_title">Edit Kstat Path</string>
|
||||
<string name="susfs_save">Save</string>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="update">Update</string>
|
||||
<string name="kstat_config_updated">Kstat config update</string>
|
||||
<string name="kstat_path_updated">Kstat path update</string>
|
||||
<string name="susfs_update_full_clone">Susfs update full clone</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user