diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt index 7f76e79e..23562612 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt @@ -113,6 +113,9 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { // 添加状态跟踪是否已经完成刷写 var hasFlashCompleted by rememberSaveable { mutableStateOf(false) } var hasExecuted by rememberSaveable { mutableStateOf(false) } + // 更新模块状态管理 + var hasUpdateExecuted by rememberSaveable { mutableStateOf(false) } + var hasUpdateCompleted by rememberSaveable { mutableStateOf(false) } val snackBarHost = LocalSnackbarHost.current val scope = rememberCoroutineScope() @@ -130,21 +133,76 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { // 重置状态 LaunchedEffect(flashIt) { - if (flashIt is FlashIt.FlashModules && flashIt.currentIndex == 0) { - moduleInstallStatus.value = ModuleInstallStatus( - totalModules = flashIt.uris.size, - currentModule = 1 - ) - hasFlashCompleted = false - hasExecuted = false - } else if (flashIt !is FlashIt.FlashModules) { - hasFlashCompleted = false - hasExecuted = false + when (flashIt) { + is FlashIt.FlashModules -> { + if (flashIt.currentIndex == 0) { + moduleInstallStatus.value = ModuleInstallStatus( + totalModules = flashIt.uris.size, + currentModule = 1 + ) + hasFlashCompleted = false + hasExecuted = false + } + } + is FlashIt.FlashModuleUpdate -> { + hasUpdateCompleted = false + hasUpdateExecuted = false + } + else -> { + hasFlashCompleted = false + hasExecuted = false + } } } - // 只有在未完成刷写时才执行刷写操作 + // 处理更新模块安装 LaunchedEffect(flashIt) { + if (flashIt !is FlashIt.FlashModuleUpdate) return@LaunchedEffect + if (hasUpdateExecuted || hasUpdateCompleted || text.isNotEmpty()) { + return@LaunchedEffect + } + + hasUpdateExecuted = true + + withContext(Dispatchers.IO) { + setFlashingStatus(FlashingStatus.FLASHING) + + try { + logContent.append(text).append("\n") + } catch (_: Exception) { + logContent.append(text).append("\n") + } + + flashModuleUpdate(flashIt.uri, onFinish = { showReboot, code -> + if (code != 0) { + text += "$errorCodeString $code.\n$checkLogString\n" + setFlashingStatus(FlashingStatus.FAILED) + } else { + setFlashingStatus(FlashingStatus.SUCCESS) + viewModel.markNeedRefresh() + } + if (showReboot) { + text += "\n\n\n" + showFloatAction = true + } + hasUpdateCompleted = true + }, onStdout = { + tempText = "$it\n" + if (tempText.startsWith("")) { // clear command + text = tempText.substring(6) + } else { + text += tempText + } + logContent.append(it).append("\n") + }, onStderr = { + logContent.append(it).append("\n") + }) + } + } + + // 安装但排除更新模块 + LaunchedEffect(flashIt) { + if (flashIt is FlashIt.FlashModuleUpdate) return@LaunchedEffect if (hasExecuted || hasFlashCompleted || text.isNotEmpty()) { return@LaunchedEffect } @@ -214,8 +272,13 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { } val onBack: () -> Unit = { - if (currentFlashingStatus.value != FlashingStatus.FLASHING) { - if (flashIt is FlashIt.FlashModules) { + val canGoBack = when (flashIt) { + is FlashIt.FlashModuleUpdate -> currentFlashingStatus.value != FlashingStatus.FLASHING + else -> currentFlashingStatus.value != FlashingStatus.FLASHING + } + + if (canGoBack) { + if (flashIt is FlashIt.FlashModules || flashIt is FlashIt.FlashModuleUpdate) { viewModel.markNeedRefresh() viewModel.fetchModuleList() navigator.navigate(ModuleScreenDestination) @@ -364,7 +427,7 @@ fun ModuleInstallProgressBar( horizontalArrangement = Arrangement.SpaceBetween ) { Text( - text = if (currentModuleName.isNotEmpty()) currentModuleName else stringResource(R.string.module), + text = currentModuleName.ifEmpty { stringResource(R.string.module) }, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) @@ -536,10 +599,21 @@ sealed class FlashIt : Parcelable { data class FlashBoot(val boot: Uri? = null, val lkm: LkmSelection, val ota: Boolean) : FlashIt() data class FlashModule(val uri: Uri) : FlashIt() data class FlashModules(val uris: List, val currentIndex: Int = 0) : FlashIt() + data class FlashModuleUpdate(val uri: Uri) : FlashIt() // 模块更新 data object FlashRestore : FlashIt() data object FlashUninstall : FlashIt() } +// 模块更新刷写 +fun flashModuleUpdate( + uri: Uri, + onFinish: (Boolean, Int) -> Unit, + onStdout: (String) -> Unit, + onStderr: (String) -> Unit +) { + flashModule(uri, onFinish, onStdout, onStderr) +} + fun flashIt( flashIt: FlashIt, onFinish: (Boolean, Int) -> Unit, @@ -567,6 +641,9 @@ fun flashIt( flashModule(currentUri, onFinish, onStdout, onStderr) } + is FlashIt.FlashModuleUpdate -> { + onFinish(false, 0) + } FlashIt.FlashRestore -> restoreBoot(onFinish, onStdout, onStderr) FlashIt.FlashUninstall -> uninstallPermanently(onFinish, onStdout, onStderr) } diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt index 7dd25922..72709e38 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt @@ -352,6 +352,9 @@ fun ModuleScreen(navigator: DestinationsNavigator) { onInstallModule = { navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it))) }, + onUpdateModule = { + navigator.navigate(FlashScreenDestination(FlashIt.FlashModuleUpdate(it))) + }, onClickModule = { id, name, hasWebUi -> val currentTime = System.currentTimeMillis() if (currentTime - lastClickTime < 600) { @@ -622,6 +625,7 @@ private fun ModuleList( modifier: Modifier = Modifier, boxModifier: Modifier = Modifier, onInstallModule: (Uri) -> Unit, + onUpdateModule: (Uri) -> Unit, onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit, context: Context, snackBarHost: SnackbarHostState @@ -709,7 +713,7 @@ private fun ModuleList( downloadUrl, fileName, downloading, - onDownloaded = onInstallModule, + onDownloaded = onUpdateModule, onDownloading = { launch(Dispatchers.Main) { Toast.makeText(context, downloading, Toast.LENGTH_SHORT).show()