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>
This commit is contained in:
ShirkNeko
2025-05-31 03:03:22 +08:00
parent 2281012e33
commit 8064472477
2 changed files with 82 additions and 17 deletions

View File

@@ -72,6 +72,8 @@ import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.webui.WebUIXActivity import com.sukisu.ultra.ui.webui.WebUIXActivity
import com.dergoogler.mmrl.platform.Platform import com.dergoogler.mmrl.platform.Platform
import androidx.core.net.toUri import androidx.core.net.toUri
import com.dergoogler.mmrl.platform.model.ModuleConfig
import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -83,6 +85,7 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
val snackBarHost = LocalSnackbarHost.current val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val confirmDialog = rememberConfirmDialog() val confirmDialog = rememberConfirmDialog()
var lastClickTime by remember { mutableStateOf(0L) }
val selectZipLauncher = rememberLauncherForActivityResult( val selectZipLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult() contract = ActivityResultContracts.StartActivityForResult()
@@ -142,7 +145,7 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
} }
} else { } else {
val uri = data.data ?: return@launch val uri = data.data ?: return@launch
// 单个安装模块 // 单个安装模块
try { try {
if (!ModuleUtils.isUriAccessible(context, uri)) { if (!ModuleUtils.isUriAccessible(context, uri)) {
snackBarHost.showSnackbar("Unable to access selected module files") snackBarHost.showSnackbar("Unable to access selected module files")
@@ -371,24 +374,48 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it))) navigator.navigate(FlashScreenDestination(FlashIt.FlashModule(it)))
}, },
onClickModule = { id, name, hasWebUi -> 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) { if (hasWebUi) {
val wxEngine = Intent(context, WebUIXActivity::class.java) try {
.setData("kernelsu://webuix/$id".toUri()) val wxEngine = Intent(context, WebUIXActivity::class.java)
.putExtra("id", id) .setData("kernelsu://webuix/$id".toUri())
.putExtra("name", name) .putExtra("id", id)
.putExtra("name", name)
val ksuEngine = Intent(context, WebUIActivity::class.java) val ksuEngine = Intent(context, WebUIActivity::class.java)
.setData("kernelsu://webui/$id".toUri()) .setData("kernelsu://webui/$id".toUri())
.putExtra("id", id) .putExtra("id", id)
.putExtra("name", name) .putExtra("name", name)
webUILauncher.launch( val config = try {
if (prefs.getBoolean("use_webuix", true) && Platform.isAlive) { id.asModuleConfig
wxEngine } catch (e: Exception) {
} else { Log.e("ModuleScreen", "Failed to get config from id: $id", e)
ksuEngine 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, context = context,
@@ -902,7 +929,8 @@ fun ModuleItemPreview() {
updateJson = "", updateJson = "",
hasWebUi = false, hasWebUi = false,
hasActionScript = false, hasActionScript = false,
dirId = "dirId" dirId = "dirId",
config = ModuleConfig(),
) )
ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {}) ModuleItem(EmptyDestinationsNavigator, module, "", {}, {}, {}, {})
} }

View File

@@ -8,10 +8,13 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope 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.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.sukisu.ultra.ui.util.HanziToPinyin import com.sukisu.ultra.ui.util.HanziToPinyin
import com.sukisu.ultra.ui.util.listModules import com.sukisu.ultra.ui.util.listModules
import kotlinx.coroutines.withContext
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.text.Collator import java.text.Collator
@@ -40,6 +43,7 @@ class ModuleViewModel : ViewModel() {
val hasWebUi: Boolean, val hasWebUi: Boolean,
val hasActionScript: Boolean, val hasActionScript: Boolean,
val dirId: String, // real module id (dir name) val dirId: String, // real module id (dir name)
var config: ModuleConfig? = null,
) )
var isRefreshing by mutableStateOf(false) var isRefreshing by mutableStateOf(false)
@@ -103,6 +107,39 @@ class ModuleViewModel : ViewModel() {
obj.getString("dir_id") obj.getString("dir_id")
) )
}.toList() }.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 isNeedRefresh = false
}.onFailure { e -> }.onFailure { e ->
Log.e(TAG, "fetchModuleList: ", e) Log.e(TAG, "fetchModuleList: ", e)