manager: update webuix

This commit is contained in:
Der_Googler
2025-05-30 01:19:39 +02:00
parent 1eb6eceb2d
commit 18219a40b0
7 changed files with 117 additions and 144 deletions

View File

@@ -108,6 +108,7 @@ dependencies {
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.swiperefreshlayout)
implementation(libs.compose.destinations.core)
ksp(libs.compose.destinations.ksp)

View File

@@ -71,12 +71,7 @@ class MainActivity : ComponentActivity() {
if (isManager) install()
setContent {
// Read AMOLED mode preference
val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
val amoledMode = prefs.getBoolean("enable_amoled", false)
KernelSUTheme (
amoledMode = amoledMode
) {
val navController = rememberNavController()
val snackBarHostState = remember { SnackbarHostState() }

View File

@@ -1,20 +1,19 @@
package com.rifsxd.ksunext.ui.theme
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.os.Build
import androidx.activity.SystemBarStyle
import androidx.activity.ComponentActivity
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import com.dergoogler.mmrl.ui.component.StatusBarStyle
private val DarkColorScheme = darkColorScheme(
primary = PRIMARY,
@@ -38,38 +37,58 @@ fun Color.blend(other: Color, ratio: Float): Color {
)
}
@Composable
fun KernelSUTheme(
/**
* AMOLED colors are handled through the context
*/
fun Context.getColorScheme(
darkTheme: Boolean = isSystemInDarkTheme(),
): ColorScheme {
// Read AMOLED mode preference
val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
val amoledMode = prefs.getBoolean("enable_amoled", false)
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
amoledMode: Boolean = false,
content: @Composable () -> Unit
) {
val colorScheme = when {
val dynamicColor = true
return when {
amoledMode && darkTheme && dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
val dynamicScheme = dynamicDarkColorScheme(context)
val dynamicScheme = dynamicDarkColorScheme(this)
dynamicScheme.copy(
background = AMOLED_BLACK,
surface = AMOLED_BLACK,
surfaceVariant = dynamicScheme.surfaceVariant.blend(AMOLED_BLACK, 0.6f),
surfaceContainer = dynamicScheme.surfaceContainer.blend(AMOLED_BLACK, 0.6f),
surfaceContainerLow = dynamicScheme.surfaceContainerLow.blend(AMOLED_BLACK, 0.6f),
surfaceContainerLowest = dynamicScheme.surfaceContainerLowest.blend(AMOLED_BLACK, 0.6f),
surfaceContainerLowest = dynamicScheme.surfaceContainerLowest.blend(
AMOLED_BLACK,
0.6f
),
surfaceContainerHigh = dynamicScheme.surfaceContainerHigh.blend(AMOLED_BLACK, 0.6f),
surfaceContainerHighest = dynamicScheme.surfaceContainerHighest.blend(AMOLED_BLACK, 0.6f),
surfaceContainerHighest = dynamicScheme.surfaceContainerHighest.blend(
AMOLED_BLACK,
0.6f
),
)
}
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
if (darkTheme) dynamicDarkColorScheme(this) else dynamicLightColorScheme(this)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
}
SystemBarStyle(
@Composable
fun KernelSUTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit,
) {
val context = LocalContext.current
val colorScheme = context.getColorScheme(darkTheme)
StatusBarStyle(
darkMode = darkTheme
)
@@ -80,31 +99,7 @@ fun KernelSUTheme(
)
}
@Composable
private fun SystemBarStyle(
darkMode: Boolean,
statusBarScrim: Color = Color.Transparent,
navigationBarScrim: Color = Color.Transparent,
) {
val context = LocalContext.current
val activity = context as ComponentActivity
SideEffect {
activity.enableEdgeToEdge(
statusBarStyle = SystemBarStyle.auto(
statusBarScrim.toArgb(),
statusBarScrim.toArgb(),
) { darkMode },
navigationBarStyle = when {
darkMode -> SystemBarStyle.dark(
navigationBarScrim.toArgb()
)
else -> SystemBarStyle.light(
navigationBarScrim.toArgb(),
navigationBarScrim.toArgb(),
)
}
)
}
internal fun isSystemInDarkTheme(): Boolean {
val uiMode = Resources.getSystem().configuration.uiMode
return (uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
}

View File

@@ -17,14 +17,15 @@ import androidx.core.view.updateLayoutParams
import androidx.webkit.WebViewAssetLoader
import com.dergoogler.mmrl.platform.model.ModId
import com.dergoogler.mmrl.webui.interfaces.WXOptions
import com.dergoogler.mmrl.webui.util.WebUIOptions
import com.dergoogler.mmrl.webui.view.WXView
import com.dergoogler.mmrl.webui.view.WebUIView
import com.topjohnwu.superuser.Shell
import com.rifsxd.ksunext.ui.util.createRootShell
import java.io.File
@SuppressLint("SetJavaScriptEnabled")
class WebUIActivity : ComponentActivity() {
private lateinit var webviewInterface: WebViewInterface
private var rootShell: Shell? = null
override fun onCreate(savedInstanceState: Bundle?) {
@@ -71,7 +72,12 @@ class WebUIActivity : ComponentActivity() {
}
}
val webView = WebView(this).apply {
val options = WebUIOptions(
modId = ModId(moduleId),
context = this,
)
val webView = WebUIView(options).apply {
ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updateLayoutParams<MarginLayoutParams> {
@@ -82,15 +88,15 @@ class WebUIActivity : ComponentActivity() {
}
return@setOnApplyWindowInsetsListener insets
}
val factory = WebViewInterface.factory()
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.allowFileAccess = false
webviewInterface = WebViewInterface(
WXOptions(this@WebUIActivity, this, ModId(moduleId))
)
addJavascriptInterface(webviewInterface, "ksu")
addJavascriptInterface(factory)
setWebViewClient(webViewClient)
loadUrl("https://mui.kernelsu.org/index.html")
loadDomain()
}
setContentView(webView)

View File

@@ -1,32 +1,19 @@
package com.rifsxd.ksunext.ui.webui
import android.app.ActivityManager
import android.os.Build
import android.os.Bundle
import android.webkit.WebView
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import com.dergoogler.mmrl.platform.Platform
import com.dergoogler.mmrl.platform.model.ModId
import com.dergoogler.mmrl.ui.component.Loading
import com.dergoogler.mmrl.webui.screen.WebUIScreen
import com.dergoogler.mmrl.webui.util.rememberWebUIOptions
import com.dergoogler.mmrl.webui.activity.WXActivity
import com.dergoogler.mmrl.webui.util.WebUIOptions
import com.dergoogler.mmrl.webui.view.WebUIXView
import com.rifsxd.ksunext.BuildConfig
import com.rifsxd.ksunext.ui.theme.KernelSUTheme
import kotlinx.coroutines.delay
import com.rifsxd.ksunext.ui.theme.getColorScheme
import com.rifsxd.ksunext.ui.theme.isSystemInDarkTheme
import kotlinx.coroutines.launch
class WebUIXActivity : ComponentActivity() {
private lateinit var webView: WebView
class WebUIXActivity : WXActivity() {
private val userAgent
get(): String {
val ksuVersion = BuildConfig.VERSION_CODE
@@ -45,69 +32,59 @@ class WebUIXActivity : ComponentActivity() {
return "KernelSU Next/$ksuVersion (Linux; Android $osVersion; $deviceModel; $platform/$platformVersion)"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
override fun onRender(savedInstanceState: Bundle?) {
super.onRender(savedInstanceState)
webView = WebView(this)
lifecycleScope.launch {
initPlatform()
if (this.modId == null) {
val msg = "ModId cannot be null"
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
throw IllegalArgumentException(msg)
}
val moduleId = intent.getStringExtra("id")!!
val name = intent.getStringExtra("name")!!
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
@Suppress("DEPRECATION")
setTaskDescription(ActivityManager.TaskDescription("KernelSU Next - $name"))
} else {
val taskDescription =
ActivityManager.TaskDescription.Builder().setLabel("KernelSU Next - $name").build()
setTaskDescription(taskDescription)
}
// Cast since we check it
val modId = this.modId!!
val prefs = getSharedPreferences("settings", MODE_PRIVATE)
val webDebugging = prefs.getBoolean("enable_web_debugging", false)
val erudaInject = prefs.getBoolean("use_webuix_eruda", false)
setContent {
KernelSUTheme {
var isLoading by remember { mutableStateOf(true) }
LaunchedEffect(Platform.isAlive) {
while (!Platform.isAlive) {
delay(1000)
}
val options = WebUIOptions(
modId = modId,
context = this,
debug = webDebugging,
appVersionCode = BuildConfig.VERSION_CODE,
isDarkMode = isSystemInDarkTheme(),
enableEruda = erudaInject,
cls = WebUIXActivity::class.java,
userAgentString = userAgent,
colorScheme = getColorScheme()
)
isLoading = false
}
val view = WebUIXView(options).apply {
wx.addJavascriptInterface(WebViewInterface.factory())
wx.loadDomain()
}
if (isLoading) {
Loading()
this.options = options
this.view = view
return@KernelSUTheme
}
val webDebugging = prefs.getBoolean("enable_web_debugging", false)
val erudaInject = prefs.getBoolean("use_webuix_eruda", false)
val dark = isSystemInDarkTheme()
// Ensure type safety
val name = intent.getStringExtra("name")
if (name != null) {
setActivityTitle("KernelSU Next - $name")
}
val options = rememberWebUIOptions(
modId = ModId(moduleId),
debug = webDebugging,
appVersionCode = BuildConfig.VERSION_CODE,
isDarkMode = dark,
enableEruda = erudaInject,
cls = WebUIXActivity::class.java,
userAgentString = userAgent
)
val loading = createLoadingRenderer()
setContentView(loading)
WebUIScreen(
webView = webView,
options = options,
interfaces = listOf(
WebViewInterface.factory()
)
)
lifecycleScope.launch {
val deferred = Platform.getAsyncDeferred(this, null) {
view
}
setContentView(deferred.await())
}
}
}

View File

@@ -1,14 +1,12 @@
package com.rifsxd.ksunext.ui.webui
import android.app.Activity
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.view.Window
import android.webkit.JavascriptInterface
import android.widget.Toast
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.dergoogler.mmrl.platform.model.ModId.Companion.moduleDir
import com.dergoogler.mmrl.webui.interfaces.WXInterface
import com.dergoogler.mmrl.webui.interfaces.WXOptions
import com.dergoogler.mmrl.webui.model.JavaScriptInterface
@@ -20,20 +18,19 @@ import com.rifsxd.ksunext.ui.util.listModules
import com.rifsxd.ksunext.ui.util.withNewRootShell
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.util.concurrent.CompletableFuture
class WebViewInterface(
wxOptions: WXOptions,
) : WXInterface(wxOptions) {
override var name: String = "ksu"
// Add logging tag for console.log
override var tag: String = "KernelSUInterface"
companion object {
fun factory() = JavaScriptInterface(WebViewInterface::class.java)
}
private val modDir get() = "/data/adb/modules/${modId.id}"
@JavascriptInterface
fun exec(cmd: String): String {
return withNewRootShell(true) { ShellUtils.fastCmd(this, cmd) }
@@ -171,23 +168,22 @@ class WebViewInterface(
@JavascriptInterface
fun fullScreen(enable: Boolean) {
if (context is Activity) {
Handler(Looper.getMainLooper()).post {
if (enable) {
hideSystemUI(activity.window)
} else {
showSystemUI(activity.window)
}
runMainLooperPost {
if (enable) {
hideSystemUI(window)
} else {
showSystemUI(window)
}
}
}
@JavascriptInterface
fun moduleInfo(): String {
val modDir = modId.moduleDir
val moduleInfos = JSONArray(listModules())
val currentModuleInfo = JSONObject()
currentModuleInfo.put("moduleDir", modDir)
val moduleId = File(modDir).getName()
val moduleId = modDir.getName()
for (i in 0 until moduleInfos.length()) {
val currentInfo = moduleInfos.getJSONObject(i)

View File

@@ -17,7 +17,8 @@ parcelablelist = "2.0.1"
libsu = "6.0.0"
apksign = "1.4"
cmaker = "1.2"
mmrl = "817d76c8b5"
mmrl = "fcb3a1fb76"
swiperefreshlayout = "1.1.0"
[plugins]
agp-app = { id = "com.android.application", version.ref = "agp" }
@@ -36,6 +37,8 @@ androidx-activity-compose = { group = "androidx.activity", name = "activity-comp
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" }
androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "swiperefreshlayout" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" }
androidx-compose-material = { group = "androidx.compose.material", name = "material" }