manager: refactor label item in superuser list

* manager: Improvements

* manager: bump mmrl

* manager: use ktx ext Str.toUri

* manager: add "webui-engine" from config.json

This allows the developer to override the user preference of the selected WebUI engine.

Supported engines are:

- `wx` for WebUI X
- `ksu` for the KernelSU WebUI

All not named strings will default to `wx`

R.string.use_webuix_summary needs proper translations

* manager: add support for multilingual module meta

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-27 16:57:54 +08:00
parent 64f0efc2c0
commit 439b99cc4a
5 changed files with 54 additions and 18 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)
@@ -372,17 +374,34 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
}, },
onClickModule = { id, name, hasWebUi -> onClickModule = { id, name, hasWebUi ->
if (hasWebUi) { if (hasWebUi) {
webUILauncher.launch( val wxEngine = Intent(context, WebUIXActivity::class.java)
if (prefs.getBoolean("use_webuix", false) && Platform.isAlive) {
Intent(context, WebUIXActivity::class.java)
.setData("kernelsu://webuix/$id".toUri()) .setData("kernelsu://webuix/$id".toUri())
.putExtra("id", id) .putExtra("id", id)
.putExtra("name", name) .putExtra("name", name)
} else {
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)
val config = id.asModuleConfig
val engine = config.getWebuiEngine(context)
if (engine != null) {
webUILauncher.launch(
when (config.getWebuiEngine(context)) {
"wx" -> wxEngine
"ksu" -> ksuEngine
else -> wxEngine
}
)
return@ModuleList
}
webUILauncher.launch(
if (prefs.getBoolean("use_webuix", true) && Platform.isAlive) {
wxEngine
} else {
ksuEngine
} }
) )
} }
@@ -898,7 +917,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

@@ -47,6 +47,8 @@ import com.sukisu.ultra.ui.component.SearchAppBar
import com.sukisu.ultra.ui.theme.CardConfig import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.util.ModuleModify import com.sukisu.ultra.ui.util.ModuleModify
import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
import com.dergoogler.mmrl.ui.component.LabelItem
import com.dergoogler.mmrl.ui.component.LabelItemDefaults
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
@Destination<RootGraph> @Destination<RootGraph>
@@ -766,13 +768,21 @@ private fun AppItem(
horizontalArrangement = Arrangement.spacedBy(4.dp) horizontalArrangement = Arrangement.spacedBy(4.dp)
) { ) {
if (app.allowSu) { if (app.allowSu) {
LabelText(label = "ROOT", backgroundColor = MaterialTheme.colorScheme.primary) LabelItem(text = "ROOT",)
} }
if (Natives.uidShouldUmount(app.uid)) { if (Natives.uidShouldUmount(app.uid)) {
LabelText(label = "UMOUNT", backgroundColor = MaterialTheme.colorScheme.tertiary) LabelItem(text = "UNMOUNT", style = LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
)
)
} }
if (app.hasCustomProfile) { if (app.hasCustomProfile) {
LabelText(label = "CUSTOM", backgroundColor = MaterialTheme.colorScheme.secondary) LabelItem(text = "CUSTOM", style = LabelItemDefaults.style.copy(
containerColor = MaterialTheme.colorScheme.onTertiary,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer,
)
)
} }
} }
} }

View File

@@ -17,6 +17,8 @@ import org.json.JSONObject
import java.text.Collator import java.text.Collator
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import com.dergoogler.mmrl.platform.model.ModuleConfig
import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig
class ModuleViewModel : ViewModel() { class ModuleViewModel : ViewModel() {
@@ -40,6 +42,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)
val config: ModuleConfig,
) )
var isRefreshing by mutableStateOf(false) var isRefreshing by mutableStateOf(false)
@@ -87,13 +90,15 @@ class ModuleViewModel : ViewModel() {
.asSequence() .asSequence()
.map { array.getJSONObject(it) } .map { array.getJSONObject(it) }
.map { obj -> .map { obj ->
val id = obj.getString("id")
val config = id.asModuleConfig
ModuleInfo( ModuleInfo(
obj.getString("id"), id,
obj.optString("name"), config.name ?: obj.optString("name"),
obj.optString("author", "Unknown"), obj.optString("author", "Unknown"),
obj.optString("version", "Unknown"), obj.optString("version", "Unknown"),
obj.optInt("versionCode", 0), obj.optInt("versionCode", 0),
obj.optString("description"), config.description ?: obj.optString("description"),
obj.getBoolean("enabled"), obj.getBoolean("enabled"),
obj.getBoolean("update"), obj.getBoolean("update"),
obj.getBoolean("remove"), obj.getBoolean("remove"),
@@ -101,6 +106,7 @@ class ModuleViewModel : ViewModel() {
obj.optBoolean("web"), obj.optBoolean("web"),
obj.optBoolean("action"), obj.optBoolean("action"),
obj.getString("dir_id"), obj.getString("dir_id"),
config
) )
}.toList() }.toList()
isNeedRefresh = false isNeedRefresh = false

View File

@@ -329,7 +329,7 @@
<string name="show_kpm_info_summary">Display KPM information and Function in home and bottom bar (Need to reopen the app)</string> <string name="show_kpm_info_summary">Display KPM information and Function in home and bottom bar (Need to reopen the app)</string>
<!-- Webui X settings --> <!-- Webui X settings -->
<string name="use_webuix">Use WebUI X</string> <string name="use_webuix">Use WebUI X</string>
<string name="use_webuix_summary">Use WebUI X instead of WebUI which supports more API\'s</string> <string name="use_webuix_summary">Use WebUI X instead of WebUI, which supports more APIs. Be aware that developers can override this feature in their module config.</string>
<string name="use_webuix_eruda">Inject Eruda into WebUI X</string> <string name="use_webuix_eruda">Inject Eruda into WebUI X</string>
<string name="use_webuix_eruda_summary">Inject a debug console into WebUI X to make debugging easier. Requires web debugging to be on.</string> <string name="use_webuix_eruda_summary">Inject a debug console into WebUI X to make debugging easier. Requires web debugging to be on.</string>
<!-- DPI setting related strings --> <!-- DPI setting related strings -->

View File

@@ -21,7 +21,7 @@ compose-material = "1.8.2"
compose-material3 = "1.3.2" compose-material3 = "1.3.2"
compose-ui = "1.8.2" compose-ui = "1.8.2"
documentfile = "1.1.0" documentfile = "1.1.0"
mmrl = "v33633" mmrl = "2bb00b3c2b"
[plugins] [plugins]
agp-app = { id = "com.android.application", version.ref = "agp" } agp-app = { id = "com.android.application", version.ref = "agp" }