From 8b42690cb3120f2c090bc871775a1ec9afd8607a Mon Sep 17 00:00:00 2001 From: 5ec1cff Date: Tue, 31 Dec 2024 13:41:03 +0800 Subject: [PATCH] allow restore uninstalled module & use module dir name as real id --- .../me/weishu/kernelsu/ui/screen/Module.kt | 69 ++++++++++++------- .../java/me/weishu/kernelsu/ui/util/KsuCli.kt | 7 ++ .../kernelsu/ui/viewmodel/ModuleViewModel.kt | 4 +- .../src/main/res/values-zh-rCN/strings.xml | 1 + manager/app/src/main/res/values/strings.xml | 1 + userspace/ksud/src/cli.rs | 7 ++ userspace/ksud/src/module.rs | 16 +++-- 7 files changed, 72 insertions(+), 33 deletions(-) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt index 28b45afa3098..3413e21843a2 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt @@ -36,6 +36,7 @@ import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.outlined.PlayArrow import androidx.compose.material.icons.outlined.Download import androidx.compose.material.icons.outlined.Delete +import androidx.compose.material.icons.outlined.Refresh import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Checkbox @@ -69,6 +70,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 @@ -101,6 +103,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.viewmodel.ModuleViewModel @@ -370,26 +373,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.id) + 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 { @@ -456,14 +467,14 @@ private fun ModuleList( navigator = navigator, module = module, updateUrl = updatedModule.first, - onUninstall = { - scope.launch { onModuleUninstall(module) } + onUninstallClicked = { + scope.launch { onModuleUninstallClicked(module) } }, onCheckChanged = { scope.launch { val success = loadingDialog.withLoading { withContext(Dispatchers.IO) { - toggleModule(module.id, !module.enabled) + toggleModule(module.dirId, !isChecked) } } if (success) { @@ -494,7 +505,7 @@ private fun ModuleList( } }, onClick = { - onClickModule(it.id, it.name, it.hasWebUi) + onClickModule(it.dirId, it.name, it.hasWebUi) } ) @@ -515,7 +526,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 @@ -626,7 +637,7 @@ fun ModuleItem( modifier = Modifier.defaultMinSize(52.dp, 32.dp), enabled = !module.remove && module.enabled, onClick = { - navigator.navigate(ExecuteModuleActionScreenDestination(module.id)) + navigator.navigate(ExecuteModuleActionScreenDestination(module.dirId)) viewModel.markNeedRefresh() }, contentPadding = ButtonDefaults.TextButtonContentPadding @@ -703,21 +714,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) ) } } @@ -741,7 +759,8 @@ fun ModuleItemPreview() { remove = false, updateJson = "", hasWebUi = false, - hasActionScript = false + hasActionScript = false, + dirId = "dirId" ) ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {}) } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt index 6d40399fa247..b6e3fbb2377b 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt @@ -143,6 +143,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, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt index 8d2085300947..081ef2b4f086 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt @@ -37,6 +37,7 @@ class ModuleViewModel : ViewModel() { val updateJson: String, val hasWebUi: Boolean, val hasActionScript: Boolean, + val dirId: String, // real module id (dir name) ) data class ModuleUpdateInfo( @@ -103,7 +104,8 @@ class ModuleViewModel : ViewModel() { obj.getBoolean("remove"), obj.optString("updateJson"), obj.optBoolean("web"), - obj.optBoolean("action") + obj.optBoolean("action"), + obj.getString("dir_id"), ) }.toList() isNeedRefresh = false 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 e133784b77e6..968f013cc189 100644 --- a/manager/app/src/main/res/values-zh-rCN/strings.xml +++ b/manager/app/src/main/res/values-zh-rCN/strings.xml @@ -24,6 +24,7 @@ 排序(有Action优先) 排序(已启用优先) 卸载 + 还原 安装 安装 重启 diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index f179fccd959c..6dba9e763c38 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -26,6 +26,7 @@ Sort (Action first) Sort (Enabled first) Uninstall + Restore Install Install Reboot diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs index 225552c02314..a336cbe48924 100644 --- a/userspace/ksud/src/cli.rs +++ b/userspace/ksud/src/cli.rs @@ -204,6 +204,12 @@ enum Module { id: String, }, + /// Restore module + Restore { + /// module id + id: String, + }, + /// enable module 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), diff --git a/userspace/ksud/src/module.rs b/userspace/ksud/src/module.rs index 83db689c4f7a..29e1706a5463 100644 --- a/userspace/ksud/src/module.rs +++ b/userspace/ksud/src/module.rs @@ -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,14 +460,12 @@ fn _list_modules(path: &str) -> Vec> { 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() { - if let Some(id) = entry.file_name().to_str() { - info!("Use dir name as module id: {}", id); - module_prop_map.insert("id".to_owned(), id.to_owned()); - } else { - 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