From adf3920caa3c7e34899ce304f3b39170c65c3138 Mon Sep 17 00:00:00 2001 From: Rifat Azad Date: Thu, 19 Dec 2024 17:33:20 +0600 Subject: [PATCH] ksud: added module restore cmd, replaced pkg id for debug and uninstall manager and changed banner manager: implement restore module UI --- .../com/rifsxd/ksunext/ui/screen/Module.kt | 125 ++++++++++++------ .../java/com/rifsxd/ksunext/ui/util/KsuCli.kt | 7 + manager/app/src/main/res/values/strings.xml | 4 + userspace/ksud/src/banner | 4 + userspace/ksud/src/cli.rs | 9 +- userspace/ksud/src/module.rs | 4 + userspace/ksud/src/utils.rs | 2 +- 7 files changed, 116 insertions(+), 39 deletions(-) diff --git a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Module.kt b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Module.kt index d26ec503..a078c240 100644 --- a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Module.kt +++ b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Module.kt @@ -31,10 +31,8 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.selection.toggleable import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.Wysiwyg -import androidx.compose.material.icons.filled.Add -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.filled.* +import androidx.compose.material.icons.outlined.* import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -101,6 +99,7 @@ import com.rifsxd.ksunext.ui.util.hasMagisk import com.rifsxd.ksunext.ui.util.reboot import com.rifsxd.ksunext.ui.util.toggleModule import com.rifsxd.ksunext.ui.util.uninstallModule +import com.rifsxd.ksunext.ui.util.restoreModule import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel import com.rifsxd.ksunext.ui.webui.WebUIActivity import okhttp3.OkHttpClient @@ -255,13 +254,17 @@ private fun ModuleList( val failedEnable = stringResource(R.string.module_failed_to_enable) val failedDisable = stringResource(R.string.module_failed_to_disable) val failedUninstall = stringResource(R.string.module_uninstall_failed) + val failedRestore = stringResource(R.string.module_restore_failed) val successUninstall = stringResource(R.string.module_uninstall_success) + val successRestore = stringResource(R.string.module_restore_success) val reboot = stringResource(R.string.reboot) val rebootToApply = stringResource(R.string.reboot_to_apply) val moduleStr = stringResource(R.string.module) val uninstall = stringResource(R.string.uninstall) + val restore = stringResource(R.string.restore) val cancel = stringResource(android.R.string.cancel) val moduleUninstallConfirm = stringResource(R.string.module_uninstall_confirm) + val moduleRestoreConfirm = stringResource(R.string.module_restore_confirm) val updateText = stringResource(R.string.module_update) val changelogText = stringResource(R.string.module_changelog) val downloadingText = stringResource(R.string.module_downloading) @@ -375,6 +378,33 @@ private fun ModuleList( reboot() } } + + suspend fun onModuleRestore(module: ModuleViewModel.ModuleInfo) { + val confirmResult = confirmDialog.awaitConfirm( + moduleStr, + content = moduleRestoreConfirm.format(module.name), + confirm = restore, + dismiss = cancel + ) + if (confirmResult != ConfirmResult.Confirmed) { + return + } + + val success = loadingDialog.withLoading { + withContext(Dispatchers.IO) { + restoreModule(module.id) + } + } + + if (success) { + viewModel.fetchModuleList() + } + val message = if (success) { + successRestore.format(module.name) + } else { + failedRestore.format(module.name) + } + } PullToRefreshBox( modifier = boxModifier, onRefresh = { @@ -427,6 +457,9 @@ private fun ModuleList( onUninstall = { scope.launch { onModuleUninstall(module) } }, + onRestore = { + scope.launch { onModuleRestore(module) } + }, onCheckChanged = { scope.launch { val success = loadingDialog.withLoading { @@ -486,6 +519,7 @@ fun ModuleItem( isChecked: Boolean, updateUrl: String, onUninstall: (ModuleViewModel.ModuleInfo) -> Unit, + onRestore: (ModuleViewModel.ModuleInfo) -> Unit, onCheckChanged: (Boolean) -> Unit, onUpdate: (ModuleViewModel.ModuleInfo) -> Unit, onClick: (ModuleViewModel.ModuleInfo) -> Unit @@ -576,29 +610,28 @@ fun ModuleItem( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - if (module.hasActionScript) { FilledTonalButton( modifier = Modifier.defaultMinSize(52.dp, 32.dp), onClick = { - navigator.navigate(ExecuteModuleActionScreenDestination(module.id)) - viewModel.markNeedRefresh() + navigator.navigate(ExecuteModuleActionScreenDestination(module.id)) + viewModel.markNeedRefresh() }, contentPadding = ButtonDefaults.TextButtonContentPadding ) { Icon( - modifier = Modifier.size(20.dp), + modifier = Modifier.size(20.dp), imageVector = Icons.Outlined.PlayArrow, contentDescription = null ) - if (!module.hasWebUi && updateUrl.isEmpty()) { + if (!module.hasWebUi && updateUrl.isEmpty()) { Text( - modifier = Modifier.padding(start = 7.dp), + modifier = Modifier.padding(start = 7.dp), text = stringResource(R.string.action), fontFamily = MaterialTheme.typography.labelMedium.fontFamily, fontSize = MaterialTheme.typography.labelMedium.fontSize ) - } + } } Spacer(modifier = Modifier.weight(0.1f, true)) @@ -612,16 +645,16 @@ fun ModuleItem( contentPadding = ButtonDefaults.TextButtonContentPadding ) { Icon( - modifier = Modifier.size(20.dp), + modifier = Modifier.size(20.dp), imageVector = Icons.AutoMirrored.Outlined.Wysiwyg, contentDescription = null ) if (!module.hasActionScript && updateUrl.isEmpty()) { Text( - modifier = Modifier.padding(start = 7.dp), - fontFamily = MaterialTheme.typography.labelMedium.fontFamily, - fontSize = MaterialTheme.typography.labelMedium.fontSize, - text = stringResource(R.string.open) + modifier = Modifier.padding(start = 7.dp), + fontFamily = MaterialTheme.typography.labelMedium.fontFamily, + fontSize = MaterialTheme.typography.labelMedium.fontSize, + text = stringResource(R.string.open) ) } } @@ -636,43 +669,61 @@ fun ModuleItem( shape = ButtonDefaults.textShape, contentPadding = ButtonDefaults.TextButtonContentPadding ) { - Icon( + Icon( modifier = Modifier.size(20.dp), imageVector = Icons.Outlined.Download, contentDescription = null - ) - if (!module.hasActionScript || !module.hasWebUi) { + ) + if (!module.hasActionScript || !module.hasWebUi) { Text( - modifier = Modifier.padding(start = 7.dp), + modifier = Modifier.padding(start = 7.dp), fontFamily = MaterialTheme.typography.labelMedium.fontFamily, fontSize = MaterialTheme.typography.labelMedium.fontSize, text = stringResource(R.string.module_update) ) - } + } } Spacer(modifier = Modifier.weight(0.1f, true)) } - FilledTonalButton( - modifier = Modifier.defaultMinSize(52.dp, 32.dp), - enabled = !module.remove, - onClick = { onUninstall(module) }, - contentPadding = ButtonDefaults.TextButtonContentPadding - ) { - Icon( - modifier = Modifier.size(20.dp), - imageVector = Icons.Outlined.Delete, - contentDescription = null - ) - if (!module.hasActionScript && !module.hasWebUi && updateUrl.isEmpty()) { - Text( - modifier = Modifier.padding(start = 7.dp), + if (module.remove) { + FilledTonalButton( + modifier = Modifier.defaultMinSize(52.dp, 32.dp), + onClick = { onRestore(module) }, + contentPadding = ButtonDefaults.TextButtonContentPadding + ) { + Icon( + modifier = Modifier.size(20.dp), + imageVector = Icons.Outlined.Restore, + contentDescription = null + ) + Text( + modifier = Modifier.padding(start = 7.dp), + fontFamily = MaterialTheme.typography.labelMedium.fontFamily, + fontSize = MaterialTheme.typography.labelMedium.fontSize, + text = stringResource(R.string.restore) + ) + } + } else { + FilledTonalButton( + modifier = Modifier.defaultMinSize(52.dp, 32.dp), + enabled = true, + onClick = { onUninstall(module) }, + contentPadding = ButtonDefaults.TextButtonContentPadding + ) { + Icon( + modifier = Modifier.size(20.dp), + imageVector = Icons.Outlined.Delete, + contentDescription = null + ) + Text( + modifier = Modifier.padding(start = 7.dp), fontFamily = MaterialTheme.typography.labelMedium.fontFamily, fontSize = MaterialTheme.typography.labelMedium.fontSize, text = stringResource(R.string.uninstall) ) - } + } } } } @@ -696,5 +747,5 @@ fun ModuleItemPreview() { hasWebUi = false, hasActionScript = false ) - ModuleItem(EmptyDestinationsNavigator, module, true, "", {}, {}, {}, {}) + ModuleItem(EmptyDestinationsNavigator, module, true, "", {}, {}, {}, {}, {}) } \ No newline at end of file diff --git a/manager/app/src/main/java/com/rifsxd/ksunext/ui/util/KsuCli.kt b/manager/app/src/main/java/com/rifsxd/ksunext/ui/util/KsuCli.kt index efc5a96c..b717efa8 100644 --- a/manager/app/src/main/java/com/rifsxd/ksunext/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/com/rifsxd/ksunext/ui/util/KsuCli.kt @@ -142,6 +142,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/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index de562fd9..786c17fb 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -27,6 +27,7 @@ Confirm Installation Do you want to continue installing this module?\nModule: %1$s Uninstall + Restore Install Install Reboot @@ -40,6 +41,9 @@ Are you sure you want to uninstall module %s? %s uninstalled Failed to uninstall: %s + Are you sure you want to restore module %s? + %s restoreed + Failed to restore: %s Version Author Refresh diff --git a/userspace/ksud/src/banner b/userspace/ksud/src/banner index 6087569c..bf46a6ce 100644 --- a/userspace/ksud/src/banner +++ b/userspace/ksud/src/banner @@ -3,3 +3,7 @@ | ' // _ \ '__| '_ \ / _ \ \___ \| | | | | . \ __/ | | | | | __/ |___) | |_| | |_|\_\___|_| |_| |_|\___|_|____/ \___/ + | \ | | _____ _| |_ + | \| |/ _ \ \/ / __| + | |\ | __/> <| |_ + |_| \_|\___/_/\_\\__| diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs index 7d8f35ce..8cdb4a5b 100644 --- a/userspace/ksud/src/cli.rs +++ b/userspace/ksud/src/cli.rs @@ -143,7 +143,7 @@ enum Debug { /// Set the manager app, kernel CONFIG_KSU_DEBUG should be enabled. SetManager { /// manager package name - #[arg(default_value_t = String::from("me.weishu.kernelsu"))] + #[arg(default_value_t = String::from("com.rifsxd.ksunext"))] apk: String, }, @@ -204,6 +204,12 @@ enum Module { id: String, }, + /// Restore module + Restore { + /// module id + id: String, + }, + /// enable module Enable { /// module id @@ -304,6 +310,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_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 4971c2f0..8c5c8c87 100644 --- a/userspace/ksud/src/module.rs +++ b/userspace/ksud/src/module.rs @@ -392,6 +392,10 @@ pub fn uninstall_module(id: &str) -> Result<()> { mark_module_state(id, defs::REMOVE_FILE_NAME, true) } +pub fn restore_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) diff --git a/userspace/ksud/src/utils.rs b/userspace/ksud/src/utils.rs index 0bc13245..21033918 100644 --- a/userspace/ksud/src/utils.rs +++ b/userspace/ksud/src/utils.rs @@ -225,7 +225,7 @@ pub fn uninstall(magiskboot_path: Option) -> Result<()> { boot_patch::restore(None, magiskboot_path, true)?; println!("- Uninstall KernelSU manager.."); Command::new("pm") - .args(["uninstall", "me.weishu.kernelsu"]) + .args(["uninstall", "com.rifsxd.ksunext"]) .spawn()?; println!("- Rebooting in 5 seconds.."); std::thread::sleep(std::time::Duration::from_secs(5));