From 8064472477ccb072e9c8306fc837f7943dadf3b9 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Sat, 31 May 2025 03:03:22 +0800 Subject: [PATCH] manager: better handle webui engine select - Optimize the flashback problem caused by null pointer Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Co-authored-by: Der_Googler <54764558+DerGoogler@users.noreply.github.com> Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> --- .../java/com/sukisu/ultra/ui/screen/Module.kt | 62 ++++++++++++++----- .../ultra/ui/viewmodel/ModuleViewModel.kt | 37 +++++++++++ 2 files changed, 82 insertions(+), 17 deletions(-) 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 ff2a8ad0..04e5f2d3 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 @@ -72,6 +72,8 @@ import com.sukisu.ultra.ui.theme.CardConfig.cardElevation import com.sukisu.ultra.ui.webui.WebUIXActivity import com.dergoogler.mmrl.platform.Platform import androidx.core.net.toUri +import com.dergoogler.mmrl.platform.model.ModuleConfig +import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig @OptIn(ExperimentalMaterial3Api::class) @@ -83,6 +85,7 @@ fun ModuleScreen(navigator: DestinationsNavigator) { val snackBarHost = LocalSnackbarHost.current val scope = rememberCoroutineScope() val confirmDialog = rememberConfirmDialog() + var lastClickTime by remember { mutableStateOf(0L) } val selectZipLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult() @@ -142,7 +145,7 @@ fun ModuleScreen(navigator: DestinationsNavigator) { } } else { val uri = data.data ?: return@launch - // 单个安装模块 + // 单个安装模块 try { if (!ModuleUtils.isUriAccessible(context, uri)) { snackBarHost.showSnackbar("Unable to access selected module files") @@ -371,24 +374,48 @@ fun ModuleScreen(navigator: DestinationsNavigator) { navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it))) }, onClickModule = { id, name, hasWebUi -> + val currentTime = System.currentTimeMillis() + if (currentTime - lastClickTime < 600) { + Log.d("ModuleScreen", "Click too fast, ignoring") + return@ModuleList + } + lastClickTime = currentTime + if (hasWebUi) { - val wxEngine = Intent(context, WebUIXActivity::class.java) - .setData("kernelsu://webuix/$id".toUri()) - .putExtra("id", id) - .putExtra("name", name) + try { + val wxEngine = Intent(context, WebUIXActivity::class.java) + .setData("kernelsu://webuix/$id".toUri()) + .putExtra("id", id) + .putExtra("name", name) - val ksuEngine = Intent(context, WebUIActivity::class.java) - .setData("kernelsu://webui/$id".toUri()) - .putExtra("id", id) - .putExtra("name", name) + val ksuEngine = Intent(context, WebUIActivity::class.java) + .setData("kernelsu://webui/$id".toUri()) + .putExtra("id", id) + .putExtra("name", name) - webUILauncher.launch( - if (prefs.getBoolean("use_webuix", true) && Platform.isAlive) { - wxEngine - } else { - ksuEngine + val config = try { + id.asModuleConfig + } catch (e: Exception) { + Log.e("ModuleScreen", "Failed to get config from id: $id", e) + null } - ) + + val engine = config?.getWebuiEngine(context) + val selectedEngine = when (engine) { + "wx" -> wxEngine + "ksu" -> ksuEngine + null -> if (prefs.getBoolean("use_webuix", true) && Platform.isAlive) wxEngine else ksuEngine + else -> ksuEngine + } + + webUILauncher.launch(selectedEngine) + } catch (e: Exception) { + Log.e("ModuleScreen", "Error launching WebUI: ${e.message}", e) + scope.launch { + snackBarHost.showSnackbar("Error launching WebUI: ${e.message}") + } + } + return@ModuleList } }, context = context, @@ -902,7 +929,8 @@ fun ModuleItemPreview() { updateJson = "", hasWebUi = false, hasActionScript = false, - dirId = "dirId" + dirId = "dirId", + config = ModuleConfig(), ) ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {}) -} +} \ No newline at end of file diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt index d98c15a6..a44af86c 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt @@ -8,10 +8,13 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.dergoogler.mmrl.platform.model.ModuleConfig +import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import com.sukisu.ultra.ui.util.HanziToPinyin import com.sukisu.ultra.ui.util.listModules +import kotlinx.coroutines.withContext import org.json.JSONArray import org.json.JSONObject import java.text.Collator @@ -40,6 +43,7 @@ class ModuleViewModel : ViewModel() { val hasWebUi: Boolean, val hasActionScript: Boolean, val dirId: String, // real module id (dir name) + var config: ModuleConfig? = null, ) var isRefreshing by mutableStateOf(false) @@ -103,6 +107,39 @@ class ModuleViewModel : ViewModel() { obj.getString("dir_id") ) }.toList() + launch { + modules.forEach { module -> + withContext(Dispatchers.IO) { + try { + runCatching { + module.config = module.id.asModuleConfig + }.onFailure { e -> + Log.e(TAG, "Failed to load config from id for module ${module.id}", e) + } + if (module.config == null) { + runCatching { + module.config = module.name.asModuleConfig + }.onFailure { e -> + Log.e(TAG, "Failed to load config from name for module ${module.id}", e) + } + } + if (module.config == null) { + runCatching { + module.config = module.description.asModuleConfig + }.onFailure { e -> + Log.e(TAG, "Failed to load config from description for module ${module.id}", e) + } + } + if (module.config == null) { + module.config = ModuleConfig() + } + } catch (e: Exception) { + Log.e(TAG, "Failed to load any config for module ${module.id}", e) + module.config = ModuleConfig() + } + } + } + } isNeedRefresh = false }.onFailure { e -> Log.e(TAG, "fetchModuleList: ", e)