From a30dfbc15dffa1e5631a66dcd849c7dc86d52d74 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 1 Apr 2025 14:34:24 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E4=BC=98=E5=8C=96KPM=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E5=92=8C=E5=8D=B8=E8=BD=BD=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E6=94=B9=E8=BF=9B=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=BC=BA=E6=A8=A1=E5=9D=97=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shirkneko/zako/sukisu/ui/screen/kpm.kt | 29 +++--- .../shirkneko/zako/sukisu/ui/util/KsuCli.kt | 20 ++-- .../zako/sukisu/ui/viewmodel/KpmViewModel.kt | 96 ++++++++++++------- 3 files changed, 92 insertions(+), 53 deletions(-) diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt index 6c7729ba..ad627ea3 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt @@ -103,18 +103,15 @@ fun KpmScreen( if (confirmResult == ConfirmResult.Confirmed) { val success = loadingDialog.withLoading { try { - val process = ProcessBuilder("nsenter", "-t", "1", "-m").start() - process.waitFor() loadKpmModule(tempFile.absolutePath) + true } catch (e: Exception) { - Log.e("KsuCli", "Failed to execute nsenter command: ${e.message}") - "failed" + Log.e("KsuCli", "Failed to load KPM module: ${e.message}") + false } } - Log.d("KsuCli", "loadKpmModule result: $success") - - if (success.contains("Success", ignoreCase = true)) { + if (success) { viewModel.fetchModuleList() snackBarHost.showSnackbar( message = kpmInstallSuccess, @@ -136,7 +133,7 @@ fun KpmScreen( viewModel.fetchModuleList() } } - // 使用 SharedPreferences 存储声明是否关闭的状态 + val sharedPreferences = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) var isNoticeClosed by remember { mutableStateOf(sharedPreferences.getBoolean("is_notice_closed", false)) } @@ -196,7 +193,7 @@ fun KpmScreen( ) IconButton(onClick = { isNoticeClosed = true - sharedPreferences.edit() { putBoolean("is_notice_closed", true) } + sharedPreferences.edit { putBoolean("is_notice_closed", true) } }) { Icon( imageVector = Icons.Outlined.Close, @@ -241,10 +238,15 @@ fun KpmScreen( ) if (confirmResult == ConfirmResult.Confirmed) { val success = loadingDialog.withLoading { - unloadKpmModule(module.id) + try { + unloadKpmModule(module.id) + true + } catch (e: Exception) { + Log.e("KsuCli", "Failed to unload KPM module: ${e.message}") + false + } } - Log.d("KsuCli", "unloadKpmModule result: $success") - if (success.contains("Success", ignoreCase = true)) { + if (success) { viewModel.fetchModuleList() snackBarHost.showSnackbar( message = kpmUninstallSuccess, @@ -323,7 +325,8 @@ private fun KpmModuleItem( horizontalArrangement = Arrangement.spacedBy(8.dp) ) { FilledTonalButton( - onClick = onControl + onClick = onControl, + enabled = module.hasAction ) { Icon( imageVector = Icons.Outlined.Settings, diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt index 1b5df7db..d6374e78 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt @@ -490,14 +490,14 @@ fun loadKpmModule(path: String, args: String? = null): Boolean { val shell = getRootShell() val cmd = "${getKpmmgrPath()} load $path ${args ?: ""}" val result = ShellUtils.fastCmd(shell, cmd) - return result.contains("Success") + return result.contains("Success", ignoreCase = true) } fun unloadKpmModule(name: String): Boolean { val shell = getRootShell() val cmd = "${getKpmmgrPath()} unload $name" val result = ShellUtils.fastCmd(shell, cmd) - return result.trim().toIntOrNull() == 0 + return result.trim().isEmpty() || result.trim() == "0" } fun getKpmModuleCount(): Int { @@ -510,15 +510,23 @@ fun getKpmModuleCount(): Int { fun listKpmModules(): String { val shell = getRootShell() val cmd = "${getKpmmgrPath()} list" - val result = ShellUtils.fastCmd(shell, cmd) - return result.trim() + return try { + ShellUtils.fastCmd(shell, cmd).trim() + } catch (e: Exception) { + Log.e(TAG, "Failed to list KPM modules", e) + "" + } } fun getKpmModuleInfo(name: String): String { val shell = getRootShell() val cmd = "${getKpmmgrPath()} info $name" - val result = ShellUtils.fastCmd(shell, cmd) - return result.trim() + return try { + ShellUtils.fastCmd(shell, cmd).trim() + } catch (e: Exception) { + Log.e(TAG, "Failed to get KPM module info: $name", e) + "" + } } fun controlKpmModule(name: String, args: String? = null): Int { diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt index 803c3222..36320e49 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt @@ -15,7 +15,6 @@ class KpmViewModel : ViewModel() { var moduleList by mutableStateOf(emptyList()) private set - var search by mutableStateOf("") internal set @@ -25,18 +24,6 @@ class KpmViewModel : ViewModel() { var currentModuleDetail by mutableStateOf("") private set - fun loadModuleDetail(moduleId: String) { - viewModelScope.launch { - currentModuleDetail = withContext(Dispatchers.IO) { - try { - getKpmModuleInfo(moduleId) - } catch (e: Exception) { - "无法获取模块详细信息: ${e.message}" - } - } - Log.d("KsuCli", "Module detail: $currentModuleDetail") - } - } fun fetchModuleList() { viewModelScope.launch { @@ -45,37 +32,78 @@ class KpmViewModel : ViewModel() { val moduleCount = getKpmModuleCount() Log.d("KsuCli", "Module count: $moduleCount") - val moduleInfo = listKpmModules() - Log.d("KsuCli", "Module info: $moduleInfo") - - val modules = parseModuleList(moduleInfo) - moduleList = modules + moduleList = getAllKpmModuleInfo() // 获取 KPM 版本信息 val kpmVersion = getKpmVersion() Log.d("KsuCli", "KPM Version: $kpmVersion") + } catch (e: Exception) { + Log.e("KsuCli", "获取模块列表失败", e) } finally { isRefreshing = false } } } - private fun parseModuleList(output: String): List { - return output.split("\n").mapNotNull { line -> - if (line.isBlank()) return@mapNotNull null - val parts = line.split("|") - if (parts.size < 7) return@mapNotNull null + private fun getAllKpmModuleInfo(): List { + val result = mutableListOf() + try { + val moduleNames = listKpmModules() + .split("\n") + .filter { it.isNotBlank() } - ModuleInfo( - id = parts[0].trim(), - name = parts[1].trim(), - version = parts[2].trim(), - author = parts[3].trim(), - description = parts[4].trim(), - args = parts[6].trim(), - enabled = true, - hasAction = controlKpmModule(parts[0].trim()).isNotBlank() - ) + for (name in moduleNames) { + try { + val moduleInfo = parseModuleInfo(name) + moduleInfo?.let { result.add(it) } + } catch (e: Exception) { + Log.e("KsuCli", "Error processing module $name", e) + } + } + } catch (e: Exception) { + Log.e("KsuCli", "Failed to get module list", e) + } + return result + } + + private fun parseModuleInfo(name: String): ModuleInfo? { + val info = getKpmModuleInfo(name) + if (info.isBlank()) return null + + val properties = info.lines() + .filter { it.isNotBlank() && !it.startsWith("#") } + .associate { line -> + val parts = line.split("=", limit = 2) + if (parts.size == 2) { + parts[0].trim() to parts[1].trim() + } else { + parts[0].trim() to "" + } + } + + return ModuleInfo( + id = name, + name = properties["name"] ?: name, + version = properties["version"] ?: "unknown", + author = properties["author"] ?: "unknown", + description = properties["description"] ?: "", + args = properties["args"] ?: "", + enabled = true, // 默认启用 + hasAction = properties["has_action"]?.toBoolean() ?: false + ) + } + + fun loadModuleDetail(moduleId: String) { + viewModelScope.launch { + try { + currentModuleDetail = withContext(Dispatchers.IO) { + getKpmModuleInfo(moduleId) + } + Log.d("KsuCli", "Module detail loaded: $currentModuleDetail") + } catch (e: Exception) { + Log.e("KsuCli", "Failed to load module detail", e) + currentModuleDetail = "Error: ${e.message}" + } } } @@ -90,4 +118,4 @@ class KpmViewModel : ViewModel() { val enabled: Boolean, val hasAction: Boolean ) -} \ No newline at end of file +} From 0c5dcec7bcae47c8fb9c750b2c91871b3b38e618 Mon Sep 17 00:00:00 2001 From: liankong Date: Tue, 1 Apr 2025 14:57:22 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E4=BF=AE=E5=A4=8DKPM?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zako/sukisu/ui/viewmodel/KpmViewModel.kt | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt index 36320e49..e72c2a14 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt @@ -70,16 +70,21 @@ class KpmViewModel : ViewModel() { val info = getKpmModuleInfo(name) if (info.isBlank()) return null - val properties = info.lines() - .filter { it.isNotBlank() && !it.startsWith("#") } - .associate { line -> - val parts = line.split("=", limit = 2) - if (parts.size == 2) { - parts[0].trim() to parts[1].trim() - } else { - parts[0].trim() to "" + val properties = info.lineSequence() // 使用序列提升大文本性能 + .filter { line -> + val trimmed = line.trim() + trimmed.isNotEmpty() && !trimmed.startsWith("#") + } + .mapNotNull { line -> + line.split("=", limit = 2).let { parts -> + when (parts.size) { + 2 -> parts[0].trim() to parts[1].trim() + 1 -> parts[0].trim() to "" + else -> null // 忽略无效行 + } } } + .toMap() return ModuleInfo( id = name, @@ -88,8 +93,8 @@ class KpmViewModel : ViewModel() { author = properties["author"] ?: "unknown", description = properties["description"] ?: "", args = properties["args"] ?: "", - enabled = true, // 默认启用 - hasAction = properties["has_action"]?.toBoolean() ?: false + enabled = true, + hasAction = true ) } From 90b79f5c0419ea59dcfc6bb75de9c3bcf1108296 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 1 Apr 2025 15:04:09 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E5=B0=86KPM=E6=A8=A1=E5=9D=97=E7=9A=84Snac?= =?UTF-8?q?kbar=E6=8C=81=E7=BB=AD=E6=97=B6=E9=97=B4=E4=BB=8E=E9=95=BF?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E7=9F=AD=EF=BC=8C=E4=BB=A5=E6=94=B9=E5=96=84?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt index ad627ea3..b519126e 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt @@ -115,12 +115,12 @@ fun KpmScreen( viewModel.fetchModuleList() snackBarHost.showSnackbar( message = kpmInstallSuccess, - duration = SnackbarDuration.Long + duration = SnackbarDuration.Short ) } else { snackBarHost.showSnackbar( message = kpmInstallFailed, - duration = SnackbarDuration.Long + duration = SnackbarDuration.Short ) } } @@ -250,12 +250,12 @@ fun KpmScreen( viewModel.fetchModuleList() snackBarHost.showSnackbar( message = kpmUninstallSuccess, - duration = SnackbarDuration.Long + duration = SnackbarDuration.Short ) } else { snackBarHost.showSnackbar( message = kpmUninstallFailed, - duration = SnackbarDuration.Long + duration = SnackbarDuration.Short ) } } From af813080977826b0c12eb1430e24c095659d7c0b Mon Sep 17 00:00:00 2001 From: liankong Date: Tue, 1 Apr 2025 15:53:58 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=B8=8D=E5=88=B0=E5=AE=8C=E6=95=B4=E4=BF=A1=E6=81=AF=E7=9A=84?= =?UTF-8?q?bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manager/app/build.gradle.kts | 8 ++++++++ .../java/shirkneko/zako/sukisu/ui/util/KsuCli.kt | 14 +++++++++++--- .../zako/sukisu/ui/viewmodel/KpmViewModel.kt | 3 ++- manager/app/src/main/res/values/strings.xml | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/manager/app/build.gradle.kts b/manager/app/build.gradle.kts index 820d3c41..67ee6ba6 100644 --- a/manager/app/build.gradle.kts +++ b/manager/app/build.gradle.kts @@ -25,6 +25,14 @@ apksign { } android { + signingConfigs { + getByName("debug") { + storeFile = file("D:\\SukiSU\\release-key.keystore") + storePassword = "2832165" + keyAlias = "shirkneko" + keyPassword = "2832165" + } + } namespace = "shirkneko.zako.sukisu" buildTypes { diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt index d6374e78..9cd8bd29 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/util/KsuCli.kt @@ -507,11 +507,19 @@ fun getKpmModuleCount(): Int { return result.trim().toIntOrNull() ?: 0 } +fun runCmd(shell : Shell, cmd : String) : String { + return shell.newJob() + .add(cmd) + .to(mutableListOf(), null) + .exec().out + .joinToString("\n") +} + fun listKpmModules(): String { val shell = getRootShell() val cmd = "${getKpmmgrPath()} list" return try { - ShellUtils.fastCmd(shell, cmd).trim() + runCmd(shell, cmd).trim() } catch (e: Exception) { Log.e(TAG, "Failed to list KPM modules", e) "" @@ -522,7 +530,7 @@ fun getKpmModuleInfo(name: String): String { val shell = getRootShell() val cmd = "${getKpmmgrPath()} info $name" return try { - ShellUtils.fastCmd(shell, cmd).trim() + runCmd(shell, cmd).trim() } catch (e: Exception) { Log.e(TAG, "Failed to get KPM module info: $name", e) "" @@ -532,7 +540,7 @@ fun getKpmModuleInfo(name: String): String { fun controlKpmModule(name: String, args: String? = null): Int { val shell = getRootShell() val cmd = "${getKpmmgrPath()} control $name ${args ?: ""}" - val result = ShellUtils.fastCmd(shell, cmd) + val result = runCmd(shell, cmd) return result.trim().toIntOrNull() ?: -1 } diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt index e72c2a14..6d7c21c6 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt @@ -48,7 +48,8 @@ class KpmViewModel : ViewModel() { private fun getAllKpmModuleInfo(): List { val result = mutableListOf() try { - val moduleNames = listKpmModules() + val str = listKpmModules() + val moduleNames = str .split("\n") .filter { it.isNotBlank() } diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index c24c465c..ce799975 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -237,7 +237,7 @@ Load of kpm module successful Load of kpm module failed kpm parameters - kpm control + 执行 KPM Version close The following kernel module functions were developed by KernelPatch and modified to include the kernel module functions of SukiSU Ultra From 08fdf2bdada046fbf926703ac93431474fe1a85c Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 1 Apr 2025 15:56:30 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E4=B8=BAKPM=E6=A8=A1=E5=9D=97=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=8E=A7=E5=88=B6=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E6=93=8D=E4=BD=9C=E6=88=90=E5=8A=9F=E6=88=96=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E7=9A=84Snackbar=E6=8F=90=E7=A4=BA=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A8=A1=E5=9D=97=E4=BF=A1=E6=81=AF=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shirkneko/zako/sukisu/ui/screen/kpm.kt | 24 +++++++++++++++++-- .../zako/sukisu/ui/viewmodel/KpmViewModel.kt | 20 +++++++++++----- manager/app/src/main/res/values/strings.xml | 2 ++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt index b519126e..30dc79eb 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt @@ -6,6 +6,8 @@ import android.content.Intent import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.SpringSpec import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -13,6 +15,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.* import androidx.compose.material3.* import androidx.compose.material3.pulltorefresh.PullToRefreshBox +import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -206,7 +209,7 @@ fun KpmScreen( PullToRefreshBox( onRefresh = { viewModel.fetchModuleList() }, isRefreshing = viewModel.isRefreshing, - modifier = Modifier + modifier = Modifier, ) { if (viewModel.moduleList.isEmpty()) { Box( @@ -279,6 +282,13 @@ private fun KpmModuleItem( onUninstall: () -> Unit, onControl: () -> Unit ) { + val viewModel: KpmViewModel = viewModel() + val scope = rememberCoroutineScope() + val snackBarHost = remember { SnackbarHostState() } + + val successMessage = stringResource(R.string.kpm_control_success) + val failureMessage = stringResource(R.string.kpm_control_failed) + ElevatedCard( colors = getCardColors(MaterialTheme.colorScheme.secondaryContainer), elevation = CardDefaults.cardElevation(defaultElevation = getCardElevation()) @@ -325,7 +335,17 @@ private fun KpmModuleItem( horizontalArrangement = Arrangement.spacedBy(8.dp) ) { FilledTonalButton( - onClick = onControl, + onClick = { + scope.launch { + val result = viewModel.controlModule(module.id, module.args) + val message = when (result) { + 0 -> successMessage + else -> failureMessage + } + snackBarHost.showSnackbar(message) + onControl() + } + }, enabled = module.hasAction ) { Icon( diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt index e72c2a14..d2641bbb 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/viewmodel/KpmViewModel.kt @@ -24,7 +24,6 @@ class KpmViewModel : ViewModel() { var currentModuleDetail by mutableStateOf("") private set - fun fetchModuleList() { viewModelScope.launch { isRefreshing = true @@ -70,7 +69,7 @@ class KpmViewModel : ViewModel() { val info = getKpmModuleInfo(name) if (info.isBlank()) return null - val properties = info.lineSequence() // 使用序列提升大文本性能 + val properties = info.lineSequence() .filter { line -> val trimmed = line.trim() trimmed.isNotEmpty() && !trimmed.startsWith("#") @@ -80,7 +79,7 @@ class KpmViewModel : ViewModel() { when (parts.size) { 2 -> parts[0].trim() to parts[1].trim() 1 -> parts[0].trim() to "" - else -> null // 忽略无效行 + else -> null } } } @@ -89,8 +88,8 @@ class KpmViewModel : ViewModel() { return ModuleInfo( id = name, name = properties["name"] ?: name, - version = properties["version"] ?: "unknown", - author = properties["author"] ?: "unknown", + version = properties["version"] ?: "", + author = properties["author"] ?: "", description = properties["description"] ?: "", args = properties["args"] ?: "", enabled = true, @@ -111,7 +110,16 @@ class KpmViewModel : ViewModel() { } } } - + fun controlModule(moduleId: String, args: String? = null): Int { + return try { + val result = controlKpmModule(moduleId, args) + Log.d("KsuCli", "Control module $moduleId result: $result") + result + } catch (e: Exception) { + Log.e("KsuCli", "Failed to control module $moduleId", e) + -1 + } + } data class ModuleInfo( val id: String, diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index c24c465c..2993f314 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -242,5 +242,7 @@ close The following kernel module functions were developed by KernelPatch and modified to include the kernel module functions of SukiSU Ultra SukiSU Ultra Look forward to + success + failed SukiSU Ultra will be a relatively independent branch of KSU in the future, but thanks to the official KernelSU and MKSU etc. for their contributions! From 57c65fdcdad9ccfeb551571b2c452cb6760d639e Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 1 Apr 2025 16:09:18 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E7=AD=BE=E5=90=8D=E9=85=8D=E7=BD=AE=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?KPM=E7=89=88=E6=9C=AC=E6=98=BE=E7=A4=BA=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0KPM=E6=8E=A7=E5=88=B6=E6=88=90?= =?UTF-8?q?=E5=8A=9F=E5=92=8C=E5=A4=B1=E8=B4=A5=E7=9A=84=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manager/app/build.gradle.kts | 8 -------- .../java/shirkneko/zako/sukisu/ui/screen/Home.kt | 14 ++++++++++++-- manager/app/src/main/res/values-zh-rCN/strings.xml | 2 ++ manager/app/src/main/res/values/strings.xml | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/manager/app/build.gradle.kts b/manager/app/build.gradle.kts index 67ee6ba6..820d3c41 100644 --- a/manager/app/build.gradle.kts +++ b/manager/app/build.gradle.kts @@ -25,14 +25,6 @@ apksign { } android { - signingConfigs { - getByName("debug") { - storeFile = file("D:\\SukiSU\\release-key.keystore") - storePassword = "2832165" - keyAlias = "shirkneko" - keyPassword = "2832165" - } - } namespace = "shirkneko.zako.sukisu" buildTypes { diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/Home.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/Home.kt index 364c2584..a6fc7fc0 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/Home.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/Home.kt @@ -549,8 +549,18 @@ private fun InfoCard() { if (!isSimpleMode) { - Spacer(Modifier.height(16.dp)) - InfoCardItem(stringResource(R.string.home_kpm_version), getKpmVersion()) + var showKpmVersion by remember { mutableStateOf(true) } + LaunchedEffect(Unit) { + try { + getKpmVersion() + } catch (e: Exception) { + showKpmVersion = false + } + } + AnimatedVisibility(visible = showKpmVersion) { + Spacer(Modifier.height(16.dp)) + InfoCardItem(stringResource(R.string.home_kpm_version), getKpmVersion()) + } } 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 08e3f5be..217aae2c 100644 --- a/manager/app/src/main/res/values-zh-rCN/strings.xml +++ b/manager/app/src/main/res/values-zh-rCN/strings.xml @@ -236,6 +236,8 @@ 加载kpm模块失败 KPM 版本 关闭 + 成功 + 错误 以下内核模块功能由KernelPatch开发,经过修改后加入SukiSU Ultra的内核模块功能 SukiSU Ultra展望 SukiSU Ultra未来将会成为一个相对独立的KSU分支,但是依然感谢官方KernelSU和MKSU等做出的贡献 diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index 86c90dae..dbeb0674 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -237,7 +237,7 @@ Load of kpm module successful Load of kpm module failed kpm parameters - 执行 + fulfillment KPM Version close The following kernel module functions were developed by KernelPatch and modified to include the kernel module functions of SukiSU Ultra From f71de1742a564cc90cbc83a373d9f746865c6c36 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 1 Apr 2025 16:16:56 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E4=BC=98=E5=8C=96KPM=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=9A=84=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=AE=9A=E6=97=B6=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=B9=B6=E8=B0=83=E6=95=B4=E7=A9=BA?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shirkneko/zako/sukisu/ui/screen/kpm.kt | 121 ++++++++---------- 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt index 30dc79eb..3d8574da 100644 --- a/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt +++ b/manager/app/src/main/java/shirkneko/zako/sukisu/ui/screen/kpm.kt @@ -1,5 +1,3 @@ -package shirkneko.zako.sukisu.ui.screen - import android.app.Activity.RESULT_OK import android.content.Context import android.content.Intent @@ -14,8 +12,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.* import androidx.compose.material3.* -import androidx.compose.material3.pulltorefresh.PullToRefreshBox -import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -27,6 +23,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import shirkneko.zako.sukisu.R import shirkneko.zako.sukisu.ui.component.ConfirmResult @@ -42,7 +39,6 @@ import java.io.File import androidx.core.content.edit import shirkneko.zako.sukisu.ui.theme.ThemeConfig - /** * KPM 管理界面 * 以下内核模块功能由KernelPatch开发,经过修改后加入SukiSU Ultra的内核模块功能 @@ -132,8 +128,9 @@ fun KpmScreen( } LaunchedEffect(Unit) { - if (viewModel.moduleList.isEmpty()) { + while(true) { viewModel.fetchModuleList() + delay(5000) } } @@ -206,69 +203,63 @@ fun KpmScreen( } } - PullToRefreshBox( - onRefresh = { viewModel.fetchModuleList() }, - isRefreshing = viewModel.isRefreshing, - modifier = Modifier, - ) { - if (viewModel.moduleList.isEmpty()) { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - Text( - stringResource(R.string.kpm_empty), - textAlign = TextAlign.Center - ) - } - } else { - LazyColumn( - modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - items(viewModel.moduleList) { module -> - val kpmUninstallConfirm = String.format(kpmUninstallConfirmTemplate, module.name) - KpmModuleItem( - module = module, - onUninstall = { - scope.launch { - val confirmResult = confirmDialog.awaitConfirm( - title = kpmUninstall, - content = kpmUninstallConfirm, - confirm = uninstall, - dismiss = cancel - ) - if (confirmResult == ConfirmResult.Confirmed) { - val success = loadingDialog.withLoading { - try { - unloadKpmModule(module.id) - true - } catch (e: Exception) { - Log.e("KsuCli", "Failed to unload KPM module: ${e.message}") - false - } - } - if (success) { - viewModel.fetchModuleList() - snackBarHost.showSnackbar( - message = kpmUninstallSuccess, - duration = SnackbarDuration.Short - ) - } else { - snackBarHost.showSnackbar( - message = kpmUninstallFailed, - duration = SnackbarDuration.Short - ) + if (viewModel.moduleList.isEmpty()) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text( + stringResource(R.string.kpm_empty), + textAlign = TextAlign.Center + ) + } + } else { + LazyColumn( + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + items(viewModel.moduleList) { module -> + val kpmUninstallConfirm = String.format(kpmUninstallConfirmTemplate, module.name) + KpmModuleItem( + module = module, + onUninstall = { + scope.launch { + val confirmResult = confirmDialog.awaitConfirm( + title = kpmUninstall, + content = kpmUninstallConfirm, + confirm = uninstall, + dismiss = cancel + ) + if (confirmResult == ConfirmResult.Confirmed) { + val success = loadingDialog.withLoading { + try { + unloadKpmModule(module.id) + true + } catch (e: Exception) { + Log.e("KsuCli", "Failed to unload KPM module: ${e.message}") + false } } + if (success) { + viewModel.fetchModuleList() + snackBarHost.showSnackbar( + message = kpmUninstallSuccess, + duration = SnackbarDuration.Short + ) + } else { + snackBarHost.showSnackbar( + message = kpmUninstallFailed, + duration = SnackbarDuration.Short + ) + } } - }, - onControl = { - viewModel.loadModuleDetail(module.id) } - ) - } + }, + onControl = { + viewModel.loadModuleDetail(module.id) + } + ) } } }