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.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -42,10 +43,18 @@ fun AddPathDialog(
|
|||||||
isLoading: Boolean,
|
isLoading: Boolean,
|
||||||
titleRes: Int,
|
titleRes: Int,
|
||||||
labelRes: Int,
|
labelRes: Int,
|
||||||
placeholderRes: Int
|
placeholderRes: Int,
|
||||||
|
initialValue: String = ""
|
||||||
) {
|
) {
|
||||||
var newPath by remember { mutableStateOf("") }
|
var newPath by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
// 当对话框显示时,设置初始值
|
||||||
|
LaunchedEffect(showDialog, initialValue) {
|
||||||
|
if (showDialog) {
|
||||||
|
newPath = initialValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (showDialog) {
|
if (showDialog) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
@@ -77,7 +86,7 @@ fun AddPathDialog(
|
|||||||
enabled = newPath.isNotBlank() && !isLoading,
|
enabled = newPath.isNotBlank() && !isLoading,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.add))
|
Text(stringResource(if (initialValue.isNotEmpty()) R.string.susfs_save else R.string.add))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
@@ -105,18 +114,28 @@ fun AddTryUmountDialog(
|
|||||||
showDialog: Boolean,
|
showDialog: Boolean,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onConfirm: (String, Int) -> Unit,
|
onConfirm: (String, Int) -> Unit,
|
||||||
isLoading: Boolean
|
isLoading: Boolean,
|
||||||
|
initialPath: String = "",
|
||||||
|
initialMode: Int = 0
|
||||||
) {
|
) {
|
||||||
var newUmountPath by remember { mutableStateOf("") }
|
var newUmountPath by remember { mutableStateOf("") }
|
||||||
var newUmountMode by remember { mutableIntStateOf(0) }
|
var newUmountMode by remember { mutableIntStateOf(0) }
|
||||||
var umountModeExpanded by remember { mutableStateOf(false) }
|
var umountModeExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
// 当对话框显示时,设置初始值
|
||||||
|
LaunchedEffect(showDialog, initialPath, initialMode) {
|
||||||
|
if (showDialog) {
|
||||||
|
newUmountPath = initialPath
|
||||||
|
newUmountMode = initialMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (showDialog) {
|
if (showDialog) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
title = {
|
title = {
|
||||||
Text(
|
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,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
fontWeight = FontWeight.Bold
|
fontWeight = FontWeight.Bold
|
||||||
)
|
)
|
||||||
@@ -186,7 +205,7 @@ fun AddTryUmountDialog(
|
|||||||
enabled = newUmountPath.isNotBlank() && !isLoading,
|
enabled = newUmountPath.isNotBlank() && !isLoading,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.add))
|
Text(stringResource(if (initialPath.isNotEmpty()) R.string.susfs_save else R.string.add))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
@@ -214,7 +233,8 @@ fun AddKstatStaticallyDialog(
|
|||||||
showDialog: Boolean,
|
showDialog: Boolean,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onConfirm: (String, String, String, String, String, String, String, String, String, String, String, String, String) -> 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 newKstatPath by remember { mutableStateOf("") }
|
||||||
var newKstatIno by remember { mutableStateOf("") }
|
var newKstatIno by remember { mutableStateOf("") }
|
||||||
@@ -230,12 +250,49 @@ fun AddKstatStaticallyDialog(
|
|||||||
var newKstatBlocks by remember { mutableStateOf("") }
|
var newKstatBlocks by remember { mutableStateOf("") }
|
||||||
var newKstatBlksize 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) {
|
if (showDialog) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
title = {
|
title = {
|
||||||
Text(
|
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,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
fontWeight = FontWeight.Bold
|
fontWeight = FontWeight.Bold
|
||||||
)
|
)
|
||||||
@@ -431,7 +488,7 @@ fun AddKstatStaticallyDialog(
|
|||||||
enabled = newKstatPath.isNotBlank() && !isLoading,
|
enabled = newKstatPath.isNotBlank() && !isLoading,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.add))
|
Text(stringResource(if (initialConfig.isNotEmpty()) R.string.susfs_save else R.string.add))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ fun SusPathsContent(
|
|||||||
susPaths: Set<String>,
|
susPaths: Set<String>,
|
||||||
isLoading: Boolean,
|
isLoading: Boolean,
|
||||||
onAddPath: () -> Unit,
|
onAddPath: () -> Unit,
|
||||||
onRemovePath: (String) -> Unit
|
onRemovePath: (String) -> Unit,
|
||||||
|
onEditPath: ((String) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@@ -70,6 +71,7 @@ fun SusPathsContent(
|
|||||||
path = path,
|
path = path,
|
||||||
icon = Icons.Default.Folder,
|
icon = Icons.Default.Folder,
|
||||||
onDelete = { onRemovePath(path) },
|
onDelete = { onRemovePath(path) },
|
||||||
|
onEdit = if (onEditPath != null) { { onEditPath(path) } } else null,
|
||||||
isLoading = isLoading
|
isLoading = isLoading
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -116,6 +118,7 @@ fun SusMountsContent(
|
|||||||
isLoading: Boolean,
|
isLoading: Boolean,
|
||||||
onAddMount: () -> Unit,
|
onAddMount: () -> Unit,
|
||||||
onRemoveMount: (String) -> Unit,
|
onRemoveMount: (String) -> Unit,
|
||||||
|
onEditMount: ((String) -> Unit)? = null,
|
||||||
onToggleHideSusMountsForAllProcs: (Boolean) -> Unit
|
onToggleHideSusMountsForAllProcs: (Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
@@ -145,6 +148,7 @@ fun SusMountsContent(
|
|||||||
path = mount,
|
path = mount,
|
||||||
icon = Icons.Default.Storage,
|
icon = Icons.Default.Storage,
|
||||||
onDelete = { onRemoveMount(mount) },
|
onDelete = { onRemoveMount(mount) },
|
||||||
|
onEdit = if (onEditMount != null) { { onEditMount(mount) } } else null,
|
||||||
isLoading = isLoading
|
isLoading = isLoading
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -189,7 +193,8 @@ fun TryUmountContent(
|
|||||||
isLoading: Boolean,
|
isLoading: Boolean,
|
||||||
onAddUmount: () -> Unit,
|
onAddUmount: () -> Unit,
|
||||||
onRunUmount: () -> Unit,
|
onRunUmount: () -> Unit,
|
||||||
onRemoveUmount: (String) -> Unit
|
onRemoveUmount: (String) -> Unit,
|
||||||
|
onEditUmount: ((String) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@@ -218,6 +223,7 @@ fun TryUmountContent(
|
|||||||
icon = Icons.Default.Storage,
|
icon = Icons.Default.Storage,
|
||||||
additionalInfo = stringResource(R.string.susfs_umount_mode_display, modeText, mode),
|
additionalInfo = stringResource(R.string.susfs_umount_mode_display, modeText, mode),
|
||||||
onDelete = { onRemoveUmount(umountEntry) },
|
onDelete = { onRemoveUmount(umountEntry) },
|
||||||
|
onEdit = if (onEditUmount != null) { { onEditUmount(umountEntry) } } else null,
|
||||||
isLoading = isLoading
|
isLoading = isLoading
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -282,7 +288,9 @@ fun KstatConfigContent(
|
|||||||
onAddKstatStatically: () -> Unit,
|
onAddKstatStatically: () -> Unit,
|
||||||
onAddKstat: () -> Unit,
|
onAddKstat: () -> Unit,
|
||||||
onRemoveKstatConfig: (String) -> Unit,
|
onRemoveKstatConfig: (String) -> Unit,
|
||||||
|
onEditKstatConfig: ((String) -> Unit)? = null,
|
||||||
onRemoveAddKstat: (String) -> Unit,
|
onRemoveAddKstat: (String) -> Unit,
|
||||||
|
onEditAddKstat: ((String) -> Unit)? = null,
|
||||||
onUpdateKstat: (String) -> Unit,
|
onUpdateKstat: (String) -> Unit,
|
||||||
onUpdateKstatFullClone: (String) -> Unit
|
onUpdateKstatFullClone: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
@@ -347,6 +355,7 @@ fun KstatConfigContent(
|
|||||||
KstatConfigItemCard(
|
KstatConfigItemCard(
|
||||||
config = config,
|
config = config,
|
||||||
onDelete = { onRemoveKstatConfig(config) },
|
onDelete = { onRemoveKstatConfig(config) },
|
||||||
|
onEdit = if (onEditKstatConfig != null) { { onEditKstatConfig(config) } } else null,
|
||||||
isLoading = isLoading
|
isLoading = isLoading
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -365,6 +374,7 @@ fun KstatConfigContent(
|
|||||||
AddKstatPathItemCard(
|
AddKstatPathItemCard(
|
||||||
path = path,
|
path = path,
|
||||||
onDelete = { onRemoveAddKstat(path) },
|
onDelete = { onRemoveAddKstat(path) },
|
||||||
|
onEdit = if (onEditAddKstat != null) { { onEditAddKstat(path) } } else null,
|
||||||
onUpdate = { onUpdateKstat(path) },
|
onUpdate = { onUpdateKstat(path) },
|
||||||
onUpdateFullClone = { onUpdateKstatFullClone(path) },
|
onUpdateFullClone = { onUpdateKstatFullClone(path) },
|
||||||
isLoading = isLoading
|
isLoading = isLoading
|
||||||
|
|||||||
@@ -164,6 +164,13 @@ fun SuSFSConfigScreen(
|
|||||||
var showAddKstatStaticallyDialog by remember { mutableStateOf(false) }
|
var showAddKstatStaticallyDialog by remember { mutableStateOf(false) }
|
||||||
var showAddKstatDialog 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 showResetPathsDialog by remember { mutableStateOf(false) }
|
||||||
var showResetMountsDialog by remember { mutableStateOf(false) }
|
var showResetMountsDialog by remember { mutableStateOf(false) }
|
||||||
@@ -499,94 +506,148 @@ fun SuSFSConfigScreen(
|
|||||||
// 各种对话框
|
// 各种对话框
|
||||||
AddPathDialog(
|
AddPathDialog(
|
||||||
showDialog = showAddPathDialog,
|
showDialog = showAddPathDialog,
|
||||||
onDismiss = { showAddPathDialog = false },
|
onDismiss = {
|
||||||
|
showAddPathDialog = false
|
||||||
|
editingPath = null
|
||||||
|
},
|
||||||
onConfirm = { path ->
|
onConfirm = { path ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
isLoading = true
|
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)
|
susPaths = SuSFSManager.getSusPaths(context)
|
||||||
}
|
}
|
||||||
isLoading = false
|
isLoading = false
|
||||||
showAddPathDialog = false
|
showAddPathDialog = false
|
||||||
|
editingPath = null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isLoading = isLoading,
|
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,
|
labelRes = R.string.susfs_path_label,
|
||||||
placeholderRes = R.string.susfs_path_placeholder
|
placeholderRes = R.string.susfs_path_placeholder,
|
||||||
|
initialValue = editingPath ?: ""
|
||||||
)
|
)
|
||||||
|
|
||||||
AddPathDialog(
|
AddPathDialog(
|
||||||
showDialog = showAddMountDialog,
|
showDialog = showAddMountDialog,
|
||||||
onDismiss = { showAddMountDialog = false },
|
onDismiss = {
|
||||||
|
showAddMountDialog = false
|
||||||
|
editingMount = null
|
||||||
|
},
|
||||||
onConfirm = { mount ->
|
onConfirm = { mount ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
isLoading = true
|
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)
|
susMounts = SuSFSManager.getSusMounts(context)
|
||||||
}
|
}
|
||||||
isLoading = false
|
isLoading = false
|
||||||
showAddMountDialog = false
|
showAddMountDialog = false
|
||||||
|
editingMount = null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isLoading = isLoading,
|
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,
|
labelRes = R.string.susfs_mount_path_label,
|
||||||
placeholderRes = R.string.susfs_path_placeholder
|
placeholderRes = R.string.susfs_path_placeholder,
|
||||||
|
initialValue = editingMount ?: ""
|
||||||
)
|
)
|
||||||
|
|
||||||
AddTryUmountDialog(
|
AddTryUmountDialog(
|
||||||
showDialog = showAddUmountDialog,
|
showDialog = showAddUmountDialog,
|
||||||
onDismiss = { showAddUmountDialog = false },
|
onDismiss = {
|
||||||
|
showAddUmountDialog = false
|
||||||
|
editingUmount = null
|
||||||
|
},
|
||||||
onConfirm = { path, mode ->
|
onConfirm = { path, mode ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
isLoading = true
|
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)
|
tryUmounts = SuSFSManager.getTryUmounts(context)
|
||||||
}
|
}
|
||||||
isLoading = false
|
isLoading = false
|
||||||
showAddUmountDialog = false
|
showAddUmountDialog = false
|
||||||
|
editingUmount = null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isLoading = isLoading
|
isLoading = isLoading,
|
||||||
|
initialPath = editingUmount?.split("|")?.get(0) ?: "",
|
||||||
|
initialMode = editingUmount?.split("|")?.get(1)?.toIntOrNull() ?: 0
|
||||||
)
|
)
|
||||||
|
|
||||||
AddKstatStaticallyDialog(
|
AddKstatStaticallyDialog(
|
||||||
showDialog = showAddKstatStaticallyDialog,
|
showDialog = showAddKstatStaticallyDialog,
|
||||||
onDismiss = { showAddKstatStaticallyDialog = false },
|
onDismiss = {
|
||||||
|
showAddKstatStaticallyDialog = false
|
||||||
|
editingKstatConfig = null
|
||||||
|
},
|
||||||
onConfirm = { path, ino, dev, nlink, size, atime, atimeNsec, mtime, mtimeNsec, ctime, ctimeNsec, blocks, blksize ->
|
onConfirm = { path, ino, dev, nlink, size, atime, atimeNsec, mtime, mtimeNsec, ctime, ctimeNsec, blocks, blksize ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
isLoading = true
|
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,
|
context, path, ino, dev, nlink, size, atime, atimeNsec,
|
||||||
mtime, mtimeNsec, ctime, ctimeNsec, blocks, blksize
|
mtime, mtimeNsec, ctime, ctimeNsec, blocks, blksize
|
||||||
)) {
|
)
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
kstatConfigs = SuSFSManager.getKstatConfigs(context)
|
kstatConfigs = SuSFSManager.getKstatConfigs(context)
|
||||||
}
|
}
|
||||||
isLoading = false
|
isLoading = false
|
||||||
showAddKstatStaticallyDialog = false
|
showAddKstatStaticallyDialog = false
|
||||||
|
editingKstatConfig = null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isLoading = isLoading
|
isLoading = isLoading,
|
||||||
|
initialConfig = editingKstatConfig ?: ""
|
||||||
)
|
)
|
||||||
|
|
||||||
AddPathDialog(
|
AddPathDialog(
|
||||||
showDialog = showAddKstatDialog,
|
showDialog = showAddKstatDialog,
|
||||||
onDismiss = { showAddKstatDialog = false },
|
onDismiss = {
|
||||||
|
showAddKstatDialog = false
|
||||||
|
editingKstatPath = null
|
||||||
|
},
|
||||||
onConfirm = { path ->
|
onConfirm = { path ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
isLoading = true
|
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)
|
addKstatPaths = SuSFSManager.getAddKstatPaths(context)
|
||||||
}
|
}
|
||||||
isLoading = false
|
isLoading = false
|
||||||
showAddKstatDialog = false
|
showAddKstatDialog = false
|
||||||
|
editingKstatPath = null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isLoading = isLoading,
|
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,
|
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
|
isLoading = false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onEditPath = { path ->
|
||||||
|
editingPath = path
|
||||||
|
showAddPathDialog = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1087,6 +1152,10 @@ fun SuSFSConfigScreen(
|
|||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onEditMount = { mount ->
|
||||||
|
editingMount = mount
|
||||||
|
showAddMountDialog = true
|
||||||
|
},
|
||||||
onToggleHideSusMountsForAllProcs = { hideForAll ->
|
onToggleHideSusMountsForAllProcs = { hideForAll ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
@@ -1113,6 +1182,10 @@ fun SuSFSConfigScreen(
|
|||||||
}
|
}
|
||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onEditUmount = { umountEntry ->
|
||||||
|
editingUmount = umountEntry
|
||||||
|
showAddUmountDialog = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1132,6 +1205,10 @@ fun SuSFSConfigScreen(
|
|||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onEditKstatConfig = { config ->
|
||||||
|
editingKstatConfig = config
|
||||||
|
showAddKstatStaticallyDialog = true
|
||||||
|
},
|
||||||
onRemoveAddKstat = { path ->
|
onRemoveAddKstat = { path ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
@@ -1141,6 +1218,10 @@ fun SuSFSConfigScreen(
|
|||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onEditAddKstat = { path ->
|
||||||
|
editingKstatPath = path
|
||||||
|
showAddKstatDialog = true
|
||||||
|
},
|
||||||
onUpdateKstat = { path ->
|
onUpdateKstat = { path ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.width
|
|||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Delete
|
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.Folder
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.material.icons.filled.Update
|
import androidx.compose.material.icons.filled.Update
|
||||||
@@ -91,6 +92,7 @@ fun PathItemCard(
|
|||||||
path: String,
|
path: String,
|
||||||
icon: ImageVector,
|
icon: ImageVector,
|
||||||
onDelete: () -> Unit,
|
onDelete: () -> Unit,
|
||||||
|
onEdit: (() -> Unit)? = null,
|
||||||
isLoading: Boolean = false,
|
isLoading: Boolean = false,
|
||||||
additionalInfo: String? = null
|
additionalInfo: String? = null
|
||||||
) {
|
) {
|
||||||
@@ -134,6 +136,23 @@ fun PathItemCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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(
|
IconButton(
|
||||||
onClick = onDelete,
|
onClick = onDelete,
|
||||||
enabled = !isLoading,
|
enabled = !isLoading,
|
||||||
@@ -141,7 +160,7 @@ fun PathItemCard(
|
|||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Delete,
|
imageVector = Icons.Default.Delete,
|
||||||
contentDescription = null,
|
contentDescription = stringResource(R.string.delete),
|
||||||
tint = MaterialTheme.colorScheme.error,
|
tint = MaterialTheme.colorScheme.error,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
)
|
)
|
||||||
@@ -149,6 +168,7 @@ fun PathItemCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kstat配置项目卡片组件
|
* Kstat配置项目卡片组件
|
||||||
@@ -157,6 +177,7 @@ fun PathItemCard(
|
|||||||
fun KstatConfigItemCard(
|
fun KstatConfigItemCard(
|
||||||
config: String,
|
config: String,
|
||||||
onDelete: () -> Unit,
|
onDelete: () -> Unit,
|
||||||
|
onEdit: (() -> Unit)? = null,
|
||||||
isLoading: Boolean = false
|
isLoading: Boolean = false
|
||||||
) {
|
) {
|
||||||
Card(
|
Card(
|
||||||
@@ -208,6 +229,23 @@ fun KstatConfigItemCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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(
|
IconButton(
|
||||||
onClick = onDelete,
|
onClick = onDelete,
|
||||||
enabled = !isLoading,
|
enabled = !isLoading,
|
||||||
@@ -215,7 +253,7 @@ fun KstatConfigItemCard(
|
|||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Delete,
|
imageVector = Icons.Default.Delete,
|
||||||
contentDescription = null,
|
contentDescription = stringResource(R.string.delete),
|
||||||
tint = MaterialTheme.colorScheme.error,
|
tint = MaterialTheme.colorScheme.error,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
)
|
)
|
||||||
@@ -223,6 +261,7 @@ fun KstatConfigItemCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add Kstat路径项目卡片组件
|
* Add Kstat路径项目卡片组件
|
||||||
@@ -231,6 +270,7 @@ fun KstatConfigItemCard(
|
|||||||
fun AddKstatPathItemCard(
|
fun AddKstatPathItemCard(
|
||||||
path: String,
|
path: String,
|
||||||
onDelete: () -> Unit,
|
onDelete: () -> Unit,
|
||||||
|
onEdit: (() -> Unit)? = null,
|
||||||
onUpdate: () -> Unit,
|
onUpdate: () -> Unit,
|
||||||
onUpdateFullClone: () -> Unit,
|
onUpdateFullClone: () -> Unit,
|
||||||
isLoading: Boolean = false
|
isLoading: Boolean = false
|
||||||
@@ -269,6 +309,20 @@ fun AddKstatPathItemCard(
|
|||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
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(
|
IconButton(
|
||||||
onClick = onUpdate,
|
onClick = onUpdate,
|
||||||
enabled = !isLoading,
|
enabled = !isLoading,
|
||||||
@@ -276,7 +330,7 @@ fun AddKstatPathItemCard(
|
|||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Update,
|
imageVector = Icons.Default.Update,
|
||||||
contentDescription = null,
|
contentDescription = stringResource(R.string.update),
|
||||||
tint = MaterialTheme.colorScheme.secondary,
|
tint = MaterialTheme.colorScheme.secondary,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
)
|
)
|
||||||
@@ -288,7 +342,7 @@ fun AddKstatPathItemCard(
|
|||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.PlayArrow,
|
imageVector = Icons.Default.PlayArrow,
|
||||||
contentDescription = null,
|
contentDescription = stringResource(R.string.susfs_update_full_clone),
|
||||||
tint = MaterialTheme.colorScheme.tertiary,
|
tint = MaterialTheme.colorScheme.tertiary,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
)
|
)
|
||||||
@@ -300,7 +354,7 @@ fun AddKstatPathItemCard(
|
|||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Delete,
|
imageVector = Icons.Default.Delete,
|
||||||
contentDescription = null,
|
contentDescription = stringResource(R.string.delete),
|
||||||
tint = MaterialTheme.colorScheme.error,
|
tint = MaterialTheme.colorScheme.error,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -800,6 +800,19 @@ object SuSFSManager {
|
|||||||
return true
|
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挂载
|
// 添加SUS挂载
|
||||||
suspend fun addSusMount(context: Context, mount: String): Boolean {
|
suspend fun addSusMount(context: Context, mount: String): Boolean {
|
||||||
val success = executeSusfsCommand(context, "add_sus_mount '$mount'")
|
val success = executeSusfsCommand(context, "add_sus_mount '$mount'")
|
||||||
@@ -817,6 +830,19 @@ object SuSFSManager {
|
|||||||
return true
|
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 {
|
suspend fun addTryUmount(context: Context, path: String, mode: Int): Boolean {
|
||||||
val commandSuccess = executeSusfsCommand(context, "add_try_umount '$path' $mode")
|
val commandSuccess = executeSusfsCommand(context, "add_try_umount '$path' $mode")
|
||||||
@@ -839,6 +865,19 @@ object SuSFSManager {
|
|||||||
return true
|
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")
|
suspend fun runTryUmount(context: Context): Boolean = executeSusfsCommand(context, "run_try_umount")
|
||||||
|
|
||||||
// 添加kstat配置
|
// 添加kstat配置
|
||||||
@@ -864,6 +903,23 @@ object SuSFSManager {
|
|||||||
return true
|
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路径
|
// 添加kstat路径
|
||||||
suspend fun addKstat(context: Context, path: String): Boolean {
|
suspend fun addKstat(context: Context, path: String): Boolean {
|
||||||
val success = executeSusfsCommand(context, "add_sus_kstat '$path'")
|
val success = executeSusfsCommand(context, "add_sus_kstat '$path'")
|
||||||
@@ -882,6 +938,20 @@ object SuSFSManager {
|
|||||||
return true
|
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
|
// 更新kstat
|
||||||
suspend fun updateKstat(context: Context, path: String): Boolean {
|
suspend fun updateKstat(context: Context, path: String): Boolean {
|
||||||
val success = executeSusfsCommand(context, "update_sus_kstat '$path'")
|
val success = executeSusfsCommand(context, "update_sus_kstat '$path'")
|
||||||
|
|||||||
@@ -541,4 +541,16 @@
|
|||||||
<string name="hide_bl_script_description">启用隐藏Bootloader解锁状态脚本</string>
|
<string name="hide_bl_script_description">启用隐藏Bootloader解锁状态脚本</string>
|
||||||
<string name="cleanup_residue">清理工具残留</string>
|
<string name="cleanup_residue">清理工具残留</string>
|
||||||
<string name="cleanup_residue_description">清理各种模块以及工具的残留文件和目录(可能会误删导致丢失以及无法启动,谨慎使用)</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>
|
</resources>
|
||||||
|
|||||||
@@ -543,4 +543,16 @@
|
|||||||
<string name="hide_bl_script_description">Enable Hide Bootloader Unlock Status Scripts</string>
|
<string name="hide_bl_script_description">Enable Hide Bootloader Unlock Status Scripts</string>
|
||||||
<string name="cleanup_residue">Cleanup Residue</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="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>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user