From e8852223c4459cb158b10287dbf6d6d751df7a64 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Wed, 10 Sep 2025 22:05:30 +0800 Subject: [PATCH] manager: Optimize the overall layout of KPM patches --- .../com/sukisu/ultra/ui/screen/Install.kt | 281 +++++++++--------- .../zako/zako/zakoui/flash/KernelFlash.kt | 10 +- .../src/main/res/values-zh-rCN/strings.xml | 47 +-- manager/app/src/main/res/values/strings.xml | 7 +- 4 files changed, 174 insertions(+), 171 deletions(-) diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt index 7c37ec3f..9f4fb7ce 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt @@ -13,7 +13,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.selection.toggleable +import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack @@ -61,14 +61,20 @@ import com.sukisu.ultra.ui.util.* * @author ShirkNeko * @date 2025/5/31. */ + +enum class KpmPatchOption { + FOLLOW_KERNEL, + PATCH_KPM, + UNDO_PATCH_KPM +} + @OptIn(ExperimentalMaterial3Api::class) @Destination @Composable fun InstallScreen(navigator: DestinationsNavigator) { var installMethod by remember { mutableStateOf(null) } var lkmSelection by remember { mutableStateOf(LkmSelection.KmiNone) } - var kpmPatchEnabled by remember { mutableStateOf(false) } - var kpmUndoPatch by remember { mutableStateOf(false) } + var kpmPatchOption by remember { mutableStateOf(KpmPatchOption.FOLLOW_KERNEL) } val context = LocalContext.current var showRebootDialog by remember { mutableStateOf(false) } var showSlotSelectionDialog by remember { mutableStateOf(false) } @@ -106,8 +112,8 @@ fun InstallScreen(navigator: DestinationsNavigator) { KernelFlashScreenDestination( kernelUri = uri, selectedSlot = method.slot, - kpmPatchEnabled = kpmPatchEnabled, - kpmUndoPatch = kpmUndoPatch + kpmPatchEnabled = kpmPatchOption == KpmPatchOption.PATCH_KPM, + kpmUndoPatch = kpmPatchOption == KpmPatchOption.UNDO_PATCH_KPM ) ) } @@ -193,10 +199,8 @@ fun InstallScreen(navigator: DestinationsNavigator) { installMethod = method } }, - kpmPatchEnabled = kpmPatchEnabled, - onKpmPatchChanged = { kpmPatchEnabled = it }, - kpmUndoPatch = kpmUndoPatch, - onKpmUndoPatchChanged = { kpmUndoPatch = it }, + kpmPatchOption = kpmPatchOption, + onKpmPatchOptionChanged = { kpmPatchOption = it }, selectedMethod = installMethod ) @@ -258,7 +262,7 @@ fun InstallScreen(navigator: DestinationsNavigator) { } // KPM 状态显示卡片 - if (kpmPatchEnabled || kpmUndoPatch) { + if (kpmPatchOption != KpmPatchOption.FOLLOW_KERNEL) { ElevatedCard( colors = getCardColors(MaterialTheme.colorScheme.surfaceVariant), elevation = getCardElevation(), @@ -273,13 +277,18 @@ fun InstallScreen(navigator: DestinationsNavigator) { ) ) { Text( - text = stringResource( - if (kpmUndoPatch) R.string.kpm_undo_patch_enabled - else R.string.kpm_patch_enabled - ), + text = when (kpmPatchOption) { + KpmPatchOption.PATCH_KPM -> stringResource(R.string.kpm_patch_enabled) + KpmPatchOption.UNDO_PATCH_KPM -> stringResource(R.string.kpm_undo_patch_enabled) + else -> "" + }, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.padding(16.dp), - color = MaterialTheme.colorScheme.primary + color = when (kpmPatchOption) { + KpmPatchOption.PATCH_KPM -> MaterialTheme.colorScheme.primary + KpmPatchOption.UNDO_PATCH_KPM -> MaterialTheme.colorScheme.tertiary + else -> MaterialTheme.colorScheme.onSurface + } ) } } @@ -364,10 +373,8 @@ sealed class InstallMethod { private fun SelectInstallMethod( isGKI: Boolean = false, onSelected: (InstallMethod) -> Unit = {}, - kpmPatchEnabled: Boolean = false, - onKpmPatchChanged: (Boolean) -> Unit = {}, - kpmUndoPatch: Boolean = false, - onKpmUndoPatchChanged: (Boolean) -> Unit = {}, + kpmPatchOption: KpmPatchOption = KpmPatchOption.FOLLOW_KERNEL, + onKpmPatchOptionChanged: (KpmPatchOption) -> Unit = {}, selectedMethod: InstallMethod? = null ) { val rootAvailable = rootAvailable() @@ -528,9 +535,9 @@ private fun SelectInstallMethod( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .toggleable( - value = option.javaClass == selectedOption?.javaClass, - onValueChange = { onClick(option) }, + .selectable( + selected = option.javaClass == selectedOption?.javaClass, + onClick = { onClick(option) }, role = Role.RadioButton, indication = LocalIndication.current, interactionSource = interactionSource @@ -578,7 +585,7 @@ private fun SelectInstallMethod( elevation = getCardElevation(), modifier = Modifier .fillMaxWidth() - .padding(bottom = if (selectedMethod is InstallMethod.HorizonKernel) 0.dp else 12.dp) + .padding(bottom = 12.dp) .clip(MaterialTheme.shapes.large) ) { MaterialTheme( @@ -635,9 +642,9 @@ private fun SelectInstallMethod( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .toggleable( - value = option.javaClass == selectedOption?.javaClass, - onValueChange = { onClick(option) }, + .selectable( + selected = option.javaClass == selectedOption?.javaClass, + onClick = { onClick(option) }, role = Role.RadioButton, indication = LocalIndication.current, interactionSource = interactionSource @@ -673,136 +680,126 @@ private fun SelectInstallMethod( } } } - } - } - } - // KPM 修补选项卡片 - if (selectedMethod is InstallMethod.HorizonKernel && selectedMethod.uri != null) { - ElevatedCard( - colors = getCardColors(MaterialTheme.colorScheme.surfaceVariant), - elevation = getCardElevation(), - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 12.dp) - .clip(MaterialTheme.shapes.large) - ) { - MaterialTheme( - colorScheme = MaterialTheme.colorScheme.copy( - surface = if (CardConfig.isCustomBackgroundEnabled) Color.Transparent else MaterialTheme.colorScheme.surfaceVariant - ) - ) { - ListItem( - leadingContent = { + // KPM修补 + if (selectedMethod is InstallMethod.HorizonKernel && selectedMethod.uri != null) { + Spacer(modifier = Modifier.height(16.dp)) + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp) + ) { Icon( Icons.Filled.Security, contentDescription = null, - tint = MaterialTheme.colorScheme.tertiary + tint = MaterialTheme.colorScheme.tertiary, + modifier = Modifier.size(20.dp) ) - }, - headlineContent = { + Spacer(modifier = Modifier.width(8.dp)) Text( stringResource(R.string.kpm_patch_options), - style = MaterialTheme.typography.titleMedium - ) - }, - supportingContent = { - Text( - stringResource(R.string.kpm_patch_description), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.tertiary ) } - ) - } - Column( - modifier = Modifier.padding( - start = 16.dp, - end = 16.dp, - bottom = 16.dp - ) - ) { - // KPM 修补开关 - Row( - modifier = Modifier - .fillMaxWidth() - .clip(MaterialTheme.shapes.medium) - .clickable { - if (!kpmPatchEnabled) { - onKpmPatchChanged(true) - if (kpmUndoPatch) onKpmUndoPatchChanged(false) - } else { - onKpmPatchChanged(false) - } - } - .padding(vertical = 12.dp, horizontal = 8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Switch( - checked = kpmPatchEnabled, - onCheckedChange = { enabled -> - onKpmPatchChanged(enabled) - if (enabled && kpmUndoPatch) onKpmUndoPatchChanged(false) - }, - colors = SwitchDefaults.colors( - checkedThumbColor = MaterialTheme.colorScheme.primary, - checkedTrackColor = MaterialTheme.colorScheme.primaryContainer - ) + Text( + stringResource(R.string.kpm_patch_description), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(bottom = 12.dp) + ) + + KpmPatchOptionGroup( + selectedOption = kpmPatchOption, + onOptionChanged = onKpmPatchOptionChanged ) - Spacer(modifier = Modifier.width(12.dp)) - Column(modifier = Modifier.weight(1f)) { - Text( - text = stringResource(R.string.enable_kpm_patch), - style = MaterialTheme.typography.bodyLarge - ) - Text( - text = stringResource(R.string.kpm_patch_switch_description), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } } + } + } + } + } + } +} - // KPM 撤销修补开关 - Row( - modifier = Modifier - .fillMaxWidth() - .clip(MaterialTheme.shapes.medium) - .clickable { - if (!kpmUndoPatch) { - onKpmUndoPatchChanged(true) - if (kpmPatchEnabled) onKpmPatchChanged(false) - } else { - onKpmUndoPatchChanged(false) - } - } - .padding(vertical = 12.dp, horizontal = 8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Switch( - checked = kpmUndoPatch, - onCheckedChange = { enabled -> - onKpmUndoPatchChanged(enabled) - if (enabled && kpmPatchEnabled) onKpmPatchChanged(false) - }, - colors = SwitchDefaults.colors( - checkedThumbColor = MaterialTheme.colorScheme.tertiary, - checkedTrackColor = MaterialTheme.colorScheme.tertiaryContainer - ) +@Composable +private fun KpmPatchOptionGroup( + selectedOption: KpmPatchOption, + onOptionChanged: (KpmPatchOption) -> Unit +) { + val options = listOf( + KpmPatchOption.FOLLOW_KERNEL to stringResource(R.string.kpm_follow_kernel_file), + KpmPatchOption.PATCH_KPM to stringResource(R.string.enable_kpm_patch), + KpmPatchOption.UNDO_PATCH_KPM to stringResource(R.string.enable_kpm_undo_patch) + ) + + val descriptions = mapOf( + KpmPatchOption.FOLLOW_KERNEL to stringResource(R.string.kpm_follow_kernel_description), + KpmPatchOption.PATCH_KPM to stringResource(R.string.kpm_patch_switch_description), + KpmPatchOption.UNDO_PATCH_KPM to stringResource(R.string.kpm_undo_patch_switch_description) + ) + + Column { + options.forEach { (option, label) -> + val interactionSource = remember { MutableInteractionSource() } + Surface( + color = if (option == selectedOption) + MaterialTheme.colorScheme.primaryContainer.copy(alpha = cardAlpha) + else + MaterialTheme.colorScheme.surfaceContainer.copy(alpha = cardAlpha), + shape = MaterialTheme.shapes.medium, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 2.dp) + .clip(MaterialTheme.shapes.medium) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .selectable( + selected = option == selectedOption, + onClick = { onOptionChanged(option) }, + role = Role.RadioButton, + indication = LocalIndication.current, + interactionSource = interactionSource + ) + .padding(vertical = 12.dp, horizontal = 12.dp) + ) { + RadioButton( + selected = option == selectedOption, + onClick = null, + interactionSource = interactionSource, + colors = RadioButtonDefaults.colors( + selectedColor = when (option) { + KpmPatchOption.FOLLOW_KERNEL -> MaterialTheme.colorScheme.primary + KpmPatchOption.PATCH_KPM -> MaterialTheme.colorScheme.primary + KpmPatchOption.UNDO_PATCH_KPM -> MaterialTheme.colorScheme.tertiary + }, + unselectedColor = MaterialTheme.colorScheme.onSurfaceVariant + ) + ) + Spacer(modifier = Modifier.width(12.dp)) + Column(modifier = Modifier.weight(1f)) { + Text( + text = label, + style = MaterialTheme.typography.bodyLarge, + color = if (option == selectedOption) + MaterialTheme.colorScheme.onPrimaryContainer + else + MaterialTheme.colorScheme.onSurface + ) + descriptions[option]?.let { description -> + Text( + text = description, + style = MaterialTheme.typography.bodySmall, + color = if (option == selectedOption) + MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.7f) + else + MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 2.dp) ) - Spacer(modifier = Modifier.width(12.dp)) - Column(modifier = Modifier.weight(1f)) { - Text( - text = stringResource(R.string.enable_kpm_undo_patch), - style = MaterialTheme.typography.bodyLarge - ) - Text( - text = stringResource(R.string.kpm_undo_patch_switch_description), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } } } } diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt index c81dbc96..0ff75ad7 100644 --- a/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt +++ b/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt @@ -286,7 +286,7 @@ class HorizonKernelWorker( } /** - * 执行KMP修补操作 + * 执行KPM修补操作 */ private fun performKpmPatch() { try { @@ -311,11 +311,11 @@ class HorizonKernelWorker( state.addLog(context.getString(R.string.kpm_found_image_file, imageFile)) - // 复制KMP工具到Image文件所在目录 + // 复制KPM工具到Image文件所在目录 runCommand(true, "cp $workDir/kptools $imageDir/") runCommand(true, "cp $workDir/kpimg $imageDir/") - // 执行KMP修补命令 + // 执行KPM修补命令 val patchCommand = if (kpmUndoPatch) { "cd $imageDir && chmod a+rx kptools && ./kptools -u -s 123 -i Image -k kpimg -o oImage && mv oImage Image" } else { @@ -335,10 +335,10 @@ class HorizonKernelWorker( else context.getString(R.string.kpm_patch_success) ) - // 清理KMP工具文件 + // 清理KPM工具文件 runCommand(true, "rm -f $imageDir/kptools $imageDir/kpimg $imageDir/oImage") - // 使用Java方式重新打包ZIP文件 + // 重新打包ZIP文件 val originalFileName = File(filePath).name val patchedFilePath = "$workDir/patched_$originalFileName" 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 6dd8762d..aa34e889 100644 --- a/manager/app/src/main/res/values-zh-rCN/strings.xml +++ b/manager/app/src/main/res/values-zh-rCN/strings.xml @@ -621,33 +621,36 @@ 未经签名的模块可能不完整。你想安装来自未知发布者的模块吗? 钩子类型 - KPM修补 - 用于添加附加的KPM功能 - KPM修补 + KPM 修补 + 用于添加附加的 KPM 功能 + KPM 修补 在刷写前对内核镜像进行KPM修补 - KPM撤销修补 + KPM 撤销修补 撤销之前应用的KPM修补 - KPM修补已启用 - KPM撤销修补已启用 - KPM修补模式 - KPM撤销修补模式 + KPM 修补已启用 + KPM 撤销修补已启用 + KPM 修补模式 + KPM 撤销修补模式 - 准备KPM修补工具 - 正在应用KPM修补 - 正在撤销KPM修补 - KPM工具准备完成 - 找到Image文件: %s - KPM修补成功 - KPM撤销修补成功 + 准备 KPM 修补工具 + 正在应用 KPM 修补 + 正在撤销 KPM 修补 + KPM 工具准备完成 + 找到 Image 文件: %s + KPM 修补成功 + KPM 撤销修补成功 文件重新打包完成 - 提取kptools工具失败 - 提取kpimg文件失败 - 准备KPM工具失败: %s + 提取 kptools 工具失败 + 提取 kpimg 文件失败 + 准备 KPM 工具失败: %s 解压压缩包失败 - 未找到Image文件 - KPM修补失败 - KPM撤销修补失败 + 未找到 Image 文件 + KPM 修补失败 + KPM 撤销修补失败 重新打包压缩文件失败 - KPM修补操作失败: %s + KPM 修补操作失败: %s + + 跟随内核 + 原样使用内核,不进行任何 KPM 修改 diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index f8cf97e4..e06284eb 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -488,7 +488,7 @@ Kstat full clone updated: %1$s Add Kstat Static Configuration File/Directory Path - Hint: You can use ”default“ to use the original value + Hint: You can use "default" to use the original value Add Kstat Path Add Reset Kstat Configuration @@ -658,4 +658,7 @@ Important Note:\n KPM undo patch failed Failed to repack zip file KPM patch operation failed: %s - + + Follow Kernel + Use kernel as-is without any KPM modifications + \ No newline at end of file