allow restore uninstalled module
This commit is contained in:
@@ -37,6 +37,7 @@ import androidx.compose.material.icons.outlined.PlayArrow
|
||||
import androidx.compose.material.icons.outlined.Download
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material.icons.outlined.Refresh
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Checkbox
|
||||
@@ -71,6 +72,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -104,6 +106,7 @@ import me.weishu.kernelsu.ui.util.LocalSnackbarHost
|
||||
import me.weishu.kernelsu.ui.util.download
|
||||
import me.weishu.kernelsu.ui.util.hasMagisk
|
||||
import me.weishu.kernelsu.ui.util.reboot
|
||||
import me.weishu.kernelsu.ui.util.restoreModule
|
||||
import me.weishu.kernelsu.ui.util.toggleModule
|
||||
import me.weishu.kernelsu.ui.util.uninstallModule
|
||||
import me.weishu.kernelsu.ui.util.getFileName
|
||||
@@ -398,26 +401,34 @@ private fun ModuleList(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun onModuleUninstall(module: ModuleViewModel.ModuleInfo) {
|
||||
val confirmResult = confirmDialog.awaitConfirm(
|
||||
moduleStr,
|
||||
content = moduleUninstallConfirm.format(module.name),
|
||||
confirm = uninstall,
|
||||
dismiss = cancel
|
||||
)
|
||||
if (confirmResult != ConfirmResult.Confirmed) {
|
||||
return
|
||||
suspend fun onModuleUninstallClicked(module: ModuleViewModel.ModuleInfo) {
|
||||
val isUninstall = !module.remove
|
||||
if (isUninstall) {
|
||||
val confirmResult = confirmDialog.awaitConfirm(
|
||||
moduleStr,
|
||||
content = moduleUninstallConfirm.format(module.name),
|
||||
confirm = uninstall,
|
||||
dismiss = cancel
|
||||
)
|
||||
if (confirmResult != ConfirmResult.Confirmed) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val success = loadingDialog.withLoading {
|
||||
withContext(Dispatchers.IO) {
|
||||
uninstallModule(module.dirId)
|
||||
if (isUninstall) {
|
||||
uninstallModule(module.dirId)
|
||||
} else {
|
||||
restoreModule(module.dirId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
viewModel.fetchModuleList()
|
||||
}
|
||||
if (!isUninstall) return
|
||||
val message = if (success) {
|
||||
successUninstall.format(module.name)
|
||||
} else {
|
||||
@@ -484,8 +495,8 @@ private fun ModuleList(
|
||||
navigator = navigator,
|
||||
module = module,
|
||||
updateUrl = updatedModule.first,
|
||||
onUninstall = {
|
||||
scope.launch { onModuleUninstall(module) }
|
||||
onUninstallClicked = {
|
||||
scope.launch { onModuleUninstallClicked(module) }
|
||||
},
|
||||
onCheckChanged = {
|
||||
scope.launch {
|
||||
@@ -543,7 +554,7 @@ fun ModuleItem(
|
||||
navigator: DestinationsNavigator,
|
||||
module: ModuleViewModel.ModuleInfo,
|
||||
updateUrl: String,
|
||||
onUninstall: (ModuleViewModel.ModuleInfo) -> Unit,
|
||||
onUninstallClicked: (ModuleViewModel.ModuleInfo) -> Unit,
|
||||
onCheckChanged: (Boolean) -> Unit,
|
||||
onUpdate: (ModuleViewModel.ModuleInfo) -> Unit,
|
||||
onClick: (ModuleViewModel.ModuleInfo) -> Unit
|
||||
@@ -731,21 +742,28 @@ fun ModuleItem(
|
||||
|
||||
FilledTonalButton(
|
||||
modifier = Modifier.defaultMinSize(52.dp, 32.dp),
|
||||
enabled = !module.remove,
|
||||
onClick = { onUninstall(module) },
|
||||
onClick = { onUninstallClicked(module) },
|
||||
contentPadding = ButtonDefaults.TextButtonContentPadding
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = Icons.Outlined.Delete,
|
||||
contentDescription = null
|
||||
)
|
||||
if (!module.remove) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = Icons.Outlined.Delete,
|
||||
contentDescription = null,
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp).rotate(180f),
|
||||
imageVector = Icons.Outlined.Refresh,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 7.dp),
|
||||
fontFamily = MaterialTheme.typography.labelMedium.fontFamily,
|
||||
fontSize = MaterialTheme.typography.labelMedium.fontSize,
|
||||
text = stringResource(R.string.uninstall)
|
||||
text = stringResource(if (!module.remove) R.string.uninstall else R.string.restore)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,13 @@ fun uninstallModule(id: String): Boolean {
|
||||
return result
|
||||
}
|
||||
|
||||
fun restoreModule(id: String): Boolean {
|
||||
val cmd = "module restore $id"
|
||||
val result = execKsud(cmd, true)
|
||||
Log.i(TAG, "restore module $id result: $result")
|
||||
return result
|
||||
}
|
||||
|
||||
private fun flashWithIO(
|
||||
cmd: String,
|
||||
onStdout: (String) -> Unit,
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<string name="module_sort_action_first">排序(可执行优先)</string>
|
||||
<string name="module_sort_enabled_first">排序(已启用优先)</string>
|
||||
<string name="uninstall">卸载</string>
|
||||
<string name="restore">还原</string>
|
||||
<string name="module_install">安装</string>
|
||||
<string name="install">安装</string>
|
||||
<string name="reboot">重启</string>
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<string name="module_sort_enabled_first">Sort (Enabled first)</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="uninstall">Uninstall</string>
|
||||
<string name="restore">Restore</string>
|
||||
<string name="module_install">Install</string>
|
||||
<string name="install">Install</string>
|
||||
<string name="reboot">Reboot</string>
|
||||
|
||||
@@ -204,6 +204,12 @@ enum Module {
|
||||
id: String,
|
||||
},
|
||||
|
||||
/// Restore module <id>
|
||||
Restore {
|
||||
/// module id
|
||||
id: String,
|
||||
},
|
||||
|
||||
/// enable module <id>
|
||||
Enable {
|
||||
/// module id
|
||||
@@ -303,6 +309,7 @@ pub fn run() -> Result<()> {
|
||||
match command {
|
||||
Module::Install { zip } => module::install_module(&zip),
|
||||
Module::Uninstall { id } => module::uninstall_module(&id),
|
||||
Module::Restore { id } => module::restore_uninstall_module(&id),
|
||||
Module::Enable { id } => module::enable_module(&id),
|
||||
Module::Disable { id } => module::disable_module(&id),
|
||||
Module::Action { id } => module::run_action(&id),
|
||||
|
||||
@@ -394,6 +394,10 @@ pub fn uninstall_module(id: &str) -> Result<()> {
|
||||
mark_module_state(id, defs::REMOVE_FILE_NAME, true)
|
||||
}
|
||||
|
||||
pub fn restore_uninstall_module(id: &str) -> Result<()> {
|
||||
mark_module_state(id, defs::REMOVE_FILE_NAME, false)
|
||||
}
|
||||
|
||||
pub fn run_action(id: &str) -> Result<()> {
|
||||
let action_script_path = format!("/data/adb/modules/{}/action.sh", id);
|
||||
exec_script(&action_script_path, true)
|
||||
@@ -456,17 +460,12 @@ fn _list_modules(path: &str) -> Vec<HashMap<String, String>> {
|
||||
module_prop_map.insert(k, v);
|
||||
});
|
||||
|
||||
let dir_id = entry.file_name().to_string_lossy().to_string();
|
||||
module_prop_map.insert("dir_id".to_owned(), dir_id.clone());
|
||||
|
||||
if !module_prop_map.contains_key("id") || module_prop_map["id"].is_empty() {
|
||||
match entry.file_name().to_str() {
|
||||
Some(id) => {
|
||||
info!("Use dir name as module id: {}", id);
|
||||
module_prop_map.insert("id".to_owned(), id.to_owned());
|
||||
}
|
||||
_ => {
|
||||
info!("Failed to get module id: {:?}", module_prop);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
info!("Use dir name as module id: {dir_id}");
|
||||
module_prop_map.insert("id".to_owned(), dir_id.clone());
|
||||
}
|
||||
|
||||
// Add enabled, update, remove flags
|
||||
|
||||
Reference in New Issue
Block a user